惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
Vercel News
Vercel News
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
N
Netflix TechBlog - Medium
Google DeepMind News
Google DeepMind News
H
Help Net Security
罗磊的独立博客
The Cloudflare Blog
J
Java Code Geeks
博客园 - 叶小钗
I
InfoQ
B
Blog
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
腾讯CDC
月光博客
月光博客
博客园_首页
雷峰网
雷峰网
M
MIT News - Artificial intelligence
博客园 - 【当耐特】
美团技术团队
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美

博客园 - Ray Liang

吐血整理JSON-RPC2.0的原理与应用 一小时手搓轻量级可代替 Qdrant 的向量数据库 彻底治愈AI“失忆”和胡说八道的真正办法 AI基于Spec开发是巨坑? 用六边形架构与整洁架构对比是伪命题? 老兵不死,只是换了战场:从27年的企业开发转型AI应用开发 被低估的量化版模型,小身材也能干大事 概念设计在AI时代的重要性:我是这样设计仿生大脑的 Opus现实打脸GLM5“教课书“式架构 顶极模型大比拼,到底谁才是真正的编程之王? EvoMap 硬刚 OpenClaw!从基因胶囊到仿生大脑,AI 的尽头果然是生物学 吊打OpenClaw!国产AI助理MindX开源:Token消耗砍至10%,还能养出专属数字分身 老程序员的信仰 Raspberry Zero 上实现平滑视频图传 ESP8266的低功耗方案-睡眠模式 WIFI智能配网 - SmartConfig Arduino Core For ESP8266 ESP8266-Arduino杀手? Arduino通过MAX9814实现录音 nrf2401 - 最廉价的2.4G无线通信方案
HAAR与DLib的实时人脸检测之实现与对比
Ray Liang · 2018-11-03 · via 博客园 - Ray Liang

人脸检测方法有许多,比如opencv自带的人脸Haar特征分类器和dlib人脸检测方法等。

对于opencv的人脸检测方法,优点是简单,快速;存在的问题是人脸检测效果不好。正面/垂直/光线较好的人脸,该方法可以检测出来,而侧面/歪斜/光线不好的人脸,无法检测。因此,该方法不适合现场应用。而对于dlib人脸检测方法采用64个特征点检测,效果会好于opencv的方法识别率会更高,本文会分别采用这几种方法来实现人脸识别。那个算法更好,跑跑代码就知道。

实时图像捕获

首先在进行人脸识别之前需要先来学点OpenCV的基础,起码知道如何从摄像头获取当前拍到的图像吧。OpenCV其实很简单,接下来的代码就是最基本的起步点。

第一步:打开本机上的摄像头,实例化VideoCapture

camera = cv2.VideoCapture(0)

开始第一帧图像的捕获,这个方法用来测试当前的摄像头是否可用

success, frame = camera.read()

success返回真时表示开始捕捉图像,反则表示摄像头打开失败,接下来就用最少的代码来打开摄像头并将当前的图像直接显示到一个窗口上,具体代码结构如下:

# coding=utf-8
# ~/learn_face/cv_base.py
from __future__ import print_function

import cv2

cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()

while success and cv2.waitKey(1) == -1:
    success, frame = cameraCapture.read()
    #TODO:在此处可放置各种对当前每一帧图像的处理
    cv2.imshow("Camera", frame)

cameraCapture.release()
cv2.destroyAllWindows()

将上述代码存为opencv_base.py然后在命令行直接运行查看效果:

python opencv_base.py

效果如下:

HAAR 分类器

基于Haar特征的cascade分类器(classifiers) 是Paul Viola和 Michael Jone在2001年,论文”Rapid Object Detection using a Boosted Cascade of Simple Features”中提出的一种有效的物品检测(object detect)方法。它是一种机器学习方法,通过许多正负样例中训练得到cascade方程,然后将其应用于其他图片。

在OpenCV3的源码的data目录中就可以找到已训练好的HAAR算法模型,至HAAR算法的各种细节与理论有兴趣的直接去Google或者百度吧,一搜一大堆。花时间看一堆理论不如直接上代码,由代码直接理解这些复杂理论的应用更适合开发人员,毕竟我们不是数学家。

使用HAAR模型识别图像中的人脸其实只要三步走,即使你对深度网络一点不懂也没关系,再复杂的理论到最终不过是一个方法调用罢了,了解清楚其中的原理就好。

第一步:初始化分类器并载入已训练好的HARR模型:

face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml')

第二步: 通过cv2.cvtColor方法将当前的图像进行灰度化处理,简化图像的信息:

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

