基于OpenCV 的人脸检测试验

292 阅读2分钟
  • 首先介绍级联分类器核心函数 detectMultiScale

1.输入图像

2.scaleFactor = 1.1 这个是每次缩小图像的比例,默认是1.1

3.minNeighbors = 3 匹配成功所需的周围矩形框的数目,每个特征匹配到的区域都是一个矩形框, 只有多个矩形同时存在的时候,才认为是匹配成功。

4.minSize 匹配人脸的最小范围

5.flags=0 可以取值

CASCADE_DO_CANNY_PRUNING 利用canny 边缘检测来排除一些边缘很少或者很多的图像区域

CASCADE_SCALE_IMAGE 正常比例检测

CASCADE_FIND_BIGGEST_OBJECT 只检测最大的物体

CASCADE_DO_ROUGH_SEARCH 初略检测
  • 采集人脸样本函数
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
import os
import imghdr
# 人脸检测
def facedetect(path, output):
    # 获取文件名
    fileName = os.path.basename(path)
#     print (fileName)
    # 读出图片
    face = cv.imread(path)
    face = cv.cvtColor(face,cv.COLOR_BGR2GRAY)
    # 级联分类器
    detector = cv.CascadeClassifier('haarcascade_frontalface_alt.xml')
    rects = detector.detectMultiScale(face, scaleFactor=1.1, minNeighbors=2, minSize=(10, 10), flags=cv.CASCADE_SCALE_IMAGE)
    for (x, y, w, h) in rects:
        # 截取人脸,并且都转化为200*200
        f = cv.resize(face[y:y+h, x:x+w], (200, 200))
        # 写入指定路径
        cv.imwrite(os.path.join(output, fileName), f)
# 检测并截取人脸
def predict_face(path, output):
    # 创建输出文件夹
    if not os.path.exists(output):
        os.makedirs(output)
    # 循环每个人物的文件夹下的图片
    for files in os.listdir(path):
        if os.path.isdir(os.path.join(path, files)):
            output2 = os.path.join(output, files)
            if not os.path.exists(output2):
                os.makedirs(output2)
            # 人物文件夹的完整路径
            fileDir = os.path.join(path, files)
            # 每个人脸的照片
            for file in os.listdir(fileDir):
                filePath = os.path.join(fileDir,file)
                # 检测人脸并保存
                facedetect(filePath, output2)
  • 预处理生成人脸抠图样本
predict_face('src', 'predict')
  • 抠图样本生成对应的 txt文件,存入路径和标识,用于模型训练
def get_label(path):
    fh = open('label.txt', 'w')
    # 表示人脸的Label
    label = 0
    for root,dirs,files in os.walk(path):
        # 循环每个文件夹
        for subdir in dirs:
            # 文件完整路径
            subdir_path = os.path.join(root, subdir)
            # 循环每个人物文件夹下面的每张照片
            for file in os.listdir(subdir_path):
                # 照片完整路径
                filePath = os.path.join(subdir_path, file)
                # 判断文件类型
                imgType = imghdr.what(filePath)
                if imgType == 'jpeg' or imgType == 'png' or imgType == 'jpg':
                    # 保存图片路径
                    fh.write(filePath)
                    fh.write(':')
                    # 标签
                    fh.write(str(label))
                    fh.write('\n')
            label = label + 1
    fh.close()
get_label('predict')
  • 训练自己的数据模型
# 保存图片数据
images = []
# 保存标签
labels = []
# 打开文件
fh = open('label.txt', 'r')
# 循环每行数据
for line in fh:
    arr = line.split(':')
    img = cv.imread(arr[0], 0)
    images.append(img)
    lableContent = arr[1].replace('\n','')
    labels.append((int)(lableContent))
# 安装opencv扩展包
# pip install opencv-contrib-python 
# 定义人脸识别模型
model = cv.face.EigenFaceRecognizer_create()
model.train(np.array(images), np.array(labels))
# # 保存模型
model.save('predict_face_lzx_zyq.xml')
  • 人脸检测测试
name = ['zyq', 'lzx']
model = cv.face.EigenFaceRecognizer_create()
model.read('predict_face_lzx_zyq.xml')
detect_images = []
for file in os.listdir('test'):
    filePath = os.path.join('test', file)
    imgType = imghdr.what(filePath)
    if  imgType == 'jpeg' or imgType == 'png' or imgType == 'jpg':
        # 读入图片
        image = cv.imread(filePath)
        image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
        gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
        detector = cv.CascadeClassifier('haarcascade_frontalface_alt.xml')
        rects = detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(10, 10), flags=cv.CASCADE_SCALE_IMAGE)
        for (x, y, w, h) in rects:
            cv.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
            face = cv.resize(gray[y:y+h,x:x+w],(200, 200))
            params = model.predict(face)
            cv.putText(image, name[params[0]],(x+w//2-20,y+h//2), cv.FONT_HERSHEY_SIMPLEX,2,(255,0,0),2)
        detect_images.append(image)
count = len(detect_images)
column = 3
row = count // 3
if not (count % 3 == 0):
    row = row + 1
plt.figure(figsize=(15,8))
for i,img in enumerate(detect_images):
    plt.subplot(row, column, i+1)
    plt.imshow(img)
plt.show()

总结:基于OpenCV 的人脸模型检测,当数据变化或者量增大时,效果并不是很好!!! 继续探索...