欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

人脸考勤识别项目

程序员文章站 2022-07-12 20:57:51
...

基于百度云人脸识别算法和4412开发板、外置摄像头实现人脸面部的采集,截取,识别,返回识别结果。

  1. 采用的软件有:putty软件(串行接口连接软件)   Winscp软件(用于电脑和开发板的文件互传) ch341(终端驱动,确保电脑可识别开发板的端口)
  2. 配置环境:确保开发板与电脑网络互连:
  3. 人脸考勤识别项目
  4. 检查互联网网络共享方法:打开电脑命令行(win+r输入cmd)确保电脑对开发板的网络互连:输入ping 192.168.137.2
  5. 检查互联网网络共享方法:打开putty,登录到开发板,在root界面输入上述指令,检查开发板与电脑的连接。
  6. 程序的烧写:
    #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)