DNN 人脸识别
- 使用facenet模型基于Torch,对每张图片进行多层卷积处理,计算出128个向量
- 使用样本空间中的每张图的128个向量与采样的128个向量进行余弦相似度比较,0度为1,表示方向相同,90度为0,表示垂直正交。值越小,相似度越高,通过label存储的名字信息,可以把人检索出来,但是应该设置一定的阈值,否则会出现误检测
代码实现过程
- 模型加载
- 人脸检测与识别模型特征向量输出
- 相似度比较,阈值控制,检索匹配
- 显示结果
模型输入输出
- 输入 Size:96*96,缩放:1/255.0,rgb:true
- 输出:111*128 一张单通道 一行 128列的浮点数据
代码
#include
#include
#include
#include
using namespace cv;
using namespace cv::dnn;
using namespace std;
void recognize_face(Mat& face, Net net, vector<float> &fv);
float compare(vector<float> &fv1, vector<float> &fv2);
int main(int argc, char** argv) {
string facenet_model = "/work/opencv_dnn/face_detector/openface.nn4.small2.v1.t7";
string pb_model = "/work/opencv_dnn/face_detector/opencv_face_detector_uint8.pb";
string pb_txt = "/work/opencv_dnn/face_detector/opencv_face_detector.pbtxt";
Net net = readNetFromTensorflow(pb_model, pb_txt);
Net face_net = readNetFromTorch(facenet_model);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
net.setPreferableTarget(DNN_TARGET_CPU);
face_net.setPreferableBackend(DNN_BACKEND_OPENCV);
face_net.setPreferableTarget(DNN_TARGET_CPU);
vector<vector<float>> face_data;
vector<string> labels;
vector<string> faces;
glob("/work/li_face", faces);
for (auto fn : faces) {
vector<float> fv;
Mat sample = imread(fn);
recognize_face(sample, face_net, fv);
face_data.push_back(fv);
labels.push_back("Jing Jing");
}
faces.clear();
glob("/work/face_pic", faces);
for (auto fn : faces) {
vector<float> fv;
Mat sample = imread(fn);
recognize_face(sample, face_net, fv);
face_data.push_back(fv);
labels.push_back("Zhang Chao");
}
VideoCapture capture(0);
Mat frame;
while (true) {
bool ret = capture.read(frame);
if (!ret) break;
flip(frame, frame, 1);
Mat blob = blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);
net.setInput(blob, "data");
Mat detection = net.forward("detection_out");
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
float confidence_threshold = 0.5;
float* curr_row;
for (int i = 0; i < detectionMat.rows; i++) {
curr_row = detectionMat.ptr<float>(i);
curr_row+=2;
float score = *curr_row++;
if (score > confidence_threshold) {
float tl_x = (*curr_row++) * frame.cols;
float tl_y = (*curr_row++) * frame.rows;
float br_x = (*curr_row++) * frame.cols;
float br_y = (*curr_row++) * frame.rows;
Rect box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
Mat face = frame(box);
vector<float> curr_fv;
recognize_face(face, face_net, curr_fv);
float minDist = 10;
int index = 0;
for (size_t i = 0; i < face_data.size(); i++) {
float dist = compare(face_data[i], curr_fv);
if (minDist > dist) {
minDist = dist;
index = i;
}
}
printf("index : %d, min distance : %.2f \n", index, minDist);
if (minDist < 0.19 && index >= 0)
{
putText(frame, format("%s", labels[index].c_str()), Point(box.x-10,box.y-10), FONT_HERSHEY_SIMPLEX, 1.5, Scalar(0, 0, 255), 2, 8);
}
rectangle(frame, box, Scalar(255, 0, 255), 1, 8, 0);
}
}
imshow("face-detection-demo", frame);
char c = waitKey(1);
if (c == 27) {
break;
}
}
capture.release();
destroyAllWindows();
waitKey(0);
return 0;
}
void recognize_face(Mat& face, Net net, vector<float> &fv) {
Mat blob = blobFromImage(face, 1 / 255.0, Size(96, 96), Scalar(0, 0, 0), true, false);
net.setInput(blob);
Mat probMat = net.forward();
Mat vec = probMat.reshape(1, 1);
for (int i = 0; i < vec.cols; i++) {
fv.push_back(vec.at<float>(0, i));
}
}
float compare(vector<float> &fv1, vector<float> &fv2) {
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 similary = dot / norm;
float dist = acos(similary) / CV_PI;
return dist;
}
效果
训练图1
训练图2
检测图