介绍
特征提取的共同目标是将原始数据表示为一组简化的特征,以更好地描述其主要特征和属性[1]。 这样,我们可以减少原始输入的维数,并将新功能用作训练模式识别和分类技术的输入。
尽管可以从图片中提取一些功能,但是局部二值模式(LBP)是理论上简单但有效的灰度和旋转不变纹理分类方法。 它们之所以起作用,是因为最频繁的模式对应于原始微特征,例如边缘,拐角,斑点,平坦区域[2]。
在[2]中,Ojala等人。 表明均匀图案的离散出现直方图是非常强大的纹理特征。 图像纹理定义为具有两个属性的二维现象:(1)空间结构(图案)和(2)对比度。
图1.用于测试本地二进制模式方法的图像
方法
圆对称邻居集
给定像素gc的圆对称邻居集由具有坐标(i,j)的点定义,这些点围绕半径为R的圆上的中心点,并包含多个元素P。
质地
我们将纹理T定义为灰度图像中的像素集合
其中gp对应于p个本地邻居的灰度值。
插补
当邻居不在像素中心时,应通过内插法计算该邻居灰度值。 因此,我们需要定义一个给定坐标的函数,该函数返回插值的灰度值。
实现灰度不变性
考虑到可能的信息丢失,可以将纹理变成联合差异。 为了计算它,我们将中心像素的灰度值减去所有邻居集的灰度值。 关节差异分布是高度可区分的纹理运算符。 它记录了P维直方图中每个像素附近的各种模式的发生。
其中gp是p个邻居的灰度值。 该分布对于灰度偏移是不变的。
本地二进制模式
根据定义,LBP_ {P,R}运算符对于灰度的任何单调变换都是不变的。 只要灰度值的顺序保持不变, LBP_ {P,R}运算符的输出就保持恒定。
哪里
统一的本地二进制模式
在[2]中,Ojala提到在他们的实际经验中LBP并不是很好的判别器。 他们建议仅选择一组局部二进制模式,以使空间转换的数量(按位0/1变化)不超过2。例如,模式“ 1111”具有0个空间转换,模式“ 1100”具有1个空间转换,模式“ 1101”具有2个空间转换。 对于每个统一的模式,一个唯一的索引被关联。 从这里借用了创建索引的公式。
现在,我们可以计算中心像素的局部二进制图案。 下一步是计算所有像素的局部二进制图案。
提示:为简单起见,我不考虑所选索引为负的情况(即img_gray [-1] [0]返回第一列的最后一个像素)。 如果我们想进行更准确的计算,则应考虑这种情况并加以处理。
赛顿码
先前的代码并不完美; 但是,真正变慢的是我们遍历所有图像像素。 如果考虑到我们还必须训练一种模式识别技术,那么要等待1分10秒才能计算出我们的特征很多。 因此,我们需要一个替代实现,它对于循环必须更快得多。 在这种情况下,我们将使用Cython。 该代码显示在下一张图像中,这是一大段代码。 它的某些部分可以改进,但是已经快得多了。 如果您对代码不了解,请随时发表评论。
编写代码的方式使得大多数代码完全在C API中运行。 这种策略大大加快了执行速度,但也使我们能够利用Cython的并行模块。 我们将把工作分配到CPU的多个内核上。
使用4个线程,我们可以在不到150 ms的时间内为所有像素计算局部二进制模式。 这是如此之快,以至于我什至不必费心计算多少次。
与类似图像的比较
让我们为砖块拍摄另一张图像,但是该图像将具有不同的纹理。
两种直方图都非常相似,并且它们应该是相似的,最后它们都是砖头。 尽管如此,两个图像中从20到40的特征却非常不同。 这意味着,通过良好的机器学习算法,我们可以正确地对它们进行分类。
结论
本地二进制模式是简单但有效的功能。 背后的理论并不难理解,而且易于编码。 但是,如果我们完全使用Python编写代码,则会遇到一些性能问题。 我们使用Cython解决了这个问题,并取得了令人印象深刻的结果。 下一步是收集不同的纹理图像,并训练您喜欢的机器学习算法对它们进行分类。
Jupyter笔记本
https://github.com/ocampor/notebooks/blob/master/notebooks/image/features/local-binary-patterns.ipynb
参考书目
[1] Marques,O.(2011)。 使用MATLAB进行实际的图像和视频处理。 约翰·威利父子。
[2] Ojala,T.,Pietikäinen,M.和Mäenpää,T.(2002)。 具有局部二进制模式的多分辨率灰度和旋转不变纹理分类。 IEEE Transactions on Pattern Analysis and Machine Intelligence,24(7),971–987。