照片效果

视频效果
注意:Dlib检测人脸在Release版耗时与CPU有关,本人I7 10代约100ms左右,这里本人将人脸检测用Yolov5对人脸简单抠图训练后 使用yolov5推理检测人脸,之后将检测到的人脸输入给Dlib做特征,发现人脸特征部分耗时也较高 约200ms,之后考虑分线程做检测或查找如何降低耗时。
源码
void Class::run()
{
	//cv::VideoCapture vc(0);
	cv::VideoCapture vc("D:/Software/FFmpeg/cxk.mp4");
	if (vc.isOpened())
	{
		while (flag)
		{
			cv::Mat Mat;
			vc >> Mat;
			if (Mat.empty()) { continue; }
			static short rrate = 0;
			if (++rrate < 3) { continue; }rrate = 0;
			///
			// 提取灰度图
			cv::Mat SrcMat;
			cv::cvtColor(Mat, SrcMat, cv::COLOR_BGR2GRAY);
			// Mat转化为dlib的matrix
			dlib::array2d<dlib::bgr_pixel> dimg;
			dlib::assign_image(dimg, dlib::cv_image<uchar>(SrcMat));
			
			// 获取一系列人脸所在区域
			std::vector<dlib::rectangle> dets = detector(dimg);
			if (dets.size() > 0)
			{
				std::cout << "\tNumber of faces detected: " << dets.size() << std::endl;
				//获取人脸特征点分布
				std::vector<dlib::full_object_detection> shapes;
				for (int i = 0; i < dets.size(); i++)
				{
					//画出人脸所在区域
					cv::Rect r;
					r.x = dets[i].left();
					r.y = dets[i].top();
					r.width = dets[i].width();
					r.height = dets[i].height();
					cv::rectangle(Mat, r, cv::Scalar(255, 0, 0), 2, 1, 0);
					//获取指定一个区域的人脸形状
					dlib::full_object_detection shape = sp(dimg, dets[i]); 
					shapes.push_back(shape);
					std::vector<dlib::matrix<dlib::rgb_pixel>> faces;
					dlib::matrix<dlib::rgb_pixel> face_chip;
					dlib::extract_image_chip(dimg, dlib::get_face_chip_details(shape, 150, 0.25), face_chip);
					faces.push_back(std::move(face_chip));
					std::vector<dlib::matrix<float, 0, 1>> face_descriptors = net(faces);
					if (faces.size() > 0 && regFlag)		// 将人脸矩阵写入本地
					{
						cv::Mat newMat = Mat(r);
						sigRegImage(MatToQImage(newMat));
						regMutex.lock(); regFlag = false; regMutex.unlock();
						writeSaveMatrix(face_descriptors[0]);
					}
					else									// 进行对比得出最相似的人,写上人名
					{
						float score = 1.0; char buf[128] = { "???\0" };
						for (QList<QPair<QString, dlib::matrix<float, 0, 1>>>::iterator it = localFaceInfo.begin(); it != localFaceInfo.end(); ++it)
						{
							QPair<QString, dlib::matrix<float, 0, 1>> pInfo = *it;
							float tScore = length(pInfo.second - face_descriptors[0]);	// 值越小越相似,通常认为小于0.5为正确
							if (score > tScore && tScore < 0.5)
							{
								score = tScore;
								memset(buf, 0, 128); sprintf(buf, "%s(%f%%)", pInfo.first.toStdString(), (1.0 - score)*100.0);
							}
						}
						cv::putText(Mat, buf ,cv::Point(r.x, r.y), 1, 3, cv::Scalar(0, 0, 255),4, 4, 0);
					}
				}
				// 特征绘制
				line_one_face_detections(Mat, shapes);
			}
			///
			QImage Image = MatToQImage(Mat);
			sigImage(Image);
		}
	}
}
void Class::writeSaveMatrix(dlib::matrix<float, 0, 1> Matrix)
{
	QFile wMatrixFile(regString);
	if (wMatrixFile.open(QFile::WriteOnly))
	{
		QByteArray data;
		for (int i = 0; i < Matrix.size(); i++)
		{
			QByteArray ba = QByteArray::number(Matrix(i, 0), 'g', 10);
			data.push_back(ba);
			if (i + 1 != Matrix.size()) { data.push_back(","); }
		}
		wMatrixFile.write(data.toHex());
		wMatrixFile.flush();
		wMatrixFile.close();
	}
	sltDirectoryChanged();
}
void Class::sltDirectoryChanged()
{
	localFaceInfo.clear();
	QDir dir(FACEDIR);
	dir.setFilter(QDir::Files | QDir::NoSymLinks);
	QFileInfoList list = dir.entryInfoList();
	for (unsigned short index = 0; index < list.size(); ++index)
	{
		QFileInfo file_info = list.at(index);
		QString pt = file_info.absoluteFilePath();
		QString ptName = file_info.baseName();
		QFile wMatrixFile(pt);
		if (wMatrixFile.open(QFile::ReadOnly))
		{
			QByteArray data = wMatrixFile.readAll();
			data = QByteArray::fromHex(data);
			QByteArrayList dataList = data.split(',');
			if (dataList.size() == 128)
			{
				dlib::matrix<float, 0, 1> Matrix(128, 1);
				for (unsigned short index = 0; index < dataList.size(); ++index)
				{
					Matrix(index, 0) = dataList[index].toDouble();
				}
				localFaceInfo.push_back(QPair<QString, dlib::matrix<float, 0, 1>>(ptName, Matrix));
			}
			wMatrixFile.close();
		}
	}
}
关注
笔者 - jxd



















