opencv中LBPH算法
人脸识别是指将一个需要识别的人脸和人脸库中的某个人脸对应起来(类似于指纹识别),目的是完成识别功能,该术语需要和人脸检测进行区分,人脸检测是在一张图片中把人脸定位出来,完成的是搜寻的功能。从OpenCV2.4开始,加入了新的类FaceRecognizer,该类用于人脸识别,使用它可以方便地进行相关识别实验。
原始的LBP算子定义为在3*3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于或等于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经比较可产生8位二进制数(通常转换为十进制数即LBP码,共256种),即得到该窗口中心像素点的LBP值,并用这个值来反映该区域的纹理特征.
。如下图所示:
原始的LBP提出后,研究人员不断对其提出了各种改进和优化
1.1 圆形LBP算子
基本的 LBP算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域,这显然不能满足不同尺寸和频率纹理的需要。为了适应不同尺度的纹理特征,Ojala等对LBP算子进行了改进,将3×3邻域扩展到任意邻域,并用圆形邻域代替了正方形邻域,改进后的LBP算子允许在半径为R的圆形邻域内有任意多个像素点,从而得到了诸如半径为R的圆形区域内含有P个采样点的LBP算子,OpenCV中正是使用圆形LBP算子,下图示意了圆形LBP算子:
1.2 旋转不变模式
从LBP的定义可以看出,LBP算子是灰度不变的,但却不是旋转不变的,图像的旋转就会得到不同的LBP值。Maenpaa等人又将LBP算子进行了扩展,提出了具有旋转不变性的LBP算子,即不断旋转圆形邻域得到一系列初始定义的LBP值,取其最小值作为该邻域的LBP值。下图给出了求取旋转不变LBP的过程示意图,图中算子下方的数字表示该算子对应的LBP值,图中所示的8种LBP模式,经过旋转不变的处理,最终得到的具有旋转不变性的LBP值为15。也就是说,图中的8种LBP模式对应的旋转不变的LBP码值都是00001111。
1.3 等价模式
一个LBP算子可以产生不同的二进制模式,对于半径为R的圆形区域内含有P个采样点的LBP算子将会产生P2种模式。很显然,随着邻域集内采样点数的增加,二进制模式的种类是急剧增加的。例如:5×5邻域内20个采样点,有220=1,048,576种二进制模式。如此多的二值模式无论对于纹理的提取还是对于纹理的识别、分类及信息的存取都是不利的。为了解决二进制模式过多的问题,提高统计性,Ojala提出了采用一种“等价模式”(Uniform Pattern)来对LBP算子的模式种类进行降维。Ojala等认为,在实际图像中,绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此,Ojala将“等价模式”定义为:当某个局部二进制模式所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该局部二进制模式所对应的二进制就成为一个等价模式类。如00000000(0次跳变),00000111(含一次从0到1的跳变和一次1到0的跳变),10001111(先由1跳到0,再由0跳到1,共两次跳变)都是等价模式类。除等价模式类以外的模式都归为另一类,称为混合模式类,例如10010111(共四次跳变)。
通过这样的改进,二进制模式的种类大大减少,模式数量由原来的2P种减少为P(P-1)+2+1种,其中P表示邻域集内的采样点数,等价模式类包含P(P-1)+2种模式,混合模式类只有1种模式。对于3×3邻域内8个采样点来说,二进制模式由原始的256种减少为59种,这使得特征向量的维数更少,并且可以减少高频噪声带来的影响。
2 LBP特征用于检测的原理
显而易见的是,上述提取的LBP算子在每个像素点都可以得到一个LBP“编码”,那么,对一幅图像(记录的是每个像素点的灰度值)提取其原始的LBP算子之后,得到的原始LBP特征依然是“一幅图片”(记录的是每个像素点的LBP值),如图所示:
如果将以上得到的LBP图直接用于人脸识别,其实和不提取LBP特征没什么区别,在实际的LBP应用中一般采用LBP特征谱的统计直方图作为特征向量进行分类识别,并且可以将一幅图片划分为若干的子区域,对每个子区域内的每个像素点都提取LBP特征,然后,在每个子区域内建立LBP特征的统计直方图。如此一来,每个子区域,就可以用一个统计直方图来进行描述,整个图片就由若干个统计直方图组成,这样做的好处是在一定范围内减小图像没完全对准而产生的误差,分区的另外一个意义在于我们可以根据不同的子区域给予不同的权重,比如说我们认为中心部分分区的权重大于边缘部分分区的权重,意思就是说中心部分在进行图片匹配识别时的意义更为重大。 例如:一幅100*100像素大小的图片,划分为10*10=100个子区域(可以通过多种方式来划分区域),每个子区域的大小为10*10像素;在每个子区域内的每个像素点,提取其LBP特征,然后,建立统计直方图;这样,这幅图片就有10*10个子区域,也就有了10*10个统计直方图,利用这10*10个统计直方图,就可以描述这幅图片了。之后,我们利用各种相似性度量函数,就可以判断两幅图像之间的相似性了,OpenCV在LBP人脸识别中使用的是如下相似度公式:
3 LBPH人脸识别关键部分源码
以OpenCV2.4.9为例,LBPH类源码该文件——opencv2.4.9\sources\modules\contrib\src\facerec.cpp中,如LBPH类创建函数的声明及实现如下:
FaceRecognizer
由代码可见LBPH使用圆形LBP算子,默认情况下,圆的半径是1,采样点P为8,x方向和y方向上的分区个数都为8,即有8*8=64个分区,最后一个参数为相似度阈值,待识别图像也图像库中图像相似度小于该值时才会产生匹配结果。对于LBPH类我们首先看一下其训练过程函数train:
train
由代码可见LBPH使用圆形LBP算子,默认情况下,圆的半径是1,采样点P为8,x方向和y方向上的分区个数都为8,即有8*8=64个分区,最后一个参数为相似度阈值,待识别图像也图像库中图像相似度小于该值时才会产生匹配结果。对于LBPH类我们首先看一下其训练过程函数train:
elbp和spatial_histogram
需要注意的是在求图像中每个位置的8个采样点的值时,是使用的采样点四个角上相应位置的加权平均值才作为采样点的值(见上面函数elbp_中12~35行处代码),这样做能降低噪音点对LBP值的影响。而spatial_histogram函数把最后的分区直方图结果reshape成一行,这样做能方便识别时的相似度计算。识别函数有predict函数实现,源代码如下:
predict
函数中7~15行是计算带预测图片_src的分区直方图query,19~25行的for循环分别比较query和人脸库直方图数组_histograms中每一个直方图的相似度(比较方法正是CV_COMP_CHISQR),并把相似度最小的作为最终结果,该部分也可以看成创建LBPH类时threshold的作用,即相似度都不小于threshold阈值则识别失败。
4 LBP人脸识别示例
最后给出LBP人脸识别的示例代码,代码中使用的人脸库是AT&T人脸库(又称ORL人脸数据库),库中有40个人,每人10张照片,共400张人脸照片。示例代码如下:
main
程序中用一个CSV文件指明人脸数据库文件及标签,即CSV文件中每一行包含一个文件名路径之后是其标签值,中间以分号为分隔符,可以手工创建该CSV文件,当然也可以用一个简单的Python程序来帮你实现该文件,我的python脚本程序如下:
create CSV file
程序中22行需改成你自己的人脸库路径。
示例程序的运行结果如下所示: