前言

使用基于Haar特征的Cascade级联分类器进行人脸识别,
用人脸识别同样的道理,扩展到人眼识别上,
用opencv自带的Harr级联分类器进行人脸、人眼与微笑识别


局限:**
仅为人脸检测,非人脸“辩识”,即只能框出人脸的位置,看不出人脸是谁。
仅能标出静态图片和视频帧上的人脸、人眼和微笑,不能进行“活体识别”,即不能看出这张脸是真人还是手机上的照片,如果用于人脸打卡签到、人脸支付的话会带来潜在的安全风险。
仅为普通的机器学习方法,没有用到深度学习和深层神经网络。

视频:同济子豪兄
点击查看【bilibili】

基础知识

啥是Harr特征

Haar特征包含三种:边缘特征、线性特征、中心特征和对角线特征。每种分类器都从图片中提取出对应的特征。

十行Python代码实现人脸识别 - 图1

十行Python代码实现人脸识别 - 图2

比如上图中,横的黑道将人脸中较暗的双眼提取了出来,而竖的白道将人脸中较亮的鼻梁提取了出来。 这种分类器有很像卷积核,卷积核也是从图片中提取指定特征的筛选器。

啥是Cascade级联分类器

基于Haar特征的cascade级联分类器是Paul Viola和 Michael Jone在2001年的论文”Rapid Object Detection using a Boosted Cascade of Simple Features”中提出的一种有效的物体检测方法。

Cascade级联分类器的训练方法:Adaboost

级联分类器的函数是通过大量带人脸不带人脸的图片通过机器学习得到的。对于人脸识别来说,需要几万个特征,通过机器学习找出人脸分类效果最好、错误率最小的特征。训练开始时,所有训练集中的图片具有相同的权重,对于被分类错误的图片,提升权重,重新计算出新的错误率和新的权重。直到错误率或迭代次数达到要求。这种方法叫做Adaboost
在Opencv中可以直接调用级联分类器函数。

将弱分类器聚合成强分类器

最终的分类器是这些弱分类器的加权和。之所以称之为弱分类器是因为每个分类器不能单独分类图片,但是将他们聚集起来就形成了强分类器。论文表明,只需要200个特征的分类器在检测中的精确度达到了95%。最终的分类器大约有6000个特征。(将超过160000个特征减小到6000个,这是非常大的进步了) 。

级联的含义:需过五关斩六将才能被提取出来

事实上,一张图片绝大部分的区域都不是人脸。如果对一张图片的每个角落都提取6000个特征,将会浪费巨量的计算资源。
如果能找到一个简单的方法能够检测某个窗口是不是人脸区域,如果该窗口不是人脸区域,那么就只看一眼便直接跳过,也就不用进行后续处理了,这样就能集中精力判别那些可能是人脸的区域。 为此,有人引入了Cascade 分类器。它不是将6000个特征都用在一个窗口,而是将特征分为不同的阶段,然后一个阶段一个阶段的应用这些特征(通常情况下,前几个阶段只有很少量的特征)。如果窗口在第一个阶段就检测失败了,那么就直接舍弃它,无需考虑剩下的特征。如果检测通过,则考虑第二阶段的特征并继续处理。如果所有阶段的都通过了,那么这个窗口就是人脸区域。 作者的检测器将6000+的特征分为了38个阶段,前五个阶段分别有1,10,25,25,50个特征(前文图中提到的识别眼睛和鼻梁的两个特征实际上是Adaboost中得到的最好的两个特征)。根据作者所述,平均每个子窗口只需要使用6000+个特征中的10个左右。

OpenCV中的Haar-cascade检测

OpenCV 既可以作为检测器也可以进行机器学习训练。如果你打算训练自己的分类器识别任意的物品,比如车,飞机,咖啡杯等。你可以用OpenCV 创造一个。完整的细节在:Cascade Classifier Training¶中。

小试牛刀:十行代码完成人脸识别

  1. # 导入opencv-python
  2. import cv2
  3. # 读入图片,1表示用彩色方式读入,0表示用灰色方式读入
  4. img = cv2.imread('image1.jpg',1)
  5. # 导入人脸级联分类器引擎,'.xml'文件里包含训练出来的人脸特征
  6. face_engine = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')
  7. # 用人脸级联分类器引擎进行人脸识别,返回的faces为人脸坐标列表,1.3是放大比例,5是重复识别次数
  8. faces = face_engine.detectMultiScale(img,scaleFactor=1.3,minNeighbors=5)
  9. # 对每一张脸,进行如下操作
  10. for (x,y,w,h) in faces:
  11. # 画出人脸框,蓝色(BGR色彩体系),线宽为2
  12. img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
  13. # 在"img1"窗口中展示效果图
  14. cv2.imshow('img1',img)
  15. # 监听键盘上任何按键,如有按键即退出并关闭窗口,并将图片保存为output.jpg
  16. cv2.waitKey(0)
  17. cv2.destroyAllWindows()
  18. cv2.imwrite('output.jpg',img)

十行Python代码实现人脸识别 - 图3

