前辈的文章详细介绍了训练xml分类器的过程,和人脸检测相关的参数设置和代码,原文在这里:传送门
但是代码直接拿来用的话还是会出问题的,
这篇记录的就是实现上述文章中调用xml的批量图片人脸检测遇到的问题和解决的办法,有空的时候也会将自己训练的详细过程和遇到的问题写出来:
1:首先自己要新建一个VS工程,新建一个是空项目的控制台应用程序,在项目中新建源文件,把代码复制粘贴过来:
2:需要重新配置Opencv的包含目录,库目录和链接库:
添加依赖项:
Wininet.lib
opencv_ml249d.lib
opencv_calib3d249d.lib
opencv_contrib249d.lib
opencv_core249d.lib
opencv_features2d249d.lib
WinInet.lib
opencv_flann249d.lib
opencv_gpu249d.lib
opencv_highgui249d.lib
opencv_imgproc249d.lib
opencv_legacy249d.lib
opencv_objdetect249d.lib
opencv_ts249d.lib
opencv_video249d.lib
opencv_nonfree249d.lib
opencv_ocl249d.lib
opencv_photo249d.lib
opencv_stitching249d.lib
opencv_superres249d.lib
opencv_videostab249d.lib
opencv_objdetect249.lib
opencv_ts249.lib
opencv_video249.lib
opencv_nonfree249.lib
opencv_ocl249.lib
opencv_photo249.lib
opencv_stitching249.lib
opencv_superres249.lib
opencv_videostab249.lib
opencv_calib3d249.lib
opencv_contrib249.lib
opencv_core249.lib
opencv_features2d249.lib
opencv_flann249.lib
opencv_gpu249.lib
opencv_highgui249.lib
opencv_imgproc249.lib
opencv_legacy249.lib
opencv_ml249.lib
3需要注意的地方:
第一个:
#pragma comment(lib,"Wininet.lib") 这里可能需要自己下载wininet.lib和头文件,同和和opencv一样设置库目录和附加依赖项
程序的修改,修改自己图片和分类器存放的路径:
using namespace std;
using namespace cv;
String cascadeName = "E://paper//MIT//haarcascade_frontalface_alt2.xml";//训练数据
//String cascadeName = "E://paper//MIT//data//cascade.xml";
struct PathElem{
TCHAR SrcImgPath[MAX_PATH * 2];
TCHAR RstImgPath[MAX_PATH * 2];
};
int FindImgs(char * pSrcImgPath, char * pRstImgPath, std::list<PathElem> &ImgList);
int nFlag = FindImgs("E:\\paper\\Caltech\\", "E:\\paper\\Caltech_save\\", ImgList);//修改为自己的路径,第一个是待检测图片,第二个路径是检测结果保存
if (nFlag != 0)
{
cout << "Read Image error ! Input 0 to exit \n";
exit(0);
}
到这里,可以编译试运行下,遇到一堆错误:
- 1>d:\code\test_xml\test_xml\test_xml.cpp(57): warning C4018: “<=”: 有符号/无符号不匹配
1>d:\code\test_xml\test_xml\test_xml.cpp(59): error C2664: “cv::Mat cv::imread(const std::string &,int)”: 无法将参数 1 从“TCHAR [520]”转换为“const std::string &”
1> 原因如下: 无法从“TCHAR [520]”转换为“const std::string”
1> 无构造函数可以接受源类型,或构造函数重载决策不明确
解决方法其实很简单:
在属性页常规中将字符集修改为使用多字符字节
编译通过,可以查看人脸检测的效果啦,
到这里又发现无论怎样调整缩放的尺度,检测完保存的图片都没有人脸框:
//detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,rects表示检测到的目标序列,1.1表示
//每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大
//小都可以检测到目标),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的
//最小最大尺寸
rects.clear();
printf("begin...\n");
t = (double)cvGetTickCount();//用来计算算法执行时间
cascade.detectMultiScale(smallImg, rects, 1.75, 2, 0, Size(30, 30));
//|CV_HAAR_FIND_BIGGEST_OBJECT//|CV_HAAR_DO_ROUGH_SEARCH|CV_HAAR_SCALE_IMAGE,
通过对比别人的代码,发现是因为目标的最大最小尺寸有问题,这里我删去size(20,20),在运行,结果就正常了,经测试,自己训练的xml还不错,哈哈~~
修改前:
cascade.detectMultiScale(smallImg,rects,1.1,2,0,Size(20,20),Size(30,30));
修改后:
cascade.detectMultiScale(smallImg, rects, 1.75, 2, 0, Size(30, 30));
这个参数的设置要根据自己图片的情况自己调整~
检测结果: