人脸考勤识别项目
程序员文章站
2022-07-12 20:57:51
...
基于百度云人脸识别算法和4412开发板、外置摄像头实现人脸面部的采集,截取,识别,返回识别结果。
- 采用的软件有:putty软件(串行接口连接软件) Winscp软件(用于电脑和开发板的文件互传) ch341(终端驱动,确保电脑可识别开发板的端口)
- 配置环境:确保开发板与电脑网络互连:
- 检查互联网网络共享方法:打开电脑命令行(win+r输入cmd)确保电脑对开发板的网络互连:输入ping 192.168.137.2
- 检查互联网网络共享方法:打开putty,登录到开发板,在root界面输入上述指令,检查开发板与电脑的连接。
- 程序的烧写:
#include <stdio.h> #include <string.h> //memset #include <stdlib.h> //malloc free #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> //inet_ntop #include <unistd.h> //sleep #include <opencv2/opencv.hpp> #include <opencv2/freetype.hpp> #include "face.h" using namespace std; using namespace cv; using namespace aip; //前后图片的分隔字符串 #define BOUNDARY "boundary--" long get_file_size(const char *filename) { FILE *fp = fopen(filename, "r"); fseek(fp, 0, SEEK_END); long size = ftell(fp); fclose(fp); return size; } void send_file(FILE *fp, const char *filename) { long size = get_file_size(filename); char *body = (char *)malloc(size); FILE *file = fopen(filename, "r"); fread(body, 1, size, file); fclose(file); fwrite(body, 1, size, fp); free(body); } void send_buffer(FILE *fp, const char *buf, long size) { fwrite(buf, 1, size, fp); } Mat image; //core pthread_mutex_t image_lock = PTHREAD_MUTEX_INITIALIZER; Mat frame; pthread_mutex_t frame_lock = PTHREAD_MUTEX_INITIALIZER; //视频采集线程 void *handle_capture(void *) { VideoCapture cam; //videoio cam.open(0); //打开第一个摄像头 while (1) { pthread_mutex_lock(&image_lock); cam.read(image); //从摄像头捕获图像 pthread_mutex_unlock(&image_lock); usleep(100000); //10fps } } Rect range; string id = ""; //人脸识别线程 void *handle_recognize(void *) { //创建级联分类器 CascadeClassifier detector; detector.load("/usr/share/opencv/lbpcascades/lbpcascade_frontalface.xml"); string appid = "180*******"; //三个秘钥为百度云创建的项目下边的秘钥。复制粘贴即可 string apikey = "kIGVsM*******************"; string secretkey = "udOc***********************"; //创建人脸识别客户端 Face client(appid, apikey, secretkey); int count = 0; while (1) { pthread_mutex_lock(&image_lock); pthread_mutex_lock(&frame_lock); frame = image; pthread_mutex_unlock(&frame_lock); pthread_mutex_unlock(&image_lock); Mat gray; cvtColor(frame, gray, COLOR_BGR2GRAY); //将彩色图像转换为黑白图像 vector<Rect> faces; detector.detectMultiScale(gray, faces); //只检测一个人脸 if (faces.size() != 0) { range = faces[0]; count++; if (count >= 5) //连续5帧图像中都检测出人脸,发送人脸识别请求 { Mat face(frame, faces[0]); //裁剪人脸图像 vector<unsigned char> facebuf; imencode(".jpg", face, facebuf); //将图像进行编码,放到内存中 //imwrite("face.jpg", face); //puts("face save to file"); //将裁剪出来的人脸图像进行Base64编码 string base64 = base64_encode((char *)facebuf.data(), facebuf.size()); Json::Value result = client.search(base64, "BASE64", "*******", null); //此处填写百度云创建的用户组名 puts(result.toStyledString().c_str()); if (result["error_code"].asInt() == 0) { id = result["result"]["user_list"][0]["user_id"].asString(); } } } else { id = ""; count = 0; } usleep(100000); //10fps } } /* 创建TCP服务器 * 1. socket 创建套接字 * 2. bind 绑定IP地址到套接字 * 3. listen 将套接字设置为监听状态 * 4. accept 建立与客户端之间的连接(TCP三次握手) */ int main() { //创建线程:视频捕获线程,人脸识别线程 pthread_t cam_thread; pthread_t recog_thread; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //设置为可分离 pthread_create(&cam_thread, &attr, handle_capture, NULL); sleep(1); //先启动视频采集线程,防止读取空图片 pthread_create(&recog_thread, &attr, handle_recognize, NULL); auto font = freetype::createFreeType2(); font->loadFontData("simkai.ttf", 0); int listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { perror("socket"); return 1; } //设置地址复用,防止服务器重启后bind失败 int opt = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr; memset(&addr, 0, sizeof addr); addr.sin_family = AF_INET; //地址类型,IPv4 addr.sin_addr.s_addr = htonl(INADDR_ANY); //绑定到所有地址 addr.sin_port = htons(8080); //1024以下的端口,需要使用root权限 //(8080)用于后续网址的输入,例如:htons(11100)则网址为:192.168.137.2:11100 int result = bind(listenfd, (struct sockaddr *)&addr, sizeof addr); if (result < 0) { perror("bind"); return 1; } result = listen(listenfd, 10); if (result < 0) { perror("listen"); return 1; } puts("web server start"); while (1) { struct sockaddr_in client_addr; socklen_t client_addrlen = sizeof client_addr; int fd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addrlen); //等待客户端连接 if (fd < 0) { perror("accept"); } char ipstr[16]; inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ipstr, client_addrlen); //将二进制的IP地址转换为字符串 printf("client %s is connected\n", ipstr); FILE *fp = fdopen(fd, "r+"); //关联文件描述符和文件流 char buf[1024]; while (fgets(buf, sizeof buf, fp)) { printf(buf); //如果读到空行,停止接收,发送响应报文 if (strcmp(buf, "\r\n") == 0) break; } puts("send response"); fprintf(fp, "HTTP/1.1 200 Meimaobing\r\n"); fprintf(fp, "Transfer-Encoding: chunked\r\n"); //分块编码 //fprintf(fp, "Content-Type: text/plain;charset=utf-8\r\n"); fprintf(fp, "Content-Type: multipart/x-mixed-replace;boundary=%s\r\n", BOUNDARY); fprintf(fp, "\r\n"); puts("header send"); while (1) { //分块大小(16进制)\r\n //Content-Type: image/jpeg -> 26 //空行 -> 2 //图片内容 -> 图片大小 + 2 //空行 -> 2 //--boundary-- -> 14 //分块大小 = 图片大小 + 2 + 25 + 2 + 2 + 14 = 45 vector<unsigned char> buf; pthread_mutex_lock(&frame_lock); rectangle(frame, range, CV_RGB(255, 0, 0), 2); //标记人脸区域 //在人脸区域上方显示用户id font->putText(frame, //< 修改的图像 id.c_str(), //< 显示的字符 range.tl(), //< 字符起始位置(左下角) 30, //< 字符高度 Scalar(0, 0, 255), //< 字符颜色 -1, //< 字符轮廓粗细,负值表示填充字符轮廓 CV_AA, //< AA表示平滑字符轮廓 true); //< 定义起始位置,为真时以左下角为起始位置,否则为左上角 imencode(".jpg", frame, buf); //将图像进行编码,放到内存中 pthread_mutex_unlock(&frame_lock); fprintf(fp, "%x\r\n", buf.size() + 46); fprintf(fp, "Content-Type: image/jpeg\r\n\r\n"); send_buffer(fp, (char *)buf.data(), buf.size()); //send_file(fp, "white.png"); fprintf(fp, "\r\n\r\n--%s\r\n\r\n", BOUNDARY); usleep(100000); //1s = 10^6us, 10fps } fclose(fp); } return 0; }
上一篇: javaIO流(一)
下一篇: JAVAIO流(09)