OpenCV Object Detection

  发布日期:   2020-06-12
  最新修改:   2020-09-27
  阅读次数:   55 次

http://image.catbro.cn/upload_2dc6b38258cf5c60d25cbf3f35ae8e18.png

前言

Object Detection:对象检测(你有没有想过数码相机是如何检测人和脸的?)

对象检测的场景在日常生活中是比较常见的,比如我们日常生活中使用的数码相机的人像模式等,下面将记录一些使用 opencv 来做对象检测相关的知识点


一、Cascade Classifiler 级联分类器

通过了解级联分类器,你将学习到如何在我们的图片中或者video中使用对像检测

目标

  • 了解haar级联对象检测的工作原理。
  • 了解使用基于haar特性的级联分类器处理人脸检测和眼部检测的基本知识
  • 使用CascadeClassifiter类去检测视频流中的对象,从过程中将重点介绍如下方法:
    • 使用CascadeClassifier加载一个.xml 分类器文件。该分类器可以是一个haar 或者lbp分类器。
    • 使用CascadeClassifier detectMultiScale 去执行检测操作

理论

使用基于Haar特征的级联分类器进行目标检测是Paul Viola和Michael Jones在其论文中提出的一种有效的目标检测方法,2001年的“使用简单特征的增强级联进行快速对象检测”是一种基于机器学习的方法,其中从许多正负图像中训练级联函数。然后用于检测其他图像中的对象。

在这里,我们将进行人脸检测。最初,该算法需要大量正图像(面部图像)和负图像(无面部图像)来训练分类器。然后,我们需要从中提取特征。为此,使用下图所示的Haar功能。它们就像我们的卷积核。每个特征都是通过从黑色矩形下的像素总和中减去白色矩形下的像素总和而获得的单个值。

https://i.loli.net/2020/06/11/mgi5hloVudGNB2t.png

现在,每个内核的所有可能大小和位置都用于计算许多功能。(试想一下它需要多少计算?即使是一个24x24的窗口也会产生超过160000个特征)。对于每个特征计算,我们需要找到白色和黑色矩形下的像素总和。为了解决这个问题,他们引入了整体形象。无论您的图像有多大,它都会将给定像素的计算减少到仅涉及四个像素的操作。很好,不是吗?它使事情变得超快。

但是在我们计算的所有这些功能中,大多数都不相关。例如,考虑下图。第一行显示了两个良好的功能。选择的第一个特征似乎着眼于眼睛区域通常比鼻子和脸颊区域更暗的性质。选择的第二个功能依赖于眼睛比鼻梁更黑的属性。但是,将相同的窗口应用于脸颊或其他任何地方都是无关紧要的。那么,我们如何从16万多个功能中选择最佳功能?它是由Adaboost实现的。

https://i.loli.net/2020/06/11/ERK8jOMH3SJka5q.png