对单个图片进行人脸识别和人眼检测

  1. #导入opencv
  2. import cv2
  3. # 导入人脸级联分类器引擎,'.xml'文件里包含训练出来的人脸特征,cv2.data.haarcascades即为存放所有级联分类器模型文件的目录
  4. face_engin = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')
  5. # 导入人眼级联分类器引擎吗,'.xml'文件里包含训练出来的人眼特征
  6. eye_engin = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_eye.xml')
  7. # 读入一张图片,引号里为图片的路径,需要你自己手动设置
  8. img = cv2.imread('image3.png')
  9. # 用人脸级联分类器引擎进行人脸识别,返回的faces为人脸坐标列表,1.3是放大比例,5是重复识别次数
  10. faces = face_engin.detectMultiScale(img, 1.3, 5)
  11. # 对每一张脸,进行如下操作
  12. for (x,y,w,h) in faces:
  13. # 画出人脸框,蓝色(BGR色彩体系),画笔宽度为2
  14. img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
  15. # 框选出人脸区域,在人脸区域而不是全图中进行人眼检测,节省计算资源
  16. face_area = img[y:y+h, x:x+w]
  17. eyes = eye_engin.detectMultiScale(face_area)
  18. # 用人眼级联分类器引擎在人脸区域进行人眼识别,返回的eyes为眼睛坐标列表
  19. for (ex,ey,ew,eh) in eyes:
  20. #画出人眼框,绿色,画笔宽度为1
  21. cv2.rectangle(face_area,(ex,ey),(ex+ew,ey+eh),(0,255,0),1)
  22. # 在"img2"窗口中展示效果图
  23. cv2.imshow('img2',img)
  24. # 监听键盘上任何按键,如有案件即退出并关闭窗口,并将图片保存为output.jpg
  25. cv2.waitKey(0)
  26. cv2.destroyAllWindows()
  27. cv2.imwrite('output.jpg',img)

十行Python代码实现人脸识别 - 图4

十行Python代码实现人脸识别 - 图5

调用电脑摄像头进行实时人脸识别和人眼识别

  1. import cv2
  2. face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')
  3. eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_eye.xml')
  4. # 调用摄像头摄像头,0 表示电脑的默认摄像头
  5. cap = cv2.VideoCapture(0)
  6. while(True):
  7. # 获取摄像头拍摄到的画面
  8. ret, frame = cap.read()
  9. faces = face_cascade.detectMultiScale(frame, 1.3, 5)
  10. img = frame
  11. for (x,y,w,h) in faces:
  12. # 画出人脸框,蓝色,画笔宽度微
  13. img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
  14. # 框选出人脸区域,在人脸区域而不是全图中进行人眼检测,节省计算资源
  15. face_area = img[y:y+h, x:x+w]
  16. eyes = eye_cascade.detectMultiScale(face_area)
  17. # 用人眼级联分类器引擎在人脸区域进行人眼识别,返回的eyes为眼睛坐标列表
  18. for (ex,ey,ew,eh) in eyes:
  19. #画出人眼框,绿色,画笔宽度为1
  20. cv2.rectangle(face_area,(ex,ey),(ex+ew,ey+eh),(0,255,0),1)
  21. # 实时展示效果画面
  22. cv2.imshow('frame2',img)
  23. # 每5毫秒监听一次键盘动作
  24. if cv2.waitKey(5) & 0xFF == ord('q'):
  25. break
  26. # 最后,关闭所有窗口
  27. cap.release()
  28. cv2.destroyAllWindows()

十行Python代码实现人脸识别 - 图6

十行Python代码实现人脸识别 - 图7

增加摄像头实时微笑识别功能

  1. import cv2
  2. # ---------调用摄像头识别人脸、眼睛和微笑------------
  3. # 人脸和人眼级联分类器引擎
  4. face_engine = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
  5. eye_engine = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')
  6. smile_cascade = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_smile.xml')
  7. # 调用摄像头, 0 表示电脑的默认摄像头
  8. cap = cv2.VideoCapture(0)
  9. while True:
  10. # 获取摄像头拍摄到的画面
  11. ret, frame = cap.read()
  12. faces = face_engine.detectMultiScale(frame, 1.3, 5)
  13. img = frame
  14. for (x, y, w, h) in faces:
  15. img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
  16. face_area = img[y:y+h, x:x+w]
  17. # 人眼检测
  18. # 用人眼级联分类器引擎在人脸区域进行人眼识别,返回的eyes为眼睛坐标列表
  19. eyes = eye_engine.detectMultiScale(face_area, 1.3, 15)
  20. for (ex, ey, ew, eh) in eyes:
  21. cv2.rectangle(face_area, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 1)
  22. # 微笑检测
  23. # 用微笑级联分类器引擎在人脸区域进行人眼识别,返回的eyes为眼睛坐标列表
  24. smiles = smile_cascade.detectMultiScale(face_area, scaleFactor=1.16, minNeighbors=65,
  25. minSize=(25, 25), flags=cv2.CASCADE_SCALE_IMAGE)
  26. for (ex, ey, ew, eh) in smiles:
  27. # 画出微笑框,红色(BGR色彩体系),画笔宽度为1
  28. cv2.rectangle(face_area, (ex, ey), (ex + ew, ey + eh), (0, 0, 255), 1)
  29. cv2.putText(img, 'Smile', (x, y - 7), 3, 1.2, (0, 0, 255), 2, cv2.LINE_AA)
  30. # 实时展示效果画面
  31. cv2.imshow('frame1', img)
  32. # 每5毫秒监听一次键盘动作
  33. if cv2.waitKey(5) & 0xFF == ord('q'):
  34. break
  35. cap.release()
  36. cv2.destroyAllWindows()

十行Python代码实现人脸识别 - 图8

十行Python代码实现人脸识别 - 图9