OpenCV4.0實現人臉識別

OpenCV 人臉識別 深度學習 人工智能 編程python新視野 2019-07-11

概述

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個特徵向量值,基於餘弦相似度進行特徵值比對,實現人臉識別。完整的流程可以圖示如下:


OpenCV4.0實現人臉識別


餘弦相似公式與解釋:


OpenCV4.0實現人臉識別


代碼實現步驟

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 data
vector<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;
}

運行效果


OpenCV4.0實現人臉識別


相關推薦

推薦中...