照片效果
视频效果
注意: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