你知道OpenCV可以识别在图片中小猫的脸吗?而且是拿来就能用,不需要其它的库之类的。
之前我也不知道。
但是在KendrickTan曝出这个功能后,我需要亲自体验一下……去看看到OpenCV是如何在我没有察觉到的情况下,将这一个功能添加进了他的软件库(就像一只悄悄溜进空盒子的猫咪一样,等待别人发觉)。
下面,我将会展示如何使用OpenCV的猫咪检测器在图片中识别小猫的脸。同样的,该技术也可以用在视频流中。
使用OpenCV在图片中检测猫咪
如果你查找过OpenCV的代码仓库,尤其是在haarcascades目录里(OpenCV在这里保存处理它预先训练好的Haar分类器,以检测各种物体、身体部位等),你会看到这两个文件:
haarcascade_frontalcatface.xml
haarcascade_frontalcatface_extended.xml
这两个HaarCascade文件都将被用来在图片中检测小猫的脸。实际上,我使用了相同的cascades分类器来生成这篇博文顶端的图片。
在做了一些调查工作之后,我发现这些cascades分类器是由鼎鼎大名的JosephHowse训练和贡献给OpenCV仓库的,他写了很多很棒的教程和书籍,在计算机视觉领域有着很高的声望。
下面,我将会展示给你如何使用Howse的Haarcascades分类器来检测图片中的小猫。
猫咪检测代码
让我们开始使用OpenCV来检测图片中的猫咪。新建一个叫cat_detector.py的文件,并且输入如下的代码:
#importthenecessarypackages
importargparse
importcv2
#constructtheargumentparseandparsethearguments
ap=argparse.ArgumentParser()
ap.add_argument("-i","--image",required=True,
help="pathtotheinputimage")
ap.add_argument("-c","--cascade",
default="haarcascade_frontalcatface.xml",
help="pathtocatdetectorhaarcascade")
args=vars(ap.parse_args())
第2和第3行主要是导入了必要的python包。6-12行用于解析我们的命令行参数。我们仅要求一个必需的参数--image,它是我们要使用OpenCV检测猫咪的图片。
我们也可以(可选的)通过--cascade参数指定我们的Haarcascade分类器的路径。默认使用haarcascades_frontalcatface.xml,假定这个文件和你的cat_detector.py在同一目录下。
注意:我已经打包了猫咪的检测代码,还有在这个教程里的样本图片。你可以在博文原文的“下载”部分下载到。如果你是刚刚接触Python+OpenCV(或者Haarcascade),我建议你下载这个zip压缩包,这个会方便你跟着教程学习。
接下来,就是检测猫的时刻了:
#loadtheinputimageandconvertittograyscale
image=cv2.imread(args["image"])
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#loadthecatdetectorHaarcascade,thendetectcatfaces
#intheinputimage
detector=cv2.CascadeClassifier(args["cascade"])
rects=detector.detectMultiScale(gray,scaleFactor=1.3,
minNeighbors=10,minSize=(75,75))
在15、16行,我们从硬盘上读取了图片,并且进行灰度化(这是一个在将图片传给Haarcascade分类器之前的常用的图片预处理步骤,尽管不是必须的)
20行,从硬盘加载Haarcasacade分类器,即猫咪检测器,并且实例化cv2.CascadeClassifier对象。
在21、22行通过调用detector的detectMultiScale方法使用OpenCV完成猫脸检测。我们给detectMultiScale方法传递了四个参数。包括:
图片gray,我们要在该图片中检测猫脸。
minNeighbors参数控制了检定框的最少数量,即在给定区域内被判断为猫脸的最少数量。这个参数可以很好的排除误报false-positive结果。
最后,minSize参数不言自明。这个值描述每个检定框的最小宽高尺寸(单位是像素),这个例子中就是75*75
detectMultiScale函数会返回rects,这是一个4元组列表。这些元组包含了每个检测到的猫脸的(x,y)坐标值,还有宽度、高度。
最后,让我们在图片上画下这些矩形来标识猫脸:
#loopoverthecatfacesanddrawarectanglesurroundingeach
for(i,(x,y,w,h))inenumerate(rects):
cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),2)
cv2.putText(image,"Cat#{}".format(i+1),(x,y-10),
cv2.FONT_HERSHEY_SIMPLEX,0.55,(0,0,255),2)
#showthedetectedcatfaces
cv2.imshow("CatFaces",image)
cv2.waitKey(0)
给我们这些框(比如,rects)的数据,我们在25行依次遍历它。
在26行,我们在每张猫脸的周围画上一个矩形。27、28行展示了一个整数,即图片中猫咪的数量。
最后,31,32行在屏幕上展示了输出的图片。
猫咪检测结果
为了测试我们的OpenCV猫咪检测器,可以在原文的最后,下载教程的源码。
然后,在你解压缩之后,你将会得到如下的三个文件/目录:
cat_detector.py:我们的主程序
haarcascade_frontalcatface.xml:猫咪检测器Haarcascade
images:我们将会使用的检测图片目录。
到这一步,执行以下的命令:
$pythoncat_detector.py--imageimages/cat_01.jp
图1.在图片中检测猫脸,甚至是猫咪部分被遮挡了。
注意,我们已经可以检测猫脸了,即使它的其余部分是被遮挡的。
试下另外的一张图片:
图2.使用OpenCV检测猫脸的第二个例子,这次猫脸稍有不同。
这次的猫脸和第一次的明显不同,因为它正在发出“喵呜”叫声的当中。这种情况下,我们依旧能检测到正确的猫脸。
在下面这张图片的结果也是正确的:
图3.使用OpenCV和python检测猫脸
我们最后的一个样例就是在一张图中检测多张猫脸:
$pythoncat_detector.py--imageimages/cat_04.jpg图4.在同一张图片中使用OpenCV检测多只猫
注意,Haarcascade返回的检定框不一定是以你预期的顺序。这种情况下,中间的那只猫会被标记成第三只。你可以通过判断他们的(x,y)坐标来自己排序这些检定框。
在这个xml文件中的注释非常重要,JosephHower提到了这个猫脸检测器有可能会将人脸识别成猫脸。
这种情况下,他推荐使用两种检测器(人脸&猫脸),然后将出现在人脸识别结果中的结果剔除掉。
这个算法能够识别图片中的对象,无论它们的位置和比例。而且最令人感兴趣的或许是它能在现有的硬件条件下实现实时检测。
Haarcascades最大的问题就是如何确定detectMultiScale方法的参数正确。特别是scaleFactor和minNeighbors参数。你很容易陷入一张一张图片调参数的坑,这个就是该对象检测器很难被实用化的原因。
换句话说,如果scaleFactor参数过低,你会检测过多的金字塔图层。这虽然可以能帮助你检测到更多的对象。但是他会造成计算速度的降低,还会明显提高误报率。Haarcascades分类器就是这样。
上述的HOG+线性SVM框架的参数更容易调优。而且更好的误报率也更低,但是唯一不好的地方是无法实时运算。
图5.在PyImageSearchGurus课程中学习如何构建自定义的对象识别器。
如果你对学习如何训练自己的自定义对象识别器感兴趣,请务必要去了解下PyImageSearchGurus课程。
在这个课程中,我提供了15节课,覆盖了超过168页的教程,来教你如何从0开始构建自定义的对象识别器。你会掌握如何应用HOG+线性SVM框架来构建自己的对象识别器来识别路标、面孔、汽车(以及附近的其它东西)。
尽管Haarcascades相当有用,但是我们也经常用HOG+线性SVM替代。因为后者相对而言更容易使用,并且可以有效地降低误报率。