【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

栏目: 数据库 · 发布时间: 6年前

内容简介:(本文所使用的Python库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )在我前面的博文局部二值模式(Local Binary Pattern, LBP)是一种用来描述图像局部纹理特征的算子,其最大优势在于旋转不变性,灰度不变性,能够多分辨分析。局部纹理分析有很多潜在的应用,比如工业表层检测,远程监控,图像分析等。

(本文所使用的 Python 库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )

在我前面的博文 【火炉炼AI】机器学习052-OpenCV构建人脸鼻子眼睛检测器 中,讲到了人脸检测的方法和代码实现,但在很多实际场合,我们需要做的是人脸识别,即判断图片中的那张脸是张三还是李四,故而本篇文章我们来看看如何使用LBP直方图来建立一个人脸识别器。

1. 局部二值模式简介

局部二值模式(Local Binary Pattern, LBP)是一种用来描述图像局部纹理特征的算子,其最大优势在于旋转不变性,灰度不变性,能够多分辨分析。局部纹理分析有很多潜在的应用,比如工业表层检测,远程监控,图像分析等。

LBP的基本思想是:原始的LBP算子是3*3的窗口,以中心像素为阈值,将相邻的8个像素的灰度值与中心像素进行比较,如果大于,则设为1,小于则为0,故而得到这9个像素的二值化图,故而名称为局部二值化,如下图所示。从二值化图的左边中心点像素为起点,逆时针方向为正方形,按顺序取该二值化数值,便得到图中Pattern的二进制数值,此数值就是一个LBP编码,此时,我们称该中心像素点的LBP值为11110001。如果对一幅图像中的所有像素点都计算LBP值,得到的就是这幅图的LBP特征图。

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

关于灰度不变性:很明显,原始的局部图中如果灰度值都同时增加一个值或同时减去一个值,便相当于亮度增加或减少,但此时,得到的LBP编码不变,故而称为灰度不变性。需要注意的是:该灰度不变性仅仅适用于灰度值的单调变化。如下图

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

上面的LBP算子有一个缺陷,它只覆盖一个固定半径范围内的小区域,这显然不能满足不同尺寸和频率纹理的需要,故而有人对其进行改进,将3*3领域扩展到任意领域,并用圆形领域代替正方形领域,如下图为以中心像素点为圆心,R为半径,在圆上均匀的选取P个点作为采样点的情况。

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

上图中,R的大小决定了圆的大小,反映了二维空间的尺度;而P的大小决定了采样点数,反映了角度空间的分辨率。同样的,我们还可以改变R和P的值,实现不同的尺度和角度分辨率(如下图)。这也是以后“多分辨率分析”的理论基础。

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

上面的LBP算子虽然能够实现多分辨率,但却不是旋转不变性,图像的旋转会得到不同的LBP值,故有人提出了具有旋转不变性的LBP算子,即不断旋转圆形领域得到一系列初始定义的LBP值,取其最小值作为该领域的LBP值。

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

在LBP的应用中,比如人脸识别,纹理分析中,我们一般不将LBP图谱作为特征向量用于分类识别,而是采用LBP特征图的统计直方图来作为特征向量。

使用LBP直方图来进行特征提取的步骤一般为:

1) 首先将检测窗口划分为16×16的小区域(cell)

2) 对于每个cell中的一个像素,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经比较可产生8位二进制数,即得到该窗口中心像素点的LBP值

3) 然后计算每个cell的直方图,即每个数字(假定是十进制数LBP值)出现的频率;然后对该直方图进行归一化处理

4)最后将得到的每个cell的统计直方图进行连接成为一个特征向量,也就是整幅图的LBP纹理特征向量;然后便可利用SVM或者其他机器学习算法进行分类了。

关于LBP的深入理论,可以参考博文: LBP(局部二值模式)特征提取原理局部二值模式(Local Binary Patterns)进行纹理分类

2. 准备数据集

本项目所用的数据集是脸部数据集的一个子集,此处我只选择三个人的脸部图片来进行测试。数据集有两部分,一个train的文件夹中有三个子文件夹,每个子文件夹代表一个人的脸部图片,test的文件夹只含有各种人脸图片,没有子文件夹。所以首先我们需要将这些图片加载到内存中,下面定义一个函数来加载图片。

# 定义一个函数来加载图片数据集
def load_train_set(imgs_folder,face_cascade):
    '''
    从imgs_folder中加载图片数据和标记,注意imgs_folder中包含有多个子文件夹,每个子文件夹的名称就是label
    '''
    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) 
        label=os.path.split(img_path)[0]
        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转换为数字
    label_encoder=LabelEncoder()
    encode_labels=label_encoder.fit_transform(labels)
    return face_imgs, encode_labels, label_encoder,labels
复制代码

测试下上面的函数是否正常,且显示下加载的脸部照片

# 测试上面函数是否正常
face_cascade=cv2.CascadeClassifier('E:\PyProjects\DataSet\FireAI\cascade_files/haarcascade_frontalface_alt.xml')
face_imgs, labels, label_encoder,labels=load_train_set('E:\PyProjects\/DataSet\FireAI\/faces_dataset/train',face_cascade)
print(len(face_imgs)) # 有53张脸,但是检测得到56个结果,显然有几张图片中检测了多张脸
# 显示任一张人脸
# 由于cv2读取的是BGR,而plt是RGB,故而需要转化一下
plt.imshow(face_imgs[3],cmap='gray')
复制代码

从打印的结果可以看出,多了三张图片,说明有三张不是脸部照片的图片混入,故而需要找出来删除。定义一个函数来找出错误图片

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
复制代码
【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器
【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器
【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

故而需要从原始数据集中删除这三张图片以及对应的label信息

# 从数据集中删除这三张照片对应的信息
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,故而只有行
复制代码

3. 构建LBP直方图识别器

此处的LBP直方图识别器相当于一个分类模型,cv2已经帮我们封装好了这个分类模型,我们只需要调用即可。

# 构建createLBPHFaceRecognizer分类模型
from cv2.face import LBPHFaceRecognizer_create
recognizer=LBPHFaceRecognizer_create()
recognizer.train(face_imgs, encode_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])
            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
复制代码

得到的结果分别为:

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器
【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器
【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

当然,这个识别器只能识别训练图片中已经有的人脸,对于训练集中没有的人脸,它会预测不准确。比如,拿凤姐的图片来预测一下试试。

【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器

估计凤姐这张照片和Person3长的比较像,所以本模型将其预测为Person3

########################小**********结###############################

1,LBP直方图模型可以快速训练并快速识别,在人脸识别领域中有着比较广泛的应用。

#################################################################

注:本部分代码已经全部上传到( 我的github )上,欢迎下载。

参考资料:

1, Python机器学习经典实例,Prateek Joshi著,陶俊杰,陈小莉译


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Rust编程之道

Rust编程之道

张汉东 / 电子工业出版社 / 2019-1 / 128

Rust 是一门利用现代化的类型系统,有机地融合了内存管理、所有权语义和混合编程范式的编程语言。它不仅能科学地保证程序的正确性,还能保证内存安全和线程安全。同时,还有能与C/C++语言媲美的性能,以及能和动态语言媲美的开发效率。 《Rust编程之道》并非对语法内容进行简单罗列讲解,而是从四个维度深入全面且通透地介绍了Rust 语言。从设计哲学出发,探索Rust 语言的内在一致性;从源码分析入......一起来看看 《Rust编程之道》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码