为此,我们将所有功能应用于所有训练图像。对于每个功能,它会找到最佳的阈值,该阈值会将人脸分为正面和负面。显然,会出现错误或分类错误。我们选择错误率最低的特征,这意味着它们是对人脸和非人脸图像进行最准确分类的特征。(此过程并非如此简单。开始时,每个图像的权重均相等。每次分类后,误分类图像的权重都会增加。然后,完成相同的过程。计算新的错误率。也是新的砝码。继续该过程,直到达到所需的准确性或错误率或找到所需的功能数量为止。

最终分类器是这些弱分类器的加权和。之所以称为弱分类,是因为仅凭它不能对图像进行分类,而是与其他分类一起形成强分类器。该论文说,甚至200个功能都可以提供95%的准确度检测。他们的最终设置具有大约6000个功能。(想象一下,从160000多个功能减少到6000个功能。这是很大的收获)。

因此,现在您拍摄一张照片。拍摄每个24x24窗口。向其应用6000个功能。检查是否有脸。哇..这不是效率低下又费时吗?是的。作者对此有一个很好的解决方案。

在图像中,大多数图像是非面部区域。因此,最好有一种简单的方法来检查窗口是否不是面部区域。如果不是,请一次性丢弃它,不要再次对其进行处理。相反,应将重点放在可能有脸的区域。这样,我们将花费更多时间检查可能的面部区域。

为此,他们引入了级联分类器的概念。不是将所有6000个功能部件应用到一个窗口中,而是将这些功能部件分组到不同阶段的分类器中,并一一应用。(通常前几个阶段将包含很少的功能)。如果窗口在第一阶段失败,则将其丢弃。我们不考虑它的其余功能。如果通过,则应用功能的第二阶段并继续该过程。经过所有阶段的窗口是一个面部区域。这个计划怎么样!

作者的检测器具有6000多个特征,具有38个阶段,在前五个阶段具有1、10、25、25和50个特征。(上图中的两个功能实际上是从Adaboost获得的最佳两个功能)。根据作者的说法,每个子窗口平均评估了6000多个特征中的10个特征。

因此,这是Viola-Jones人脸检测工作原理的简单直观说明。阅读本文以获取更多详细信息,或查看其他资源部分中的参考资料。

OpenCV中的Haar级联检测

OpenCV提供了一种训练方法(请参阅Cascade Classifier Training)或预先训练的模型,可以使用cv :: CascadeClassifier :: load方法读取该模型。预训练的模型位于OpenCV安装的data文件夹中,或在此处找到。

以下代码示例将使用预训练的Haar级联模型来检测图像中的面部和眼睛。首先,创建一个cv :: CascadeClassifier并使用cv :: CascadeClassifier :: load方法加载必要的XML文件。然后,使用cv :: CascadeClassifier :: detectMultiScale方法完成检测,该方法返回检测到的脸部或眼睛的边界矩形。

from __future__ import print_function
import cv2 as cv
import argparse
def detectAndDisplay(frame):
    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    frame_gray = cv.equalizeHist(frame_gray)
    #-- Detect faces
    faces = face_cascade.detectMultiScale(frame_gray)
    for (x,y,w,h) in faces:
        center = (x + w//2, y + h//2)
        frame = cv.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
        faceROI = frame_gray[y:y+h,x:x+w]
        #-- In each face, detect eyes
        eyes = eyes_cascade.detectMultiScale(faceROI)
        for (x2,y2,w2,h2) in eyes:
            eye_center = (x + x2 + w2//2, y + y2 + h2//2)
            radius = int(round((w2 + h2)*0.25))
            frame = cv.circle(frame, eye_center, radius, (255, 0, 0 ), 4)
    cv.imshow('Capture - Face detection', frame)
parser = argparse.ArgumentParser(description='Code for Cascade Classifier tutorial.')
parser.add_argument('--face_cascade', help='Path to face cascade.', default='data/haarcascades/haarcascade_frontalface_alt.xml')
parser.add_argument('--eyes_cascade', help='Path to eyes cascade.', default='data/haarcascades/haarcascade_eye_tree_eyeglasses.xml')
parser.add_argument('--camera', help='Camera divide number.', type=int, default=0)
args = parser.parse_args()
face_cascade_name = args.face_cascade
eyes_cascade_name = args.eyes_cascade
face_cascade = cv.CascadeClassifier()
eyes_cascade = cv.CascadeClassifier()
#-- 1. Load the cascades
if not face_cascade.load(cv.samples.findFile(face_cascade_name)):
    print('--(!)Error loading face cascade')
    exit(0)
if not eyes_cascade.load(cv.samples.findFile(eyes_cascade_name)):
    print('--(!)Error loading eyes cascade')
    exit(0)
camera_device = args.camera
#-- 2. Read the video stream
cap = cv.VideoCapture(camera_device)
if not cap.isOpened:
    print('--(!)Error opening video capture')
    exit(0)
while True:
    ret, frame = cap.read()
    if frame is None:
        print('--(!) No captured frame -- Break!')
        break
    detectAndDisplay(frame)
    if cv.waitKey(10) == 27:
        break

结果

  • 这是运行上面的代码并将内置摄像头的视频流用作输入的结果: https://i.loli.net/2020/06/11/PGNoyDSe93giZY5.png

确保程序会找到文件haarcascade_frontalface_alt.xml和haarcascade_eye_tree_eyeglasses.xml的路径。它们位于opencv / data / haarcascades中

  • 这是使用文件lbpcascade_frontalface.xml(经过LBP训练)进行人脸检测的结果。对于眼睛,我们继续使用本教程中使用的文件。

https://i.loli.net/2020/06/11/hwNEde32bO7HA8P.png


   转载规则

《OpenCV Object Detection字》GajAngels 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。