计算机视觉(一):人脸检测和识别

1 - 引言

之前我们学习了机器学习数字图像处理的相关知识,了解了基本的概念理论和OpenCV和TensorFlow框架的使用,现在我们可以结合这些知识与工具写出属于我们自己的计算机视觉项目,本文主要介绍了如何使用OpenCV提供的函数来构建一个人脸识别和检测的应用

2 - Haar级联的概念

我们知道提取出图像数据的细节特征对产生稳定分类结果和跟踪结果很有用,两个图像的相似程度可以通过他们对应特征的欧氏距离来度量。

类Haar特征是一种用于实现实时人脸跟踪的特征。文献《Robust Real-time Face Detection》首次采用这种特征来进行人脸检测

OpenCV的源代码中data文件夹中包含了这种特征的XML文件,可以用来检测静止的图像、视频和摄像头中的人脸

我们可以利用这些特征创造自己的级联,并训练这些级联来检测各种对象

3 - 使用OpenCV进行人脸检测

3.1 - 静态图像中的人脸检测

人脸检测首先是加载图像并检测人脸,这也是最基本的一步,我们在图片的人脸处绘制矩形框
首先在项目中创建cascades文件夹,把特征XML文件放入cascades文件夹中。使用Python实现:

import cv2

filename = 'images/6.jpg'

def detect(filename):
    """
    函数:face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    该函数声明了face_cascade变量,该变量为CascadeClassifier对象,它负责人脸检测
    

    函数:faces = face_cascade.detectMultiScale(gray,1.3,5)
    传递的参数是scaleFactor和minNeighbors,它们分别表示人脸检测过程中每次迭代时图像的
    压缩率以及每个人脸矩形保留邻近数目的最小值

    返回值为人脸矩形数组

    函数:img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    通过坐标来绘制矩形(x,y表示左上角的坐标,w,h表示人脸矩形的宽度和高度)


    """
    face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    img = cv2.imread(filename)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray,1.3,5)
    for (x,y,w,h) in faces:
        img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    cv2.namedWindow('Vikings Detected!!')
    cv2.imshow('Vikings Detected!!', img)
    cv2.waitKey(0)

detect(filename)

下面识别索尔维会议中的人脸(有两个人没有检测出来,可见光用使用face_cascade一个特征来识别人脸还是不太行啊)

在这里插入图片描述

3.2 - 视频中的人脸检测

在视频的帧上重复这个过程就能完成视频中的人脸检测

import cv2
import sys
def detect():

    """
    定义两个特征:面部特征和眼部特征

    """
    face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
    camera = cv2.VideoCapture(0)    #0表示使用第一个摄像头

    """
    接下来捕获帧,read()函数会返回两个值:第一个值为布尔值,用来表明是否成功读取帧,第二个值为帧本身。捕捉到帧后,将其
    转换成灰度图像
    """
    while (True):
        ret, frame = camera.read()

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)

        for (x, y, w, h) in faces:  # 返回的x,y代表roi区域的左上角坐标,w,h代表宽度和高度
            img = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
            roi_gray = gray[y:y + h, x:x + w]
            eyes = eye_cascade.detectMultiScale(roi_gray, 1.03, 5, 0, (40, 40))

            for (ex, ey, ew, eh) in eyes:
                cv2.rectangle(img, (x + ex, y + ey), (x + ex + ew, y + ey + eh), (0, 255, 0), 2)

        cv2.imshow("camera", frame)

        key = cv2.waitKey(30) & 0xff #按ESC退出
        if key == 27:
            sys.exit()

if __name__ == "__main__":
    detect()

通过在摄像头中识别的效果
在这里插入图片描述

4 - 人脸识别

我们在实现人脸检测,它是人脸识别的基础,识别和检测的区别在于一个程序能否识别出给定图像或视频中的人脸。实现这一目标的方法之一是用一系列分好类的图像(人脸数据库)来“训练”程序,并基于这些图像来进行识别

