Qt人脸识别
·
背景
由于工作需要,研究了一下opencv,dlib人脸识别、人脸特征提取,这里做一下记录。
环境
Cmake :3.15
Qt :5.12.12(MinGW 7.3.0)
opencv,dlib的编译可以参考网上的较长,这里不罗嗦了
opencv用于人脸识别
dlib用于人脸特征提取,和特征对比(判断是否是用同一个人)
几个关键方法实现
opencv
// 获取人脸识别后的图片
cv::Mat cvFindFace(std::string face_path){
std::string face_file = cv::samples::findFile(face_path);
cv::Mat image = cv::imread(face_file);
if (image.empty()) {
std::cerr << "Could not open or find the image" << std::endl;
return image;
}
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(image, faces, 1.1, 2, cv::CASCADE_FIND_BIGGEST_OBJECT | cv::CASCADE_DO_ROUGH_SEARCH, cv::Size(30, 30));
for (size_t i = 0; i < faces.size(); i++) {
cv::Rect roi(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
cv::rectangle(image, roi, cv::Scalar(255, 0, 0), 2);
}
return image;
}
// 将cv::Mat转为Qt的QPixmap,用于显示
void FaceRegisterDialog::slotBtnSelectPic(){
file_path_ = "";
QPixmap pixmap;
ui->label->setPixmap(pixmap);
QString filePath = QFileDialog::getOpenFileName(nullptr, QObject::tr("选择图片"),
QDir::homePath(), QObject::tr("Images (*.jpg *.png)"));
if (!filePath.isEmpty()) {
file_path_ = filePath;
cv::Mat image = lx_opencv::cvFindFace(filePath.toStdString());
QImage qImage = cvMat2QImage(image);
pixmap = QPixmap::fromImage(qImage);
pixmap = pixmap.scaled(ui->label->size(),Qt::KeepAspectRatio);
ui->label->setPixmap(pixmap);
}
}
QImage FaceRegisterDialog::cvMat2QImage(const cv::Mat &mat){
QImage image;
int temp = mat.type();
switch(temp )
{
case CV_8UC1:
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
break;
case CV_8UC3:
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
image = image.rgbSwapped();
break;
case CV_8UC4:
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
break;
case CV_16UC4:
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGBA64);
image = image.rgbSwapped();
break;
}
return image;
}
dlib
// 人脸特征提取
std::vector<float> getFaceDescriptor(string face, int &ret) {
std::vector<float> tz_vec;
matrix<rgb_pixel> img;
load_image(img, face);
std::vector<matrix<rgb_pixel>> faces;
for (auto face : detector(img)) {
auto shape = sp(img, face);
matrix<rgb_pixel> face_chip;
extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
faces.push_back(move(face_chip));
}
if (faces.size() == 0) {
cout << "No faces found in image!" << endl;
ret = 1;
return tz_vec;
}
if (faces.size() > 1) {
cout << "Too many faces in image!" << endl;
ret = 10;
return tz_vec;
}
ret = 0;
std::vector<matrix<float, 0, 1>> face_descriptors = net(faces);
matrix<float, 0, 1> tz = face_descriptors.at(0);
for (int i = 0; i < tz.size(); i++) {
tz_vec.push_back(tz(i));
}
return tz_vec;
}
// 人脸特征对比 使用常用的欧式距离,小于某个值得时候认为是同一个人(一般默认是0.6,不过本人验证的时候误差较大,改为了0.4)
int cmpFaceTz(std::vector<float> tz1, std::vector<float> tz2) {
matrix<float, 0, 1> m_tz1(tz1.size());
for (size_t i = 0; i < tz1.size(); ++i) {
m_tz1(i) = tz1[i];
}
matrix<float, 0, 1> m_tz2(tz2.size());
for (size_t i = 0; i < tz2.size(); ++i) {
m_tz2(i) = tz2[i];
}
double dist = length(m_tz1 - m_tz2);
cout << "The distance between the two faces is " << dist << endl;
if (dist < cpm_len) {
cout << "The faces are a match." << endl;
return 0;
} else {
cout << "The faces are not a match." << endl;
return -1;
}
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)