NO.57——基于LBP(局部二值特征模式)的人脸识别器

opencv封装了可用于人脸识别的类FaceRecognizer,这个类目前包含三种人脸识别方法:基于PCA变换的人脸识别(EigenFaceRecognizer)、基于Fisher变换的人脸识别(FisherFaceRecognizer)、基于局部二值模式的人脸识别(LBPHFaceRecognizer)。对于像我这样的人脸识别初学者,对人脸识别理论了解得不是很透彻,但并不影响对函数的使用,下面就LBPHFaceRecognizer来详细的谈一下opencv人脸识别的实现。

LBP local binary patterns,从纹理分析的角度来看,图像上某个像素点的纹理特征,大多数情况下是指这个点和周围像素点的关系,即这个点和它的邻域内点的关系。从哪个角度对这种关系提取特征,就形成了不同种类的特征。有了特征,就能根据纹理进行分类。LBP构造了一种衡量一个像素点和它周围像素点的关系。

。灰度不变性LBP( gray scale invariant)

。旋转不变性LBP(rotation invariant)

。旋转不变等价LBP(rotation & uniform invariant)

具体可参考这篇博文,写的很详细。

 

import numpy as np
import pandas as pd
np.random.seed(37) # 使得每次运行得到的随机数都一样
import matplotlib.pyplot as plt
import cv2
from sklearn import preprocessing
from glob import glob
import os
from sklearn.preprocessing import LabelEncoder
# 构建createLBPHFaceRecognizer分类模型
from cv2.face import LBPHFaceRecognizer_create

# 定义一个函数来加载图片数据集
def load_train_set(imgs_folder,face_cascade):
    '''
    从imgs_folder中加载图片数据和标记,注意imgs_folder中包含有多个子文件夹,每个子文件夹的名称就是label
    os.path.join(path1, path2, ...)对多个路径进行拼接
    glob.glob(pathname)遍历当前文件夹下的文件,不能遍历子文件夹中的文件
    '''
    folders=glob(os.path.join(imgs_folder,'*'))   #遍历子文件夹
    imgs_paths=[]
    [imgs_paths.extend(glob(os.path.join(folder, '*.*'))) for folder in folders]  #遍历子文件夹中的图片
    
    face_imgs=[]
    labels=[]
    # 对每一张图片都检测画面上的人脸
    for img_path in imgs_paths:
        image = cv2.imread(img_path, 0)
        #os.path.split():将文件名和路径分割开
        label=os.path.split(img_path)[1]  #索引为0视为路径,索引为1视为文件名
        img_folder=os.path.split(img_path)[0]
        #用训练好的模型检测每一张人脸
        faces = face_cascade.detectMultiScale(image, 1.1, 2, minSize=(100,100))
        for (x, y, w, h) in faces:
            face_imgs.append(image[y:y+h, x:x+w])  #切割的人脸图片
            labels.append(os.path.split(img_folder)[1])   #labels为图名
    # 此处有点不合理,本数据集中每张图片只有一个人脸,故而可以用这个方式,
    # 如果有多个不同人的脸,则不能用折冲方式。
    # 将labels转换为数字。LabelEncoder 将一列文本数据转化成数值
    label_encoder=LabelEncoder()
    encode_labels=label_encoder.fit_transform(labels)
    return face_imgs, encode_labels, label_encoder, labels

#找到错误面孔
def find_false_faces(face_imgs):
    '''
    将所有脸部照片显示出来,如果发现有错误的,按d键,记录下错误的脸部照片
    '''
    need_del_ids=[]
    for idx,face in enumerate(face_imgs):
        cv2.namedWindow('check', cv2.WINDOW_NORMAL)
        cv2.resizeWindow('check', 500, 500)
        cv2.imshow('check', face)
        key = cv2.waitKey(0)
        
        if key==27: # 如果输入时Esc,则退出循环
            print('esc to exit')
            break
        elif key==100: # 如果输入d键,则记录该脸对应的id
            need_del_ids.append(idx)
    cv2.destroyAllWindows()
    print('finished...')
    return need_del_ids

# 从数据集中删除非人脸图片
def delete_error_images(face_imgs, need_del_ids, encode_labels, labels):
    face_imgs=np.delete(np.array(face_imgs), need_del_ids, axis=0)
    encode_labels=np.delete(np.array(encode_labels), need_del_ids, axis=0)
    labels=np.delete(np.array(labels), need_del_ids,axis=0)
    print(face_imgs.shape) # 53张图没错,元素已经变成了np.ndarray,故而只有行
    return face_imgs, encode_labels, labels

# 用训练好的模型预测新照片
def predict_imgs(new_imgs_folder, face_cascade,recognizer,label_encoder):
    '''
    用训练好的人脸识别器来识别人脸
    '''
    img_paths=glob(new_imgs_folder+'/*.*')
    predicted_imgs=[]
    for img_path in img_paths:
        image=cv2.imread(img_path)
        gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        #人脸检测,把检测到的人脸用矩形画出来
        faces=face_cascade.detectMultiScale(gray,1.1, 2, minSize=(100,100))
        for (x, y, w, h) in faces:
            cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),3)
            predicted_index, conf = recognizer.predict(gray[y:y+h, x:x+w])
            #inverse_transform将标准化后的数据转化成原始数据
            predicted_label=label_encoder.inverse_transform([predicted_index])[0]
            #在测试的图片上添加预测出的文字说明
            cv2.putText(image, predicted_label,(x,y-20), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), 3)
        predicted_imgs.append(image)
    return predicted_imgs



if __name__ == '__main__':
    #获取训练好的人脸参数数据
    face_cascade=cv2.CascadeClassifier('/Users/chenyan/important/python_demo/Project/LBP/cascade_files/haarcascade_frontalface_alt.xml')
    face_imgs, encode_labels, label_encoder, labels=load_train_set('/Users/chenyan/important/python_demo/Project/LBP/train',face_cascade)
    print(len(face_imgs)) # 有53张脸,但是检测得到55个结果,显然有几张图片中检测了多张脸
    
    # 任意显示任一张人脸
    # 由于cv2读取的是BGR,而plt是RGB,故而需要转化一下
    #plt.imshow(face_imgs[3],cmap='gray')
    #plt.show()
    
    #找到错误面孔
    #need_del_ids=find_false_faces(face_imgs)
    #print(need_del_ids)
    need_del_ids =[25,47]
    
    #删除错误面孔
    face_imgs, encode_labels, labels = delete_error_images(face_imgs,need_del_ids,encode_labels,labels)
    
    # 构建createLBPHFaceRecognizer分类模型
    recognizer=LBPHFaceRecognizer_create()
    recognizer.train(face_imgs, encode_labels) # 模型训练
    
    predicted=predict_imgs('/Users/chenyan/important/python_demo/Project/LBP/test',face_cascade,recognizer,label_encoder)
    # 随便显示几张预测后的图片
    print(len(predicted))
    
    for i in range(9):
        i=predicted[i].copy()
        i=cv2.cvtColor(i,cv2.COLOR_BGR2RGB)
        plt.imshow(i)
        plt.show()

 

你可能感兴趣的:(图像处理)