OpenCV4.0实现人脸识别 !

概述

OpenCV4.0深度神经网络模块,支持openface模型的导入,提取人脸的128特征向量,进行相似度比对,实现人脸识别。Openface模型的详细信息看这里

http://www.cv-foundation.org/openaccess/content_cvpr_2015/app/1A_089.pdf

主要原理是基于2015年CVPR的FaceNet网络的论文,去年的时候写过一篇文章介绍过它,想要了解详细信息的点击这里查看即可

OpenCV+Tensorflow实现实时人脸识别演示

主要思路

首先使用OpenCV4.0 DNN模块支持的人脸检测模型,实现对图像或者视频的人脸检测,然后对得到的人脸区域通过openface的预训练模型提取128个特征向量值,基于余弦相似度进行特征值比对,实现人脸识别。完整的流程可以图示如下:

16749901-c92b7952fa9a6621
image

余弦相似公式与解释:

16749901-340d8b2e83468592
image

代码实现步骤

01

加载网络

需要先加载人脸检测与openface人脸识别网络模型,代码实现如下:

    String modelDesc = "D:/projects/opencv_tutorial/data/models/resnet/deploy.prototxt";    String modelBinary = "D:/projects/opencv_tutorial/data/models/resnet/res10_300x300_ssd_iter_140000.caffemodel";    String facemodel = "D:/projects/opencv_tutorial/data/models/face_detector/openface.nn4.small2.v1.t7";    // 初始化网络    Net net = readNetFromCaffe(modelDesc, modelBinary);    Net netRecogn = readNetFromTorch(facemodel);

这两个模型的下载地址如下:

https://github.com/gloomyfish1998/opencv_tutorial/tree/master/data/models/face_detector

02

设置计算后台

OpenCV支持不同的计算后台,这里我们采用OpenVINO作为计算后台,可以实现加速计算,代码如下:

// 设置计算后台Net netRecogn = readNetFromTorch(facemodel);net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);net.setPreferableTarget(DNN_TARGET_CPU);netRecogn.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);netRecogn.setPreferableTarget(DNN_TARGET_CPU);// load face datavector<vector<float>> face_data;vector<string> labels;vector<string> faces;glob("D:/my_faces/zhigang", faces);for (auto fn : faces) {    vector<float> fv;    Mat sample = imread(fn);    recognize_face(sample, netRecogn, fv);    face_data.push_back(fv);    printf("file name : %s\n", fn.c_str());    labels.push_back("zhigang");}faces.clear();glob("D:/my_faces/balvin", faces);for (auto fn : faces) {    vector<float> fv;    Mat sample = imread(fn);    recognize_face(sample, netRecogn, fv);    face_data.push_back(fv);    printf("file name : %s\n", fn.c_str());    labels.push_back("balvin");}if (net.empty() || netRecogn.empty()){    printf("could not load net...\n");    return -1;}

03

人脸检测

通过人脸检测网络实现人脸检测,代码实现如下:

// 输入数据调整Mat inputBlob = blobFromImage(frame, inScaleFactor,    Size(inWidth, inHeight), meanVal, false, false);net.setInput(inputBlob, "data");// 人脸检测Mat detection = net.forward("detection_out");vector<double> layersTimings;double freq = getTickFrequency() / 1000;double time = net.getPerfProfile(layersTimings) / freq;Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());

04

人脸比对

把实时检测得到ROI区域与预先加载的人脸样本进行比较,找到距离最小的,如果小于阈值T,即为识别输出结果,解析人脸检测并实现人脸识别的代码如下:

for (int i = 0; i < detectionMat.rows; i++){    // 置信度 0~1之间    float confidence = detectionMat.at<float>(i, 2);    if (confidence > confidenceThreshold)    {        int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * frame.cols);        int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);        int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);        int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);        Rect object((int)xLeftBottom, (int)yLeftBottom,            (int)(xRightTop - xLeftBottom),            (int)(yRightTop - yLeftBottom));        if (object.width < 5 || object.height < 5) {            continue;        }        // 截取人脸ROI区域        Mat roi = frame(object);        // 人脸比对,发现相似度最高的        vector<float> curr_fv;        recognize_face(roi, netRecogn, curr_fv);        float minDist = 10;        int index = -1;        for (int i = 0; i < face_data.size(); i++) {            float dist = compare(curr_fv, face_data[i]);            if (minDist > dist) {                minDist = dist;                index = i;            }        }        // 阈值与显示识别结果        printf("index : %d, dist: %.2f \n", index, minDist);        if (index >= 0 && minDist < 0.30) {            putText(frame, labels[index].c_str(), Point(xLeftBottom, yLeftBottom-20),                FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255));        }        rectangle(frame, object, Scalar(0, 255, 0));        ss.str("");        ss << confidence;        String conf(ss.str());        String label = "Face: " + conf;        int baseLine = 0;        Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);        rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),            Size(labelSize.width, labelSize.height + baseLine)),            Scalar(255, 255, 255), FILLED);        putText(frame, label, Point(xLeftBottom, yLeftBottom),            FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));    }}

余弦相似比较

float compare(vector<float> &fv1, vector<float> fv2) {    // 计算余弦相似, 0 ~ 1 距离,距离越小越相似,    // 0表示夹角为0°,1表示夹角为90°    float dot = 0;    float sum2 = 0;    float sum3 = 0;    for (int i = 0; i < fv1.size(); i++) {        dot += fv1[i] * fv2[i];        sum2 += pow(fv1[i], 2);        sum3 += pow(fv2[i], 2);    }    float norm = sqrt(sum2)*sqrt(sum3);    float similarity = dot / norm;    float dist = acos(similarity) / CV_PI;    return dist;}

运行效果

16749901-a7684a41d1bcde1a
image

猜你喜欢

转载自blog.csdn.net/weixin_33797791/article/details/90923103
今日推荐