调整基于HAAR特征的AdaBoost级联分类器的物体识别的参数

来源:互联网 发布:数据库地址 编辑:程序博客网 时间:2024/04/29 01:51


1. 基于HAAR特征的AdaBoost级联分类器的物体识别问题

        Paul A. Viola和Michael J. Jones在2001年发表文章“使用简单特征的提高级联检测器的快速物体检测”。同时CSDN上很多博主在07年到13年也纷纷对该方法的原理,库函数内容,XML文件的训练以及OpenCV的实现做出很多工作。同时,调用OpenCV的库函数很方便,能够用很短的代码即可实现人脸的检测。但是,在实际使用中发现,很多训练好的XML文件不好用

2. 调整参数的意义

        既然训练好的XML文件不好用,是不是意味着要重新训练分类器?如果需要检测的物体在OpenCV中有,那么尽量用OpenCV中自带的分类器。因为自带的分类器包含了很多工作人员的心血,绝对不会那么轻易不好用的。所以根据需要根据实际情况查找问题。主要问题包括:图像分辨率,参数设置和物体摆放的位姿

(1)图像分辨率

        如果图像分辨率过低导致图像中的物体不清晰,甚至连人眼都看不清楚,当然检测不出来物体;如果图像分辨率过高,导致物体的大小超出分类器的尺寸,即分类器最多只能检测到物体的一部分,但检测不到整体,这样也不会检测出物体。

(2)参数设置

        参数设置的内容会在调整参数的步骤中详细说明。

(3)物体摆放的位姿

        举个极端的例子:分类器训练的样本都是物体的正面,而实际检测的为物体的反面,物体正面和反面又是截然不同的,所以也有可能检测不出物体。简单地说,训练的样本和测试的样本虽然是同一类物体,但在图像中表现得差异过大。有两种解决办法:数据库不完备,增加数据库样本重新训练;摆正样本。

3. 代码实现

        有人声称用不到25行的代码实现人脸检测,笔者为说明问题,暂时不作代码长度的考虑。下面为笔者应用OpenCV库中检测人脸,左眼,右眼,鼻子,嘴巴等XML文件的实现代码。
import cv2import numpy as npfrom matplotlib import pyplot as plt################################################################################print 'Load Object Cascade Classifier'faceCascade = cv2.CascadeClassifier('D:/OpenCV 2.4.9/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')lefteyeCascade = cv2.CascadeClassifier('D:/OpenCV 2.4.9/opencv/sources/data/haarcascades/haarcascade_mcs_lefteye.xml')righteyeCascade = cv2.CascadeClassifier('D:/OpenCV 2.4.9/opencv/sources/data/haarcascades/haarcascade_mcs_righteye.xml')noseCascade = cv2.CascadeClassifier('D:/OpenCV 2.4.9/opencv/sources/data/haarcascades/haarcascade_mcs_nose.xml')mouthCascade = cv2.CascadeClassifier('D:/OpenCV 2.4.9/opencv/sources/data/haarcascades/haarcascade_mcs_mouth.xml')################################################################################print 'Load Image'imgFile = 'images/face.jpg'# load an original imageimg = cv2.imread(imgFile)# convert color space from bgr to grayimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)imgGray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)faces = faceCascade.detectMultiScale(imgGray, scaleFactor = 1.3, minNeighbors = 4, minSize = (60,60), maxSize = (300,300), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)for (x,y,w,h) in faces:        cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)        faceGray = imgGray[y:y+h, x:x+w]    faceColor = img[y:y+h, x:x+w]        '''    # for small Alice    lefteye = lefteyeCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 5, minSize = (20,20), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    righteye = righteyeCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 5, minSize = (20,20), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    # cannot search nose successfully!    nose = noseCascade.detectMultiScale(faceGray, scaleFactor = 1.1, minNeighbors = 0, minSize = (5,5), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)            # mistaken eye for mouth!    mouth = mouthCascade.detectMultiScale(faceGray, scaleFactor = 1.05, minNeighbors = 10, minSize = (5,5), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    '''            '''    # for big Alice    lefteye = lefteyeCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 18, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    righteye = righteyeCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 16, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    nose = noseCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 10, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)        mouth = mouthCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 10, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    '''        # for face    lefteye = lefteyeCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 18, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    righteye = righteyeCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 16, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    nose = noseCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 16, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)    mouth = mouthCascade.detectMultiScale(faceGray, scaleFactor = 1.3, minNeighbors = 10, minSize = (40,40), maxSize = (80,80), flags = cv2.cv.CV_HAAR_SCALE_IMAGE)              ############################################################################        print 'Add Objects on Face'                                        for (ex,ey,ew,eh) in lefteye:        cv2.rectangle(faceColor, (ex,ey), (ex+ew,ey+eh), (0,255,0), 2)    for (ex,ey,ew,eh) in righteye:        cv2.rectangle(faceColor, (ex,ey), (ex+ew,ey+eh), (255,255,0), 2)                for (ex,ey,ew,eh) in nose:        cv2.rectangle(faceColor, (ex,ey), (ex+ew,ey+eh), (0,255,255), 2)               for (ex,ey,ew,eh) in mouth:        cv2.rectangle(faceColor, (ex,ey), (ex+ew,ey+eh), (0,100,100), 2)################################################################################print 'Display Face Image'                plt.subplot(1,1,1), plt.imshow(img), plt.title('Face Image'), plt.xticks([]), plt.yticks([])plt.show()################################################################################            print 'Goodbye!'

4. 调整参数的步骤

(1)默认参数:设置默认参数观察是否检测到物体;
(2)检测物体的范围:修改minSize(检测的对象最小尺寸,单位:像素*像素)和maxSize(检测对象的最大尺寸),使对象落在检测器的大小范围内;
(3)投票数:设置minNeighbor为0,观察所有的投票结果,投票结果最集中的位置为最终的检测结果。增加投票数滤除误检测的对象,检测到对象的条件越苛刻;减少投票数增加检测到对象的几率,检测到对象的条件越宽松;
(4)尺度:被检测对象的尺度变化,尺度变化的图像的集合可以构成图像金字塔。scaleFactor的合理的范围在1.1~1.4之间,尺度越大,越容易漏掉检测的对象,但检测速度加快;尺度越小,检测越细致准确,但检测速度变慢。

5. 实验结果

        第一幅和第二幅人脸为标准的正脸,应该说检测的过程得还挺完美。
        第三幅人脸检测结果也算是尽力了。刚开始用第二幅图的参数时,检测人脸的分类器会在左边的蜗牛壳那边检测出第二个人脸。通过调整minSize和maxSize才将背景的伪正结果给去掉了。接着是左眼的检测,大爱丽丝的左眼比小爱丽丝的左眼范围大太多,所以需要将左眼的minSize和maxSize调小。调整右眼的参数时,右眼的检测结果重叠在左眼上,我认为是左眼的位姿比较暧昧,同时满足了左右眼的检测标准。检测鼻子时,一直检测不到结果,因为肉眼查看图像发现小爱丽丝的鼻子为细长状,头微微低下使鼻尖处的宽度不够大。检测嘴巴时,嘴巴的投票全部在左眼上,确实小爱丽丝的嘴由于脸部微侧显得特别小,并且相比之下,左眼的形状也更像嘴巴。

技术分享

结语

        Paul Viola大神的文章只给出了大致的框架。本来希望自己写一遍这个实现的过程,但我只写完了积分图像和AdaBoost分类器。最后怎么结合还要查找更多的材料,但有可能就到此为止了,毕竟这个库函数调一调速度可以很快的。
0 0
原创粉丝点击