OpenCV3计算机视觉+Python(五)
人脸检测和识别
本章将介绍Haar级联分类器,通过对比分析相邻图像区域来判断给定图像或子图像与已知对象是否匹配。本章将考虑如何将多个Haar级联分类器构成一个层次结构,即一个分类器能识别整体区域(如人脸),而其他的分类器可识别小的区域(眼睛、鼻子和嘴)。
Haar级联的概念
当谈到目标分类和位置跟踪时,希望精确定位什么?什么才是目标的可识别部分?
摄影作品(甚至是来自网络摄像头的图像)可能包含很多令人愉悦的细节。但是,由于灯光、视角、视距、摄像头抖动以及数字噪声的变化,图像细节变得不稳定。人们在分类时不会受这些物理细节方面差异的影响。
提取出图像的细节对产生稳定分类结果和跟踪结果很有用。这些提取的结果被称为特征,专业的表述为:从图像数据中提取特征。虽然任意像素都可能影响多个特征,但特征应该比像素数少得多。两个图像的相似程度可以通过它们对应特征的欧式距离来度量。
例如,距离可能以空间坐标或颜色坐标来定义。类Haar特征是一种用于实现实时人脸跟踪的特征。文献《Robust Real-Time Face Detection,Paul Viola and Michael Jones,Kluwer Academic Publishers,2001》首次采用这种特征来进行人脸检测。每个类Haar特征都描述了相邻图像区域的对比模式。例如,边、顶点和细线都能生成具有判别性的特征。
对给定的图像,特征可能会因区域大小而有所不同,区域大小也可被称为窗口大小。即使窗口大小不一样,仅在尺度上不同的两幅图像也应该有相似的特征。因此,能为不同大小的窗口生成特征非常有用。这些特征集合称为级联。Haar级联具有尺度不变性,换句话说,它在尺度变化上具有鲁棒性。OpenCV提供了尺度不变Haar级联的分类器和跟踪器,并可将其保存成指定的文件格式。
OpenCV的Haar级联不具有旋转不变性。例如,Haar级联不认为倒置的人脸图像和直立的人脸图像一样,而侧面的人脸图像与正面的人脸图像也不一样。更可通过多种图像变换和多种窗口大小来提高Haar级联的旋转鲁棒性,但这样会变得很复杂,而且会耗费更多计算资源。
获取Haar级联数据
在OpenCV3源代码的副本中会有一个文件夹data/haarcascades.该文件夹包含了所有OpenCV的人脸检测的XML文件,并将haarcascades文件夹中的所有文件复制到cascades文件夹中:
haarcascade_profileface.xml
haarcascade_righteye_2splits.xml
haarcascade_russian_plate_number.xml
haarcascade_smile.xml
haarcascade_upperbody.xml
从文件名可知这些级联是用于人脸、眼睛、鼻子和嘴的跟踪。这些文件需要正面、直立的人脸图像。在稍后创建人脸检测器时会使用这些文件。有了很大的耐心以及强大的计算机,就可以创建自己的级联,并训练这些级联来检测各种对象。
使用OpenCV进行人脸检测
在静态图像或视频中检测人脸的操作非常相似。视频人脸检测只是从摄像头读出每帧图像,然后采用静态图像中的人脸检测方法进行检测。当然,视频人脸检测还涉及其他的概念,例如跟踪,而静态图像中的人脸检测就没有这样的概念,但它们基本理论是一致的。
静态图像中的人脸检测
人脸检测首先是加载图像并检测人脸,这也是最基本的一步。为了使所得到的结果有意义,可在原始图像的人脸周围绘制矩形框。
现在,项目中已经包含了haarcascades文件夹的内容,下面创建一个基本的脚本来实现人脸检测。
import cv2 filename='3.jpg' def detect(filename): face_cascade=cv2.CascadeClassifier('haarcascade_frontalface_default.xml') face_cascade.load('C:/Users/yif/Anaconda3/envs/tensorflow/Lib/site-packages/opencv_python-3.4.0.dist-info/haarcascades/haarcascade_frontalface_default.xml') img=cv2.imread(filename) gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) faces=face_cascade.detectMultiScale(gray,1.3,5) for (x,y,w,h) in faces: img=cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) cv2.namedWindow('Vikings Detected') cv2.imshow('Vikings Detected',img) cv2.waitKey() detect(filename)
注意:
face_cascade=cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
face_cascade.load('C:/Users/yif/Anaconda3/envs/tensorflow/Lib/site-packages/opencv_python-3.4.0.dist-info/haarcascades/haarcascade_frontalface_default.xml')
该变量为CascadeClassifier对象
face_cascade.detectMultiScale传递参数是scaleFactor和minNeighbors,它们分别表示人脸检测过程中每次迭代时图像的压缩率以及每个人脸矩形保留近邻数目的最小值。
检测操作的返回值为人脸矩形数组。函数cv2.rectangle允许通过坐标来绘制矩形(x和y表示左上角的坐标,w和h表示人脸矩形的宽度和高度)
通过依次提取faces变量中的值来找到人脸,并在人脸周围绘制蓝色矩形,这是在原始图像而不是图像的灰色版本上进行绘制。
视频中的人脸检测
在视频的帧上重复这个过程就能完成视频(如摄像头的输入或视频文件)中的人脸检测。
该脚本将执行以下任务:打开摄像头,读取帧,检测帧中的人脸,扫描检测到的人脸中的眼睛,对人脸绘制蓝色的矩形框,对眼睛绘制绿色的矩形框。
import cv2 def detect(): face_cascade=cv2.CascadeClassifier('haarcascade_frontalface_default.xml') eye_cascade=cv2.CascadeClassifier('haarcascade_eye.xml') face_cascade.load('C:/Users/yif/Anaconda3/envs/tensorflow/Lib/site-packages/opencv_python-3.4.0.dist-info/haarcascades/haarcascade_frontalface_default.xml') eye_cascade.load('C:/Users/yif/Anaconda3/envs/tensorflow/Lib/site-packages/opencv_python-3.4.0.dist-info/haarcascades/haarcascade_eye.xml') camera=cv2.VideoCapture(0) while(True): ret,frame=camera.read() gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) faces=face_cascade.detectMultiScale(gray,1.3,5) for (x,y,w,h) in faces: img=cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) roi_gray=gray[y:y+h,x:x+w] eyes=eye_cascade.detectMultiScale(roi_gray,1.03,5,0,(40,40)) for (ex,ey,ew,eh)in eyes: cv2.rectangle(img,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) cv2.imshow("camera",frame) camera.release() cv2.destroyAllWindows() if __name__=="__main__": detect()
首先用detect函数加载Haar级联文件,由此可以执行人脸检测。
然后打开一个VideoCapture目标(初始化摄像头)。VideoCapture构造函数的参数用来表示要使用的摄像头
接下来捕获帧。read()函数会返回两个值:第一个值为布尔值,用来表明是否成功读取帧,第二个值为帧本身。捕捉到帧后,将其转换为灰度图像。这个操作很有必要。
与静态图像的例子一样,对具有灰度色彩空间的帧调用detectMultiScale
在眼睛检测中还有另外几个参数,因为眼睛是在确定了人脸的基础上,在比较小的图像上确定眼睛。
同样用循环输出检测眼睛的结果,并在其周围绘制绿色的矩形框
人脸识别
人脸检测是OpenCV的一个很不错的功能,它是人脸识别的基础。什么是人脸识别?其实就是一个程序能识别给定图像或视频中的人脸。实现这一目标的方法之一(OpenCV也采用这种方法)是用一系列分好类的图像(人脸数据库)来训练程序,并基于这些图像来进行识别。
这就是OpenCV及其人脸识别模块进行人脸识别的过程。
人脸识别模块的另一个重要特征是:每个识别都具有转置信评分,因此可在实际应用中通过对其设置阈值来进行筛选。
人脸识别所需要的人脸可以通过两种方式来得到:自己获得图像或从人脸数据库免费获得可用的人脸图像
1.生成人脸识别数据
下面继续介绍生成图像的脚本。这里需要一些包含不同表情的图像,但是,必须确保样本图像满足如下条件:
1)图像是灰度格式,后缀名为.pgm
2)图像形状为正方形
3)图像大小要一样
import cv2 def generate(): face_cascade=cv2.CascadeClassifier('haarcascade_frontalface_default.xml') eye_cascade=cv2.CascadeClassifier('haarcascade_eye.xml') face_cascade.load('C:/Users/yif/Anaconda3/envs/tensorflow/Lib/site-packages/opencv_python-3.4.0.dist-info/haarcascades/haarcascade_frontalface_default.xml') eye_cascade.load('C:/Users/yif/Anaconda3/envs/tensorflow/Lib/site-packages/opencv_python-3.4.0.dist-info/haarcascades/haarcascade_eye.xml') camera=cv2.VideoCapture(0) count=0 while(True): ret,frame=camera.read() gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) faces=face_cascade.detectMultiScale(gray,1.3,5) for (x,y,w,h)in faces: img=cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) f=cv2.resize(gray[y:y+h,x:x+w],(200,200)) cv2.imwrite('./data/%s.pgm'%str(count),f) count+=1 cv2.imshow("camera",frame) if (cv2.waitKey(int(1000/12)))&(0xff==ord("q")): break camera.release() cv2.destroyAllWindows() if __name__=="__main__": generate()
2.人脸识别
OpenCV3有三种人脸识别的方法,它们分别基于三种不同的算法:Eigenfaces、Fisherfaces和Local Binary Pattern