参考: https://github.com/shantnu/FaceDetect/


OpenCV

OpenCV cascade 把人脸检测问题分解为好几步。对于每个数据块,它都进行一个粗略、快速的检测。若通过,会再进行一个更仔细的检测,以此不断类推。该算法有 30 到 50 个这样的阶段,或者说 cascade。只有通过全部阶段,算法才会判断检测到人脸。这样做的好处是:大多数图形都会在头几步就产生否定反馈,算法因而不需要在它上面测试所有 6000 个特征,大大节省了时间。相对于“正常流程”耗费数个小时,这可以实时实现人脸检测。

实践中的 Cascade

它的理论也许听起来很复杂,实际操作起来其实是很简单的。这些 cascades 只是一系列包含 OpenCV 数据的 XML 文件。你用想要的 cascade 初始化代码,它自会替你做你想要的事。

由于人脸识别的普遍性,OpenCV 有一系列能检测各种东西的内置 cascade,从眼睛到手到腿都可以检测。甚至还有针对非人体物体的 cascade。比如说,如果你经营一家卖香蕉的水果店,想要监测偷香蕉的人,就有一个家伙开发了一个针对这一场景的算法

理解代码

源代码可在资源库下载。记得拿好 face_detect.py 文本、abba.png 图片以及 haarcascade_frontalface_default.xml。下面,我把代码分解开来。

将图片和 cascade 名字作为命令行参数传入。我们会用 Abba 图片和 OpenCV 提供的默认 cascade 来人脸检测。

# Get user supplied values

imagePath = sys.argv[1]

cascPath = sys.argv[2]

现在,我们创建一个 cascade,并用人脸 cascade 初始化。这把人脸 cascade 导入内存,所以它随时可以使用。记住,该 cascade 只是一个包含人脸检测数据的 XML 文件。

# Create the haar cascade

faceCascade = cv2.CascadeClassifier(cascPath)

读取图片把它转化到灰度格式。

# Read the image

image = cv2.imread(imagePath)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

以下函数做的就是检测人脸,是代码核心部分。所以,我们来过一遍选项。

# Detect faces in the image

faces = faceCascade.detectMultiScale(    

gray,    

scaleFactor=1.1,    

minNeighbors=5,    

minSize=(30, 30),   

flags = cv2.cv.CV_HAAR_SCALE_IMAGE

)

DetectMultiScale 函数是一个检测物体的通用函数。我们在人脸 cascade 上调用它,它检测的就是人脸。

第一个选项是灰度图片。

第二个是 scaleFactor。有的人脸离镜头近,会比其他人脸更大。ScaleFactor 对此进行补偿。

检测算法使用移动窗口来检测物体。在系统宣布检测到人脸之前,minNeighbors 会对当前其周围有多少物体进行定义。MinSize 给出每个窗口的大小。

我用的是这些领域的常用值。现实中,你会拿不同的值试验窗口尺寸、扩展因素等参数,直到找出最比较合适的那一个。

当该函数认为它找到一张人脸时,会返回一个矩形列表。下一步,我们会进行循环,直到它认为检测出了什么。

# 该函数返回四个值:矩形的 x 和 y 坐标,以及它的高和宽。我们用这些值和内置的 rectangle() 函数,画出矩阵。

print "Found {0} faces!".format(len(faces))

# Draw a rectangle around the faces

for (x, y, w, h) in faces:

    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 我们显示该模型,等用户摁下按键。
cv2.imshow("Faces found" ,image)

cv2.waitKey(0)

检验结果

$ python3 face_detect.py abba.png haarcascade_frontalface_default.xml

基于opencv的人体姿态估计 opencv人体检测_OpenCV

那两个东西不是脸,我们再试一次。我调整了参数,发现把 scaleFactor 调成 1.2 能去除错误检测。

基于opencv的人体姿态估计 opencv人体检测_ide_02

发生了什么?第一张图片由高清摄像机近距离拍摄,第二章拍摄距离相对更远,而且可能是用手机拍的。这就是需要调整 scaleFactor 的原因。正如我说的,你需要按照实际场景设置算法,避免假正例。

这里,雷锋网提醒大家,由于这基于机器学习,结果永远不会 100% 精确。大多数情况下,你会得到不错的结果。但算法偶尔会失误。

最终代码在这里

# -*- coding: UTF-8 -*-

"""
opencv实现人脸识别
参考:
1、https://github.com/opencv/opencv/tree/master/data/haarcascades
2、https://github.com/shantnu/FaceDetect
"""

import cv2
import sys

# Get user supplied values
imagePath = "nba.jpg"
# imagePath = sys.argv[1]

cascPath = "./haarcascade_frontalface_default.xml"

# Create the haar cascade
faceCascade = cv2.CascadeClassifier(cascPath)

# Read the image
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Detect faces in the image
faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30),
    # flags = cv2.cv.CV_HAAR_SCALE_IMAGE
)

print("Found {0} faces!".format(len(faces)))

# Draw a rectangle around the faces
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.imshow("Faces found", image)
cv2.waitKey(0)

用网络摄像头

如果你想要用网络摄像头呢?OpenCV 从摄像头读取每一帧,你可以通过处理每一帧进行人脸检测。你需要一个性能强大的 PC

# -*- coding: UTF-8 -*-

"""
opencv实现人脸识别
参考:
1、https://github.com/shantnu/FaceDetect/blob/master/live.py

"""

import cv2
import sys

# Get user supplied values
videoPath = "vtest.avi"
# imagePath = sys.argv[1]

cascPath = "./haarcascade_frontalface_default.xml"

# Create the haar cascade
faceCascade = cv2.CascadeClassifier(cascPath)

# Read the video
cap = cv2.VideoCapture(videoPath)
# cap = cv2.VideoCapture(0) # 对于摄像头 

if not cap.isOpened():
    print("Could not open video", videoPath)
    exit(-1)

while(1):
    ret, image = cap.read()
    if not ret:
        print("Game over!")
        break
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Detect faces in the image
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5,
        minSize=(30, 30),
        # flags = cv2.cv.CV_HAAR_SCALE_IMAGE
    )

    print("Found {0} faces!".format(len(faces)))

    # Draw a rectangle around the faces
    for (x, y, w, h) in faces:
        cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

    cv2.imshow("Faces found", image)
    c = cv2.waitKey(1) & 0xff
    if c == 27: break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()