一、前言
由于还处于学习阶段,大多数内容都是从网上学习借鉴的,重复的内容就不多赘述,只是将自己的经验和想法分享出来。感觉不错的学习资源如下
http://www.cnblogs.com/tornadomeet/archive/2012/03/28/2420936.html
http://www.cnblogs.com/wengzilin/p/3849118.html
http://blog.csdn.net/liulina603/article/details/8197889
二、目标检测概念
在实践前我先阅读了OpenCV中文网用户手册的相关内容,对目标检测有了一个大体的概念。
链接:http://wiki.opencv.org.cn/index.php/Cv模式识别
三、前期准备
1.准备用于人脸识别的正负样本
样本的选取上面链接的博客中说的都很清楚,按要求选好样本的大小,比例
需要注意的是。负样本的选取很有讲究,并不是图片越复杂,图片之间越不相干越好。如果识别有特定的应用场景,则负样本中应尽量挑选具有这类特定场景的图片。当然,我们的人脸识别并没有特定的场景,尽量选中照相时经常出现的背景即可。另外可以考虑添加一些干扰项,比如动物的脸。
下面是我使用的正负样本的下载地址,正样本均标准化为24*24像素,方便大家使用
http://download.csdn.net/detail/u011583927/8534763
2.生成正负样本的描述文件
按照上面链接中的教程一步一步来即可
以正样本为例,先打开cmd
使用cd 命令将命令行的作用位置调到存放样本图像的文件夹下
输入dir /b >pos_image.txt
正样本需要将生产的txt文件中数据格式化成固定格式,负样本不需要
3.创建vec文件
命令:opencv_createsamples.exe -vec pos.vec -info pos_image.txt -bg neg_image.txt -w 24 -h 24 -num 400
四、训练xml文件
命令:opencv_haartraining.exe -data xml -vec pos.vec -bg neg_image.txt -nstages 20 -nsplits 2 -minhitrate 0.999 -maxfalsealarm 0.5 -npos 800 -nneg 2500 -w 24 -h 24 -mem 1024 -mode ALL
训练的参数进行了多次调整,上面所示是我多次修改后最后选用的。训练过程可能出现多种多样的问题,需要耐心的尝试修改自己的样本集。如果并没有达到设置的阶段数就停止迭代,并没有发生错误,只是负样本太少或者不够丰富。我的就是这种情况,设置的20层,只运行到了14层。这种情况不会自动生成想要的xml文件,需要手动运行
文件夹转换为xml文件命令:convert.exe --size="24x24" xml haarcascade.xml
convert.exe是opencv自带的转换文件,名字应该是convert_cascade。exe
xml是训练时生成的文件夹的名字
haarcascade.xml是想要生成的xml文件的名字
由于对于算法的理解还不深刻,参数的选择只是在实践性的尝试。
获得的经验是影响训练的效果的最重要环节是样本的选择好坏!
首先,在你的精力和时间允许的情况下,收集的样本越多越好。正样本好坏会决定人脸的漏识率,负样本的好坏决定了误识率。
仔细分析我的样本可以看出,正样本800个,是直接下载的人脸包,貌似外国人的人脸居多,可能会影响我们的识别。负样本2500个,数量较大。
根据我最后的测试结果,和我们的分析是符合的。人脸的漏识率还是不太满意的,但是误识率比较低。
训练了几个小时,在第13层时停止迭代了,应该是负样本
五、识别
识别代码如下,只是简单调用了openCV提供的函数
#include "cv.h"
#include "highgui.h"CvHaarClassifierCascade* load_object_detector( const char* cascade_path )
{return (CvHaarClassifierCascade*)cvLoad( cascade_path );
}void detect_and_draw_objects( IplImage* image,CvHaarClassifierCascade* cascade,int do_pyramids )
{IplImage* small_image = image;CvMemStorage* storage = cvCreateMemStorage(0);CvSeq* faces;int i, scale = 1;/* if the flag is specified, down-scale the 输入图像 to get a performance boost w/o loosing quality (perhaps) 如果标识(do_puramids)是指定的,把输入图像缩小比例来获得一个性能的提升 without 不稳定的质量*/if( do_pyramids ){small_image = cvCreateImage( cvSize(image->width/2,image->height/2), IPL_DEPTH_8U, 3 );cvPyrDown( image, small_image, CV_GAUSSIAN_5x5 );/*功能:函数cvPyrDown使用Gaussian金字塔分解对输入图像向下采样。格式:void cvPyrDown(const CvArr*src,CvArr*dst,int filter=CV_GAUSSIAN_5x5);参数:src 输入图像。dst 输出图像,其宽度和高度应是输入图像的一半。filter 卷积滤波器类型,目前仅支持CV_GAUSSIAN_5x5。*/scale = 2;}/* use the fastest variant *//*使用了最快速的检测方式*/faces = cvHaarDetectObjects( small_image, cascade, storage, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING );/* draw all the rectangles */for( i = 0; i < faces->total; i++ ){/* extract the rectanlges only *///CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i, 0 );CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i );cvRectangle( image, cvPoint(face_rect.x*scale,face_rect.y*scale),cvPoint((face_rect.x+face_rect.width)*scale,(face_rect.y+face_rect.height)*scale),CV_RGB(255,0,0), 3 );}if( small_image != image )cvReleaseImage( &small_image );cvReleaseMemStorage( &storage );
}
// .exe testImageAddress 分类器地址(xml)
/* takes image filename and cascade path from the command line */
int main( int argc, char** argv )
{IplImage* image;if( argc==3 && (image = cvLoadImage( argv[1], 1 )) != 0 ){CvHaarClassifierCascade* cascade=(CvHaarClassifierCascade*)cvLoad(argv[2]);//CvHaarClassifierCascade* cascade = load_object_detector(argv[2]);detect_and_draw_objects( image, cascade, 1 );cvNamedWindow( "test", 0 );cvShowImage( "test", image );cvWaitKey(0);cvReleaseHaarClassifierCascade( &cascade );cvReleaseImage( &image );}return 0;
}
运行测试文件命令: 可执行文件地址 图片地址 xml文件地址
C:\Users\Administrator\Desktop\lena\x64\Debug\lena.exe D:\数字图像处理\图像处理图片\标准测试图片\dollar.bmp C:\Users\Administrator\Desktop\haarcascade.xml
上传了几张程序运行结果
对于比较明显的人脸,尤其是外国人。。。识别结果还是不错的
还用了一些生活中的照片,识别效果一般,这里就不上传了,有一部分脸会漏识,还会偶尔有误识别。下一步打算把具体的算法深入研究一下,应该会有所突破