第三步:然后将灰度化后的图像输入到分类器进行预判:

faces = face_cascade.detectMultiScale(gray, 1.3, 5) #识别人脸

只要faces数组的长度大于一就表示检测到当前画面中检测到人脸,反之亦然。简单来说其实人脸检测已经完成,

最后,为了我们可以知道识别出来的结果,我们可以将脸用方框给圈出来,这里写个方法来圈脸:

def mark_face(img,x,y,w,h):
    return cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)

以下为本例的全部代码:

# coding=utf-8
# ~/learn_face/cv_haar.py
from __future__ import print_function
import cv2

def mark_face(img, x, y, w, h):
    return cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)

cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml') # 1.载入模型

while success and cv2.waitKey(1) == -1:
    success, frame = cameraCapture.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #  2.生成灰度图
    faces = face_cascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5
    ) # 3.进行识别
    [mark_face(frame, *args) for args in faces] #画出识别的结果
    cv2.imshow("Camera", frame)
cameraCapture.release()
cv2.destroyAllWindows()

以下是运行效果:

运行起来就会觉得HAAR的识别效果不怎么样,稍微动一下就很会识别不了。

Dlib

接下来我们试试用DLib这个老牌的专做人脸识别起家的C++库来试试,Dlib是一个跨平台的C++公共库,除了线程支持,网络支持,提供测试以及大量工具等等优点,Dlib还是一个强大的机器学习的C++库,包含了许多机器学习常用的算法。同时支持大量的数值算法如矩阵、大整数、随机数运算等等。Dlib同时还包含了大量的图形模型算法。最重要的是Dlib的文档和例子都非常详细。

与HAAR分类器的检测方法相比dLib就简单得多了,只需要用dlib自带的人脸检测器detector就够了,连模型都省了!之前的代码两步就能完成

第一步:实例化 detector:

detector = dlib.get_frontal_face_detector()

第二步:进行人脸检测

faces = detector(frame, 1)

That's all! 是不是很简单?

以下是本例的全部代码:

# coding=utf-8
# ~/learn_face/cv_dlib.py
from __future__ import print_function
import cv2
import dlib

cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
detector = dlib.get_frontal_face_detector()

while success and cv2.waitKey(1) == -1:
    success, frame = cameraCapture.read()
    faces = detector(frame, 1)
    for k, d in enumerate(faces):
        frame = cv2.rectangle(frame, (d.left(), d.top()),
                              (d.right(), d.bottom()), (255, 0, 0), 2)

    cv2.imshow("Camera", frame)

cameraCapture.release()
cv2.destroyAllWindows()

运行上述代码后会发现dlib的效果真的比HAAR的检测效果要好很多!不管头怎么转都能瞬间识别到,画出来的矩形框都不带闪的!

特征点检测

接下来我们用DLib的特征点提取器detector所识别出来的人脸轮廓点给标记出来。关键点(landmarks)提取需要一个特征提取器predictor,为了构建特征提取器,预训练模型必不可少。除了自行进行训练外,可以使用官方提供的一个模型。该模型可从dlib sourceforge 库下载,此模型是从人脸中提出64个特征点进行检测,其准确度相当高。

具体实现思路如下:

  • 第一步:生成灰度图
  • 第二步:生成直方图
  • 第三步:进行检测

以下为全部代码

# coding=utf-8
# ~/learn_face/landmark.py
import cv2
import dlib

cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(
    "shape_predictor_68_face_landmarks.dat")  

while success and cv2.waitKey(1) == -1:
    success, frame = cameraCapture.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)            #生成灰度图
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))  #生成直方图
    clahe_image = clahe.apply(gray)
    detections = detector(clahe_image, 1)

    for k, d in enumerate(detections): 
        shape = predictor(clahe_image, d)  # 获取坐标
        for i in range(1, 68):  # 每张脸都有68个识别点
            cv2.circle(frame, (shape.part(i).x, shape.part(i).y), 1, (0, 0, 255),
                       thickness=2)

    cv2.imshow("Camera", frame)

cameraCapture.release()
cv2.destroyAllWindows()

运行效果:

小结

我在macBookPro上跑以上的代码在速度是上没有什么很大区别的,至少不会产生卡顿。但如果换将代码植到树莓3和树莓Zero上区别就明显了,HAAR分类器在树梅Zero上的运行时间平均在1.2s左右,而dlib则需要8s。至于准确率Dlib又明显会优于HAAR。

参考阅读

  • HAAR分类器 - 这篇知乎上的文章对HAAR分类器的原理分析得很详尽,有兴趣可以读一读
  • 本文代码可到我的码云上下载