天天看点

【转载】项目实战—人脸检测之级联分类器实战(二)

在上个教程中,使用 Adaboost 学习分类函数过程非常有效,但仍存在一个重大问题。在图像中,大部分图像为非面部区域。对图像的每个区域给予等同的注意力是没有意义的,因为我们应该主要关注最有可能包含人脸的区域。Viola 和 Jone 使用级联分类器在减少了计算时间的同时,实现了更高的检测率。

关键思想是在识别人脸区域时排除不含人脸的子窗口。由于任务是正确识别人脸,我们希望假阴率最小,即包含人脸却未被识别的子窗口最少。

每个子窗口都使用一系列分类器。这些分类器是简单的决策树:

·如果第一个分类器检测为正样本,继续用第二个

·如果第二个分类器检测是正样本,继续用第三个

·以此类推

虽然有时可能包含人脸的图被认成负样本被子窗口漏检。但初级分类器以较低的计算成本筛除了大多数负样本,下图的分类器可额外消除更多的负样本,但需要更多的计算量。

【转载】项目实战—人脸检测之级联分类器实战(二)

使用 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

【转载】项目实战—人脸检测之级联分类器实战(二)

继续阅读