在这里,我们可以利用视频操作来生成属于自己的面部数据

4.1 生成人脸识别数据

样本图像满足

  • 图像是灰度格式,后缀名为.pgm
  • 图像形状为正方形
  • 图像大小要一样(这里使用200x200)
import cv2
import sys
def detect():

    """
    定义两个特征:面部特征和眼部特征

    """
    face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
    camera = cv2.VideoCapture(0)    #0表示使用第一个摄像头
    count = 0
    """
    接下来捕获帧,read()函数会返回两个值:第一个值为布尔值,用来表明是否成功读取帧,第二个值为帧本身。捕捉到帧后,将其
    转换成灰度图像
    """
    while (True):
        ret, frame = camera.read()

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)

        for (x, y, w, h) in faces:  # 返回的x,y代表roi区域的左上角坐标,w,h代表宽度和高度
            img = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
            f = cv2.resize(gray[y:y+h, x:x+w],(200,200))
            cv2.imwrite('./data/at/jm/%s.pgm' % str(count),f)
            count += 1
        cv2.imshow("camera", frame)

        key = cv2.waitKey(30) & 0xff #按ESC退出
        if key == 27:
            sys.exit()

if __name__ == "__main__":
    detect()

这样就将数据存储到文件夹中
在这里插入图片描述

4.2 - 人脸识别

Opencv提供的三种算法:

  • Eigenfaces
    通过PCA来处理,分析训练集的主成分,计算训练集相对于数据库的发散程度,并输出一个值,值越小,表面人脸数据库和检测到的人脸之间的差别就越小;
  • Fisherfaces
    PCA衍生并发展起来的概念,采用更复杂的逻辑,比Eigenfaces 更容易得到准确的效果
  • Local Binary Pattern Histogram(LBPH)
    将检测到的人脸分成小单元,并将其与模型中的对应单元进行比较,对每个区域的匹配值产生一个直方图。

这些方法都有类似的过程,即都使用了分好类的训练数据集来训练,并从两方面来确认:是否识别到目标;目标真正被识别到的置信度的度量,这也称为置信度评分

import cv2,os,sys
import numpy as np

def read_images(path, sz = None):
    c = 0
    X, y = [], []

    for dirname, dirnames, filenames in os.walk(path):
        for subdirname in dirnames:
            subject_path = os.path.join(dirname, subdirname)
            for filename in os.listdir(subject_path):
                try:
                    if not filename.endswith('.pgm'):
                        continue
                    filepath = os.path.join(subject_path, filename)
                    im = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)
                    if sz is not None:
                        im = cv2.resize(im,(200,200))
                    X.append(np.asarray(im, dtype=np.uint8))
                    y.append(c)
                except:
                    print("Unexpected error:",sys.exc_info()[0])
            c = c + 1
    return [X, y]

def face_rec(img_path):
    names = ['Leon']
    [X,y] = read_images(img_path)
    y = np.asarray(y, dtype=np.int32)
    model = cv2.face.EigenFaceRecognizer_create()
    model.train(np.asarray(X), np.asarray(y))

    camera = cv2.VideoCapture(0)
    face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    while (True):
        read, img = camera.read()
        faces = face_cascade.detectMultiScale(img, 1.3, 5)
        for (x, y, w, h) in faces:
            img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            roi = gray[x: x+w, y: y+h]
            try:
                roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)
                params = model.predict(roi)
                print("Label: %s, Confidence: %.2f" % (params[0], params[1]))
                cv2.putText(img, names[params[0]], (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)
            except:
                continue
        cv2.imshow("camera", img)
        if cv2.waitKey(1000 // 12) & 0xff == ord('q'):
            break
    cv2.destroyAllWindows()

if __name__ == "__main__":
    face_rec('./data/at/')  #人脸数据路径img_path

可以把人脸检测出来并且识别出是谁的人脸
在这里插入图片描述

置信度评价:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/HHH_ANS/article/details/85234072