原本是想做一个类似windown hello的人脸识别解锁项目,先做了一个简单的人脸识别的小项目,很多内容其实很多其它博主都做过了,做了一个资源的整合。做的比较垃圾,求指点。
功能演示:
主界面
录入界面
最后识别界面
项目框架
input_face:录入新的人脸信息(录入并存储人脸照片,设置人脸姓名,并保存为csv数据格式)
mainwindow:主界面
my_camera:摄像头模块(摄像头的开闭,获取帧)
my_dlib:包含对人脸数据的全部操作(将人脸数据转化为128D的数据,检查人脸差异)
主要代码:
人脸识别块
//接受人脸mat 返回是否是指定人脸的姓名
QString my_dlib::recognition_face(const cv::Mat &cap)
{
QString name="Unkown";
if(data_csv.size() == 0)
return name;
//在传过来的cap帧上识别人脸
cv::Mat grep_cap;
cv::cvtColor(cap,grep_cap,cv::COLOR_RGBA2GRAY);
//dlib::cv_image<rgb_pixel> dlib_img(grep_cap); //将cv中的Mat转化为dlib中的 image
dlib::cv_image<unsigned char> dlib_img(grep_cap);
auto rects = detector(dlib_img);
//获得脸部的特征点
auto shape = sp(dlib_img, rects[0]);
dlib::matrix<rgb_pixel> face_chip;
extract_image_chip(dlib_img, get_face_chip_details(shape, 150, 0.25), face_chip);
std::vector<dlib::matrix<rgb_pixel>> faces;
faces.clear();
faces.push_back(face_chip);
//利用该人脸获得数据
//每个vector<matrix<float, 0, 1>>里面就有128个float数据
std::vector<matrix<float, 0, 1>> face_descriptor = net(faces); //获得脸部数据
QVector<float> face_data;
matrix_To_Qvector(face_descriptor,face_data);
//用获得的数据和csv中的数据判断差异
QVector<double> e_distance_list;
e_distance_list.clear();
for(int i = 0; i< data_csv.size(); i++)
{
std::vector<matrix<float, 0, 1>> data_csv_matrix;
//Qvector_to_Matrix(data_csv[i],data_csv_matrix);
//double dis=(double)length(face_descriptor[0]-data_csv_matrix[0]);
double dis =get_distance(data_csv[i],face_data); //计算距离差距
if(dis == -1) continue;
e_distance_list.push_back(dis); //将差距结果存放起来
}
auto min = std::min_element(std::begin(e_distance_list), std::end(e_distance_list)); //找到最小值
//最大值和最小值的位置的表示方式:
auto positionmin = std::distance(std::begin(e_distance_list),min); //找到最小值所在的下标
//qDebug()<<"Minimum e distance with person"<<int(positionmin) + 1;
//如果差异小于0.4则证明该人脸为csv文件内的一张脸
if(*min < 0.4)
{
name = folder_name[positionmin];
qDebug()<<"recognition face name :"<<name;
return name;
}
return name;
}
保存人脸数据到csv
//将从dlib中解析的人脸数据 保存到csv
bool save_to_csv(std::vector<std::vector<matrix<float, 0, 1>>> &data)
{
std::string filename = QString("D:/QT_file/opencv_test/face_camera/model/%0.csv").arg("face").toStdString();
if(data.size()==0)
{
return false;
}
std::ofstream outfile(filename, std::ofstream::out);
for(auto descriptors:data)
{
for (const auto& desc : descriptors)
{
for (long r = 0; r < desc.nr(); ++r)
{
for (long c = 0; c < desc.nc(); ++c)
{
outfile << desc(r, c) << ',';
}
}
outfile << '\n';
}
}
outfile.close();
qDebug()<<"save csv ok!";
return true;
}
获取视频帧:
//获得当前摄像头的一帧
QPixmap &my_camera::get_pixmap()
{
capture>>cap; //读取当前帧
ShowFPS_Method(cap); //显示帧率
if (!cap.empty()) //判断当前帧是否捕捉成功 **这步很重要
{
//对图像进行预处理
cvtColor(cap, cap_gray, cv::COLOR_BGR2GRAY); //转为灰度图
equalizeHist(cap_gray, cap_gray); //直方图均衡化,增加对比度方便处理
//进行识别
face_cascade.detectMultiScale(cap_gray, faceRect, 1.1, 3, 0 | cv::CASCADE_DO_ROUGH_SEARCH, cv::Size(50, 50));//检测,检测的结果会放到faceRect中
//开始画框 faceRect.size表示检测到的人脸个数
for (size_t i = 0; i < faceRect.size(); i++)
{
cv::rectangle(cap, faceRect[i], cv::Scalar(0, 255, 0)); //用绿色矩形画出检测到的位置
//在此处要判判断人脸,获取name
QString reco_name = d->recognition_face(cap);
//给图片加文字
cv::putText(cap, reco_name.toStdString(), cv::Point(faceRect[i].x,faceRect[i].y-1), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 0),2,2, 0);
//如果脸部大于10张,就不保存了
cv::Mat faceROI = cap_gray(faceRect[i]); //保存脸部图片
cv::resize(faceROI,faceROI,cv::Size(92, 112));
face_mat = faceROI;
}
//将每一帧的画面添加到label中
imag = Mat2QImage(cap); // 将Mat转换成QImage对象来显示
imag = imag.scaled(m_width, m_height,
Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//设置图片大小和label的长宽一致
pm_cam = QPixmap::fromImage(imag);
//ui->cam->setPixmap(QPixmap::fromImage(imag)); // 将图片显示到label上
}
else
qDebug("can not ");
return pm_cam; //将每一帧的图片传回
}
开源地址:
https://gitee.com/linye2830/face_camera.git
总结:
这个项目还有很多需要改进的地方:
1,视频中人像移动太快,会导致程序直接崩溃。。。。(感觉这个没思路解决)
2,帧率太低,尤其是在识别出已有的人脸时,帧数会特别低(这个我感觉可以用多线程解决,主要是计算过程很耗时)
3,我自己编译的dlib库时release版本的,比较头疼,用qt编译的时候要用release
求大佬指点