在上个教程中,使用 Adaboost 学习分类函数过程非常有效,但仍存在一个重大问题。在图像中,大部分图像为非面部区域。对图像的每个区域给予等同的注意力是没有意义的,因为我们应该主要关注最有可能包含人脸的区域。Viola 和 Jone 使用级联分类器在减少了计算时间的同时,实现了更高的检测率。
关键思想是在识别人脸区域时排除不含人脸的子窗口。由于任务是正确识别人脸,我们希望假阴率最小,即包含人脸却未被识别的子窗口最少。
每个子窗口都使用一系列分类器。这些分类器是简单的决策树:
·如果第一个分类器检测为正样本,继续用第二个
·如果第二个分类器检测是正样本,继续用第三个
·以此类推
虽然有时可能包含人脸的图被认成负样本被子窗口漏检。但初级分类器以较低的计算成本筛除了大多数负样本,下图的分类器可额外消除更多的负样本,但需要更多的计算量。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNCM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR50djpnT6lEROBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwUTN2QDMwATM4ETMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
使用 Adaboost 训练分类器,并调整阈值使错误率降到最低。在训练该模型时,变量如下:
· 每个阶段分类器数量
· 每个阶段的特征数量
· 每个阶段的阈值
方便的是,在 OpenCV 中,整个模型已经经过预训练,可直接用于人脸检测。
如果想了解有关 Boosting 技术的更多信息,欢迎查看作者关于 Adaboost 的文章:
https://maelfabien.github.io/machinelearning/adaboost
实战
下一步是找到预训练的权重。我们将使用默认的预训练模型来检测人脸、眼睛和嘴巴。
关于OpenCV中的已经训练好的XML文件,这个需要自行去官网下载,这边就不再赘述。
确定路径后,以此方式声明级联分类器:
view plaincopy to clipboardprint?
cascPath = "haarcascade_frontalface_default.xml"
eyePath = "haarcascade_eye.xml"
smilePath = "haarcascade_smile.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
eyeCascade = cv2.CascadeClassifier(eyePath)
smileCascade = cv2.CascadeClassifier(smilePath)
检测图像中的人脸
在实现实时人脸检测算法之前,让我们先尝试在图像上简单检测一下。从加载测试图像开始:
view plaincopy to clipboardprint?
gray = cv2.imread('min.jpg',0)
plt.figure(figsize=(12,8))
plt.imshow(gray, cmap='gray')
plt.show()
然后开始检测人脸,并将检测到的人脸框起来。
view plaincopy to clipboardprint?
# Detect faces
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
flags=cv2.CASCADE_SCALE_IMAGE
)
# For each face
for (x, y, w, h) in faces:
# Draw rectangle around the face
cv2.rectangle(gray, (x, y), (x+w, y+h), (255, 255, 255), 3)
以下是 detectMultiScale 函数常见的参数列表:
·scaleFactor:确定每个图像缩放比例大小。
·minNeighbors:确定每个候选矩形应保留多少个相邻框。
·minSize:最小目标的大小。小于该值的目标将被忽略。
·maxSize:最大目标的大小。大于该值的目标将被忽略。
最后,显示结果:
view plaincopy to clipboardprint?
plt.figure(figsize=(12,8))
plt.imshow(gray, cmap='gray')
plt.show()
在测试图像上成功检测到人脸。现在开始实时检测!
实时人脸检测
下面继续进行实时人脸检测的 Python 实现。第一步是启动摄像头,并拍摄视频。然后,将图像转换为灰度图。这用于减小输入图像的维数。实际上,我们应用了一个简单的线性变换,而不是每个像素用三个点来描述红、绿、蓝。
这在 OpenCV 中是默认实现的。
view plaincopy to clipboardprint?
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
现在我们使用上述定义的 faceCascade 变量,它包含一个预训练算法,现在将其用于灰度图。
view plaincopy to clipboardprint?
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE
)
对于检测到的每个人脸,都加上一个矩形框:
view plaincopy to clipboardprint?
for (x, y, w, h) in faces:
if w > 250 :
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]
对于检测到的每张嘴,都加上一个矩形框:
view plaincopy to clipboardprint?
smile = smileCascade.detectMultiScale(
roi_gray,
scaleFactor= 1.16,
minNeighbors=35,
minSize=(25, 25),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (sx, sy, sw, sh) in smile:
cv2.rectangle(roi_color, (sh, sy), (sx+sw, sy+sh), (255, 0, 0), 2)
cv2.putText(frame,'Smile',(x + sx,y + sy), 1, 1, (0, 255, 0), 1)
对于检测到的每双眼睛,都加上一个矩形框:
view plaincopy to clipboardprint?
eyes = eyeCascade.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
cv2.putText(frame,'Eye',(x + ex,y + ey), 1, 1, (0, 255, 0), 1)
然后计算人脸总数,显示整体图像:
view plaincopy to clipboardprint?
cv2.putText(frame,'Number of Faces : ' + str(len(faces)),(40, 40), font, 1,(255,0,0),2)
# Display the resulting frame
cv2.imshow('Video', frame)
当按下 q 键时,执行退出选项。
view plaincopy to clipboardprint?
if cv2.waitKey(1) & 0xFF == ord('q'):
break
最后当所有操作完成后,关闭所有窗口。
view plaincopy to clipboardprint?
video_capture.release()
cv2.destroyAllWindows()
封装代码:
view plaincopy to clipboardprint?
import cv2
import matplotlib.pyplot as plt
cascPath = "haarcascade_frontalface_default.xml"
eyePath = "haarcascade_eye.xml"
smilePath = "haarcascade_smile.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
eyeCascade = cv2.CascadeClassifier(eyePath)
smileCascade = cv2.CascadeClassifier(smilePath)
font = cv2.FONT_HERSHEY_SIMPLEX
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(200, 200),
flags=cv2.CASCADE_SCALE_IMAGE
)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 3)
roi_gray = gray[y:y + h, x:x + w]
roi_color = frame[y:y + h, x:x + w]
cv2.putText(frame, 'Face', (x, y), font, 2, (255, 0, 0), 5)
smile = smileCascade.detectMultiScale(
roi_gray,
scaleFactor=1.16,
minNeighbors=35,
minSize=(25, 25),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (sx, sy, sw, sh) in smile:
cv2.rectangle(roi_color, (sh, sy), (sx + sw, sy + sh), (255, 0, 0), 2)
cv2.putText(frame, 'Smile', (x + sx, y + sy), 1, 1, (0, 255, 0), 1)
eyes = eyeCascade.detectMultiScale(roi_gray)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
cv2.putText(frame, 'Eye', (x + ex, y + ey), 1, 1, (0, 255, 0), 1)
cv2.putText(frame, 'Number of Faces : ' + str(len(faces)), (40, 40), font, 1, (255, 0, 0), 2)
# Display the resulting frame
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()
至于结果大家自行实验。用自己的摄像头就可以。
查看文章汇总页https://blog.csdn.net/weixin_44237705/article/details/107864965
更多openvino技术信息可以入群交流~
申请备注:CSDN