人脸识别(五)

news/2024/10/3 19:55:05

源码位置:https://github.com/comhaqs/face_find.git  分支: develop_libfacedetection

之前的人脸检测使用的是opencv的人脸检测功能,识别率低,基本无法使用。网上查找的时候有几个库,一个是MTCNN相关库,使用的是鹅厂的ncnn,不过看issues里是说ncnn只针对arm处理器做了优化,PC端效率低,所以就没有测试。另一个是libfacedetection,纯粹C++编写,故使用了该库,

bool face_recognition::train(unsigned char *p_data, int width, int height){try {if(!mp_model || !mp_cascade){return false;}cv::Mat bgr(cv::Size(width, height), CV_8UC3);bgr.data = p_data;// DETECT_BUFFER_SIZE为0x20000这个不能改,libfacedetection固定死了static unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);// 这里跟opencv的不同,是使用非灰度图像,不要尝试传灰度图像,不然会识别错误auto pResults = facedetect_cnn(pBuffer, (unsigned char*)(bgr.ptr(0)), bgr.cols, bgr.rows, (int)bgr.step);if(nullptr != pResults){for(int i = 0; i < *pResults; ++i){short * p = ((short*)(pResults+1))+142*i;int x = p[0];int y = p[1];int w = p[2];int h = p[3];int confidence = p[4];// 这个角度暂时没有使用到// int angle = p[5];if(90 > confidence){continue;}cv::Rect r(x,y,w,h);bool flag_find_face = false;std::string name;// 复制出检测出来的人脸,然后转换成灰度图片,不转换会报错cv::Mat desc;bgr(r).copyTo(desc);cv::Mat gray_desc;gray_desc.create(desc.size(), desc.type());cv::cvtColor(desc, gray_desc, cv::COLOR_BGR2GRAY);int index = -1;double condi = 0.0;// 实际总会返回一个检测结果,置信度暂时不知道怎么使用mp_model->predict(gray_desc, index, condi);if(0 > index){}else{auto iter = m_index_to_name.find(index);if(m_index_to_name.end() == iter){LOG_WARN("找不到对应人脸信息;序号:"<<index);}else{//LOG_INFO("找到人脸;名称:"<<iter->second<<"; 可信度:"<<condi<<"; 序号:"<<index);name = (boost::format("%s[%d][%d]") % iter->second % static_cast<int>(condi) % confidence).str();flag_find_face = true;}}if(flag_find_face){cv::rectangle(bgr, r, CV_RGB(0, 255, 0), 2);cv::putText(bgr, name, Point(r.x + 0.5 * r.width, r.y - 5), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, CV_RGB(0, 255, 0));}else{cv::rectangle(bgr, r, CV_RGB(255, 0, 0), 2);}}}} catch(const std::exception& e){LOG_ERROR("发生错误:"<<e.what());}return true;
}

 

整个类代码如下:

#include <opencv2/opencv.hpp>#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <libfacedetection/facedetectcnn.h>using namespace cv;
using namespace cv::face;#define DETECT_BUFFER_SIZE 0x20000face_recognition::face_recognition()
{}void face_recognition::start(){try{Ptr<LBPHFaceRecognizer> p_model = LBPHFaceRecognizer::create();// 获取训练图片集合std::vector<info_recognition_ptr> infos;if(!find_face_info(infos, "./face")){return;}std::vector<Mat> images;std::vector<int> labels;for(auto& p_info : infos){for(auto& f : p_info->files){// 这里记得是IMREAD_GRAYSCALE,即灰度图片,不然会报错images.push_back(imread(f, cv::IMREAD_GRAYSCALE));labels.push_back(p_info->index);}m_index_to_name.insert(std::make_pair(p_info->index, p_info->name));}// 训练模型p_model->train(images, labels);mp_model = p_model;// 加载opencv提供的人脸检测模型,识别率比较低std::string face_file("./haarcascade_frontalface_alt2.xml");if(boost::filesystem::exists(face_file)){mp_cascade = std::make_shared<cv::CascadeClassifier>();mp_cascade->load(face_file);}else{LOG_ERROR("找不到对应的文件检测模型文件:"<<face_file);}}catch(const std::exception& e){LOG_ERROR("发生错误:"<<e.what());}
}bool face_recognition::train(unsigned char *p_data, int width, int height){try {if(!mp_model || !mp_cascade){return false;}cv::Mat bgr(cv::Size(width, height), CV_8UC3);bgr.data = p_data;// DETECT_BUFFER_SIZE为0x20000这个不能改,libfacedetection固定死了static unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);// 这里跟opencv的不同,是使用非灰度图像,不要尝试传灰度图像,不然会识别错误auto pResults = facedetect_cnn(pBuffer, (unsigned char*)(bgr.ptr(0)), bgr.cols, bgr.rows, (int)bgr.step);if(nullptr != pResults){for(int i = 0; i < *pResults; ++i){short * p = ((short*)(pResults+1))+142*i;int x = p[0];int y = p[1];int w = p[2];int h = p[3];int confidence = p[4];// 这个角度暂时没有使用到// int angle = p[5];if(90 > confidence){continue;}cv::Rect r(x,y,w,h);bool flag_find_face = false;std::string name;// 复制出检测出来的人脸,然后转换成灰度图片,不转换会报错cv::Mat desc;bgr(r).copyTo(desc);cv::Mat gray_desc;gray_desc.create(desc.size(), desc.type());cv::cvtColor(desc, gray_desc, cv::COLOR_BGR2GRAY);int index = -1;double condi = 0.0;// 实际总会返回一个检测结果,置信度暂时不知道怎么使用mp_model->predict(gray_desc, index, condi);if(0 > index){}else{auto iter = m_index_to_name.find(index);if(m_index_to_name.end() == iter){LOG_WARN("找不到对应人脸信息;序号:"<<index);}else{//LOG_INFO("找到人脸;名称:"<<iter->second<<"; 可信度:"<<condi<<"; 序号:"<<index);name = (boost::format("%s[%d][%d]") % iter->second % static_cast<int>(condi) % confidence).str();flag_find_face = true;}}if(flag_find_face){cv::rectangle(bgr, r, CV_RGB(0, 255, 0), 2);cv::putText(bgr, name, Point(r.x + 0.5 * r.width, r.y - 5), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, CV_RGB(0, 255, 0));}else{cv::rectangle(bgr, r, CV_RGB(255, 0, 0), 2);}}}} catch(const std::exception& e){LOG_ERROR("发生错误:"<<e.what());}return true;
}bool face_recognition::find_and_save_face(const std::string& folder_desc, const std::string& folder_src){std::vector<std::string> files;if(!find_file_from_folder(files, folder_src)){return false;}cv::CascadeClassifier cascade;cascade.load("./haarcascade_frontalface_alt2.xml");for(auto& p : files){cv::Mat src = cv::imread(p);if(nullptr == src.data){LOG_ERROR("文件无法正常读取:"<<p);continue;}cv::Mat gray;gray.create(src.size(), src.type());cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);// 人脸检测std::vector<cv::Rect> rect;cascade.detectMultiScale(gray, rect, 1.1, 3, 0);if(rect.empty()){LOG_WARN("没有检测到人脸:"<<p);continue;}int index = 0;for (auto& r : rect){cv::Mat desc;src(r).copyTo(desc);imwrite((boost::format("%s/%d.png") % folder_desc % (index++)).str(), desc);}}return true;
}
bool face_recognition::find_face_info(std::vector<info_recognition_ptr>& infos, const std::string& folder){std::vector<std::string> all_folders;if(!find_folder_from_folder(all_folders, boost::filesystem::system_complete(folder).string())){return false;}int index = 1;for(auto& d : all_folders){std::vector<std::string> files;if (!find_file_from_folder(files, d)) {continue;}auto path = boost::filesystem::system_complete(d);auto parent_folder = path.parent_path().string();auto name = path.string().substr(parent_folder.size() + 1);auto p_info = std::make_shared<info_recognition>();p_info->index = index++;p_info->name = name;for(auto& f : files){p_info->files.push_back(f);}infos.push_back(p_info);}return true;
}bool face_recognition::find_file_from_folder(std::vector<std::string>& files, const std::string& folder, const std::string& extend){boost::filesystem::path path_folder(folder);if(!boost::filesystem::exists(path_folder)){LOG_ERROR("文件夹路径不存在:"<<folder);return false;}boost::filesystem::directory_iterator end;for(boost::filesystem::directory_iterator iter(path_folder); iter != end; ++iter){auto path = iter->path();if (boost::filesystem::is_directory(path)) {continue;}if(!extend.empty() && extend != path.extension()){continue;}files.push_back(path.string());}return true;
}bool face_recognition::find_folder_from_folder(std::vector<std::string>& all_folders, const std::string& folder){boost::filesystem::path path_folder(folder);if(!boost::filesystem::exists(path_folder)){LOG_ERROR("文件夹路径不存在:"<<folder);return false;}boost::filesystem::directory_iterator end;for(boost::filesystem::directory_iterator iter(path_folder); iter != end; ++iter){auto path = iter->path();if (!boost::filesystem::is_directory(path)) {continue;}if("." == path.string() || ".." == path.string()){continue;}all_folders.push_back(path.string());}return true;
}

 

libfacedetection库的人脸检测成功率还是非常高的,比较稳定,符合预期。从测试来看,使用单线程人脸检测分辨率576*324的图像平均耗时55毫秒,人脸识别模块耗时25毫秒,总耗时90毫秒,无法流畅解析视频流,故需跳帧检测,或是多线程处理,或是提高效率。另外,人脸识别模块的成功率非常烂,得找另外的库代替。默认的opencv人脸模块还是靠不住,得自己优化。


https://dhexx.cn/news/show-25386.html

相关文章

平昌县网上书城系统设计与实现

目 录 第一章 概述 1 1.1 开发背景 1 1.2 开发环境 2 1.3 开发工具 2 1.3.1 MyEclipse 2 1.3.2 Navicat 3 1.3.3 MySQL 3 第二章 需求分析 5 2.1 总体需求 5 2.3 功能需求 6 2.4 性能需求 6 2.5 运行需求 6 2.6 其他需求 7 2.7 可行性分析 7 2.7.1技术可行性 7 2.7.2 经济可行性…

Linux系统介绍:内核、shell及软件包管理

目录Linux内核版本查看系统版本shell常见 shell运行 shell查看Linux系统信息查看系统位数查看内存信息查看CPU信息Linux软件包管理源码编译安装RPMRPM包安装rpm命令其它用法yumDPKGDPKG 命令安装apt查看历史命令historyLinux 文件句柄Linux系统主要包括3层&#xff0c; 硬件&am…

基于MATLAB虚拟仿真的四杆机构运动分析

目 录 1 绪论 (1) 1.1 本文研究的目的意义 (1) 1.2 四杆机构的发展与应用 (1) 1.3 本文研究的主要内容 (2) 2 平面四杆机构运动学分析 (3) 2.1 四杆机构自由度的计算 (3) 2.2 角位移分析 (3) 2.3 角速度分析 (3) 2.4 角加速度分析 (3) 2.5 计算仿真前四杆机构的初始参数值 (4) …

360全景开发(一)

自己车上装了个360全景&#xff0c;但不知是安装调试的问题&#xff0c;还是APP开发的问题&#xff0c;拼出来的360全景部分地方有畸变&#xff0c;拼接缝隙明显&#xff0c;额外功能&#xff08;例如ADAS&#xff09;没有&#xff0c;果然便宜没好货。。。恰好最近在学图像处理…

SSH 总是出现ssh_exchange_identification: read: Connection reset by peer问题的解决方案

最近&#xff0c;ssh登录阿里云服务器时经常出现ssh_exchange_identification: read: Connection reset by peer的错误&#xff0c;经过分析排查&#xff0c;可能是因为开始git服务后&#xff0c;服务器的连接数太多&#xff0c;很容易达到ssh的连接上限。当达到连接上限时&…

VSCode + Python环境配置

VSCode Python开发环境配置 目录Visual Studio Code 下载安装设置 Python 环境安装code runner插件配置code runnerRun in Terminal其它配置配置VSCode自动保存快捷键Jupyter Notebook插件安装将ipynb文件转换为markdown系列文章Visual Studio Code 下载安装 Visual Studio Co…

基于Ocean Connect云平台的照明控制系统设计

目 录 摘 要 I Abstract II 1 绪论 1 1.1选题背景及意义 1 1.2国内外研究现状 2 1.2.1云平台发展现状 2 1.2.2智能照明的发展现状 2 1.3 研究主要内容 3 2 总体方案设计 5 2.1 系统的需求分析 5 2.2 系统架构设计 6 2.3 通信协议设计 7 2.3.1协议数据帧格式 7 2.3.2控制协议的具…

360全景开发(二) 鱼眼摄像头校正

鱼眼摄像头校正有很多方法&#xff0c;这里取棋盘法&#xff0c;因为opencv自带这个方法。棋盘法是将一块类似国际象棋的黑白棋盘放到摄像头的前面&#xff0c;然后调用opencv获取棋盘上的角点&#xff0c;算出图像的相关转换矩阵&#xff0c;这样以后这个摄像头的图像就可以直…