目前人工智能领域中机器视觉正在快速发展,其产品已经深入到我们的日常生活中,例如各种软件的人脸识别,汽车自动驾驶,自动化药物分拣机器等。Cascade级联分类器基于Haar特征,是一种视觉目标检测的机器学习法,它能够非常快速地处理图像而且能实现高检测速率。

什么是Haar特征?

Haar特征分为三类:边缘特征、线性特征、中心特征和对角线特征。
opencv1-6c0f775d50604f29b654de6b2bc70c6c
特征模板中有黑色和白色的矩形,模板的特征值为白色矩形的像素之和减去黑色矩形的像素和。通过改变特征模板的大小和位置,可以在人脸图像中提取主要特征,如下图所示。
opencv2-60722175facb4f208d9b09e304f4a11e
黑色矩形把人脸照片中颜色较为暗的眼睛特征提取了出来,而白色矩形则把较为亮的鼻梁特征提取了出来。这种方式比较像卷积神经网络,通过卷积核把图片特征提取出来。

什么是卷积神经网络?

卷积神经网络是用于高级计算机视觉的一中算法,这种算法告诉能够告诉计算机如何去识别图像。

卷积神经网络原理

(以下图片引用于这里
计算机对于一个图片,比如字母x或者字母o,只能识别图片像素点,通过卷积神经网络可以告诉计算机这个图片代表x或o,即使图片经过误导性处理计算机也能识别出来。
opencv3-ad7caf724b25408e9256b198a7ed603d

opencv4-06e5871544b64a85ae8f7816dfdf378f

通过把主要的特征提取出来,这个特征称之为卷积核,白色像素点标为1,黑色像素点标记为-1。

opencv5-07c45322c6c743649de1549210f4cb3d
通过卷积核在原图像素点上的扫动,我们可以进行运算,红色数字乘绿色框内的数字之和进行相加,每次扫描得到不同的值再放着一个新的矩阵内(feature map),之后把新矩阵内所有数相加再除以9,以此类推可以得到下图二的feature map,图中的0.77代表卷积核的特征在此图内占0.77,不难看出经过卷积之后字母X的一撇大致显示在图中。
opencv6-628c0699480146fb898dc369b975fb39
图二
opencv6-52cc2fa6329b445dbe611a223f199887

但是如果光是卷积则运算量特别大,在时间要求比较苛刻的场所不能够达到要求,所以要进行池化,池化就是在图二的feature map中只取最大值(当然也可以用平均值代表),减小计算量,其中还需要经过ReLU(修正线性单元)处理(即把负数都换成0,减小计算难度),最后把特征图排列成特征数组进行全链接,每一个数字乘以他的权重相加得到的数组如果于之前训练图片相接近,计算机就能识别出该图片内容,这是通过大量的图片数据训练出来的,只有训练的足够多,全链接所得的结果就更准确。

总结

卷积神经网络流程

卷积线性修正池化全链接

本次学习的Cascade级联分类器就是通过大量人脸图片训练出来的,opencv库中已经封装好了,可以直接python调用。(要注意提前安装好opencv库)

对于人脸的识别处理,由于其特征太多会导致运算复杂,Cascade级联分类器就很好的解决这个问题,将大量特征进行阶段分类,层层递进,只要有一个阶段识别不是人脸则直接跳过,更好的节约时间减少计算量。直接上代码。。。

import cv2
#调用人脸级联分类器
face_data = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
#调用人眼级联分类器
eye_data = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')
#调用微笑级联分类器
smile_data = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_smile.xml')
# 调用摄像头摄像头
cap = cv2.VideoCapture(0)

while (True):
    # 获取摄像头拍摄到的画面
    #第一个参数ret的值为true或false只有没有读取到图片
    #第二个参数frame为当前截取一帧图片
    ret,frame = cap.read()
    faces = face_data.detectMultiScale(frame, 1.3, 2)
    img = frame
    for (x, y, wide, height) in faces:
        # 画出人脸框,蓝色,画笔宽度为2
        #x加上识别出的人脸宽度,y加上人脸高度画出的矩形对角线上第二个点
        #颜色为RGB
        img = cv2.rectangle(img, (x, y), (x + wide, y + height), (255, 0, 0), 2)
        # 框选出人脸区域,在人脸区域而不是全图中进行人眼检测,节省计算资源
        face_area = img[y:y + height, x:x + wide]

        ## 人眼检测
        # 用人眼级联分类器引擎在人脸区域进行人眼识别,返回的eyes为眼睛坐标列表
        eyes = eye_data.detectMultiScale(face_area, 1.3, 10)#1.3为放大比例,10为重复次数
        for (ex, ey, ew, eh) in eyes:
            # 画出人眼框,绿色,画笔宽度为1
            cv2.rectangle(face_area, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 1)
        # 用微笑级联分类器引擎在人脸区域进行人眼识别,返回的eyes为眼睛坐标列表
        smiles = smile_data.detectMultiScale(face_area, scaleFactor=1.16, minNeighbors=65, minSize=(25, 25),
                                                flags=cv2.CASCADE_SCALE_IMAGE)
        for (ex, ey, ew, eh) in smiles:
            # 画出微笑框,红色(BGR色彩体系),画笔宽度为1
            cv2.rectangle(face_area, (ex, ey), (ex + ew, ey + eh), (0, 0, 255), 1)
            #画出smile字体
            cv2.putText(img, 'Smile', (x, y - 7), 3, 1.2, (0, 0, 255), 2)

    # 输出效果窗口
    cv2.imshow('window', img)
    #检测键码,如果按下对应按键则退出窗口,程序结束。
    if cv2.waitKey(5) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

效果如下图

opencv7-126e013c3baa47a5949c1266cd0bb529

Q.E.D.