人脸识别的第一步就是要找到一个模型可以用简洁又有差异性的方式准确反映出每个人脸的特征。识别人脸时,先将当前人脸采用与前述同样的方式提取特征,再从已有特征集中找出当前特征的最邻近样本,从而得到当前人脸的标签。
LBPH 局部二值模式直方图,使用的模型基于 LBP 局部二值模式算法,具有旋转不变性和灰度不变性等显著的优点,再表述图像局部纹理特征上效果出众。
基本原理就是,将像素点A 的值与其最邻近的 8个像素点的值逐一比较,如果A 的像数值大于其临近点的像数值,得到0,小于其临近点的像素值,得到1。最后将像素点A 与其周围8个像素点比较所得的0,1 值连接起来,得到一个8位的二进制序列,将该二进制序列转换为十进制数作为A 点的 LBP 值。 完成二值化后,任意指定一个开始位置将得到的二值结果进行序列化,组成一个8位的二进制数。例如从中心的正上方开始,顺时针获得二进制序列01011001,十进制就是89,作为当前中心点的像素值。
对图像逐像素用以上方式进行处理,就得到LBP 特征图像,这个特征图像的直方图被称为 LBPH ,就是LBP 直方图。
为了得到不同尺度下的纹理结果,还可以使用圆形邻域,将计算扩大到任意大小的邻域内。圆形邻域可以用 (P, R)表示,其中 P 表示圆形邻域内参与运算的像素点个数,R 表示邻域的半径。
例如:左图就是(4,1)右图(8,2)在参与比较的 8 个邻域像素点中,部分邻域可能不会直接取实际存在的某个位置上的像素点,而是通过计算构造一个“虚拟”像素值来与当前像素点进行比较。 人脸的整体灰度由于受到光线的影响,经常会发生变化,但是人脸各部分之间的相对灰度会基本保持一致,LBP 的主要思想是以当前点与其邻域像素的相对关系作为处理结果,正是因为这一点,再图像灰度整体发生变化(单调变化)时,从LBP 算法提取的特征能保持不变。另外,通过不断旋转邻域得到一系列初始定义的 LBP 值,取其最小值作为该邻域的 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或者其他机器学习算法进行分类了。
在 OpenCV 中,可以用函数 cv2.face.LBPHFaceRecognizer_create()生成 LBPH 识别器实例模型,然后应用 cv2.face_FaceRecognizer.train() 函数完成训练,最后用cv2.face_FaceRecognizer.predict()函数完成人脸识别。
retval = cv2.face.LBPHFaceRecognizer_create( [, radius[, neighbors[, grid_x[, grid_y[, threshold]]]]]) 参数都是可选的。 radius 半径,默认1neighbors 邻域点的个数,默认8邻域可以根据需要计算更多邻域点grid_x 将LBP 特征图像划分为一个个单元格时,每个单元格再水平方向上的像素个数。默认8,就是再LBP 特征图像再行方向上以8个像素为单位分组。grid_y 列方向上单元格的像素个数。threshold 预测时使用的阈值,如果大于该阈值,就认为没有识别到任何目标对象。 None = cv2.face_FaceRecognizer.train( src, labels ) 对每个参考图像计算 LBPH ,得到一个向量,每个人脸都是整个向量集中的一点。 src,训练图像,用来学习的人脸图像labels 标签,人脸图像对应的标签。 label, confidence = cv2.face_FaceRecognizer.predict( src ) 函数对一个待测人脸图像进行判断,寻找与当前图像距离最近的人脸图像, 与哪个人脸图像最近,就像当前待测图像标注为其对应的标签,当然,如果待测图像与所有人脸图像都大于 cv2.face.LBPHFaceRecognizer_create() 中参数 threshold 指定的距离值,就认为没有找到对应的结果,既无法识别当前人脸。 src,需要识别的人脸图像label 返回的识别结果标签confidence 返回的置信度评分,置信度评分用来衡量识别结果与原有模型之间的距离,0表示完全匹配,通常情况下认为小于50的值可以接受,如果该值大于80认为差别较大。EigneFaces 通常也称为特征脸,使用主成分分析(PCA) 方法将高维的人脸数据处理为低维后再进行数据分析和处理,获取识别结果。
现实中,很多信息的表示都是冗余的,例如 上图一组圆的参数就存在冗余信息,因为各个参数之间存在非常强的相关性。
在进行数据分析时,如果我们希望更直观的看到这些参数的值,就需要获取所有字段的值,但是再比较圆面积大小时,就用半径就够了,其他信息就是冗余的。因此我们可以理解 半径 就是表中所列数据中的主成分,将半径从上述数据中提取出来供后续分析使用,就实现了降维。
再大多数情况下,处理的数据复杂的多,我们可能无法直接判断哪些数据是关键的主成分,可以通过 PCA 方法将复杂的数据内的主成分分析出来。EigenFaces 就是对原始数据使用 PCA 方法进行降维,获取其中的主要成分信息,从而实现人脸识别的方法。
PCA 方法是 EigenFaces 方法的核心,它找到了最大化数据总方差特征的线性组合。不可否认,EigenFaces 是一种非常有效的方法,但是它的缺点在于在操作过程中会损失许多特征信息。因此,在一些情况下,如果损失的信息正好是用于分类的关键信息,必然会导致无法完成分类。
Fsiherfaces 采用 LDA (线性判别分析)实现人脸识别。
线性判别分析再对特征降维的同时考虑类别信息。思路就是,在低纬表示下,相同的类应该紧密的聚集在一起,不同类别应该尽可能的分散开,且它们之间的距离应该尽可能的远。简单来说线性判别就是要满足:类别间的差别尽可能大,类别内的差别尽可能的小。
做线性判别时,首先将训练样本集投影到一条直线A 上,让投影后的点满足,同类间的点尽可能靠近,异类间的点尽可能远离。做完投影后,将待测样本投影到直线A 上,根据投影点的位置判定样本的类别,就完成了识别。。
左图和右图就是两条不同的投影线,可以明显看出,样本集在 L2 直线上的投影效果好于在 L1 上的投影效果。
线性判别就是要找一条最优的投影线。找到这条直线后,如果要判断某个待测样本的分组,就可以直接将该样本点向投影线投影,然后根据投影点的位置判断其所属类别。
在 OpenCV 中,通过函数 cv2.face.FisherFaceRecognizer_create()生成 Fisherfaces 识别器实例模型,然后应用 cv2.face_FaceRecognizer.train()函数完成训练,用 cv2.face_FaceRecognizer.predict()函数完成人脸识别。
retval = cv2.face.FisherFaceRecognizer_create( [, num_components[, threshold]] ) num_components 使用 Fisherfaces 准则进行线性判别分析时保留的成分数量,可以采用默认值0,让函数自动设置合适的成分数量。threshold 进行识别时所用的阈值,如果最近的距离比阈值还大,函数会返回 -1 None = cv2.face_FaceRecognizer.train( src, labels ) 对每个参考图像进行计算,得到一个向量,每个人脸都是整个向量集中的一点。label, confidence = cv2.face_FaceRecognizer.predict( src ) 对一个待检测人脸图像进行判断,寻找与其距离最近的人脸图像,与哪个人脸图像最近,就将待测图像识别为对应的标签。 src 待识别的图像label 返回的结果标签confidence 置信度评分。用来衡量识别结果与原有模型之间的距离,0表示完全匹配,值通常在0-20000 之间,低于5000 就认为很可靠了。 import cv2 import numpy as np images=[] for i in range(1,6): images.append(cv2.imread(r'LBP\FM_000046_IEU+00_PM+00_EN_A'+str(i)+'_D0_T0_BB_M0_R1_S0.tif',0)) # 找了CAS-PEAL-R1专业的数据库 for i in range(1,6): images.append(cv2.imread(r'LBP\FM_000214_IEU+00_PM+00_EN_A'+str(i)+'_D0_T0_BB_M0_R0_S0.tif',0)) print(len(images)) labels=[0,0,0,0,0,1,1,1,1,1] recognizer = cv2.face.FisherFaceRecognizer_create() recognizer.train(images, np.array(labels)) predict_image=cv2.imread(r"LBP\FM_000046_IEU+00_PM+00_EN_A6_D0_T0_BB_M0_R1_S0.tif",0) label,confidence= recognizer.predict(predict_image) print("label=",label) print("confidence=",confidence) 10 label= 0 confidence= 944.1640861502074链接: https://pan.baidu.com/s/1AtjeL6oiVxCi3Obef226fw 提取码: 76dy 复制这段内容后打开百度网盘手机App,操作更方便哦。。我就想知道为啥中科院搞得数据库没有中文版的。。。。。