图像的LBP特征

参考https://blog.csdn.net/q1007729991/article/details/52995734 和https://blog.csdn.net/qq_37577735/article/details/80041586 这两篇博文,由这两篇描述知道,要了解LBP就要先学习插值,以双线性插值为例。

插值

首先看最简单的线性插值如下:
这是最简单的线性插值,公式推导很简单,此处不再赘述
接下来就是将线性插值用在双线性插值中,如下:
已知四个相邻的红色像素,要插值得到P这个像素值,就要使用双线性插值
这个公式也很简单,不再推导
即这样推导 由这个推导的最后结果就可与下面所述f(i+u,j+v)对上,说明推导正确。可以明显看到对某个像素点的插值结果其实就是附近4个相邻像素点的加权。双线性插值的最终描述
到此,我们已明白双线性插值的意思。

圆形LBP特征

原始LBP:

接下来我们看LBP的原理,由文章开头发的链接中作者介绍可知:像素3*3的邻域内,以邻域中心像素为阈值,相邻的8个像素的灰度值与邻域中心的像素值进行比较,若周围像素大于中心像素值,则该像素点的位置被标记为1,否则为0。那么对于某个中心周围的8个邻域点,就有pow(2,8)=256种可能,取值范围就是[0,255],所以出来的LBP特征图就是一个灰度图。
原始LBP是以左上角开始顺时针组合得到最后结果
可以由上图看到此时采样点组成了一个正方形,我觉得原始LBP可以叫做正方形LBP,自然此时不用插值。如作者给的opencv代码所述,就是从左上角顺时针一圈的结果:

//原始LBP特征计算
template <typename _tp>
void getOriginLBPFeature(InputArray _src,OutputArray _dst)
{
    Mat src = _src.getMat();
    _dst.create(src.rows-2,src.cols-2,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);
    for(int i=1;i<src.rows-1;i++)
    {
        for(int j=1;j<src.cols-1;j++)
        {
            _tp center = src.at<_tp>(i,j);
            unsigned char lbpCode = 0;
            lbpCode |= (src.at<_tp>(i-1,j-1) > center) << 7;
            lbpCode |= (src.at<_tp>(i-1,j  ) > center) << 6;
            lbpCode |= (src.at<_tp>(i-1,j+1) > center) << 5;
            lbpCode |= (src.at<_tp>(i  ,j+1) > center) << 4;
            lbpCode |= (src.at<_tp>(i+1,j+1) > center) << 3;
            lbpCode |= (src.at<_tp>(i+1,j  ) > center) << 2;
            lbpCode |= (src.at<_tp>(i+1,j-1) > center) << 1;
            lbpCode |= (src.at<_tp>(i  ,j-1) > center) << 0;
            dst.at<uchar>(i-1,j-1) = lbpCode;
        }
    }
}

可以看到左上角的那个点放在最高位上,顺时针以此类推。这个原始LBP很好理解,不用赘述。

圆形LBP:

作者后面说的圆形LBP中说了两个词:半径radius和采样点neighbors:
半径与采样点
可以看到上图的LBP的右上角值就是radius,右下角值就是neighbors。可以看到不一定要求neighbors=8*radius,而是**<=**即可,因为以radius为半径的周长就是当前半径下最大采样点数。以radius=1,neighbors=8为例:根据作者提供的代码:

template <typename _tp>
void getCircularLBPFeature(InputArray _src,OutputArray _dst,int radius,int neighbors)
{
    Mat src = _src.getMat();
    //LBP特征图像的行数和列数的计算要准确
    _dst.create(src.rows-2*radius,src.cols-2*radius,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);
    //循环处理每个像素
    for(int i=radius;i<src.rows-radius;i++)
    {
        for(int j=radius;j<src.cols-radius;j++)
        {
            //获得中心像素点的灰度值
            _tp center = src.at<_tp>(i,j);
            unsigned char lbpCode = 0;
            for(int k=0;k<neighbors;k++)
            {
                //根据公式计算第k个采样点的坐标,这个地方可以优化,不必每次都进行计算radius*cos,radius*sin
                float x = i + static_cast<float>(radius * \
                    cos(2.0 * CV_PI * k / neighbors));
                float y = j - static_cast<float>(radius * \
                    sin(2.0 * CV_PI * k / neighbors));
                //根据取整结果进行双线性插值,得到第k个采样点的灰度值

                //1.分别对x,y进行上下取整
                int x1 = static_cast<int>(floor(x));
                int x2 = static_cast<int>(ceil(x));
                int y1 = static_cast<int>(floor(y));
                int y2 = static_cast<int>(ceil(y));

                //2.计算四个点(x1,y1),(x1,y2),(x2,y1),(x2,y2)的权重
                //将坐标映射到0-1之间
                float tx = x - x1;
                float ty = y - y1;
                //根据0-1之间的x,y的权重计算公式计算权重
                float w1 = (1-tx) * (1-ty);
                float w2 =    tx  * (1-ty);
                float w3 = (1-tx) *    ty;
                float w4 =    tx  *    ty;
                //3.根据双线性插值公式计算第k个采样点的灰度值
                float neighbor = src.at<_tp>(x1,y1) * w1 + src.at<_tp>(x1,y2) *w2 \
                    + src.at<_tp>(x2,y1) * w3 +src.at<_tp>(x2,y2) *w4;
                //通过比较获得LBP值,并按顺序排列起来
                lbpCode |= (neighbor>center) <<(neighbors-k-1);
            }
            dst.at<uchar>(i-radius,j-radius) = lbpCode;
        }
    }
}

可以看到使用了双线性插值,因为不再像原始LBP那样使用正方形,这里是圆形就必须插值,如下图所示0、2、4、6位置是插值所得:原始LBP是正方形采样点,圆形LBP的采样点是圆形
由上图还可以看到,原始LBP与圆形LBP的二进制放的起始位置变了,比如最高位原始LBP在左上角,但圆形LBP最高位在正下方。但没关系,8个采样点组成了圆形所以是符合原理的。
突然看到https://blog.csdn.net/xhdmtx_hcf/article/details/80060963 这里也介绍了圆形LBP,但这个作者给的elbp_函数中,却不对,以中心点(1,1)为例,radius=1,neighbors=8:

from function elbp_():
1,1 bitpos:0  biliear:2,1 - 2,1 - 2,1 - 2,1
1,1 bitpos:1  biliear:1,0 - 2,0 - 1,1 - 2,1
1,1 bitpos:2  biliear:1,0 - 2,0 - 1,0 - 2,0
1,1 bitpos:3  biliear:0,0 - 1,0 - 0,1 - 1,1
1,1 bitpos:4  biliear:0,0 - 0,0 - 0,1 - 0,1
1,1 bitpos:5  biliear:0,1 - 1,1 - 0,2 - 1,2
1,1 bitpos:6  biliear:0,2 - 1,2 - 0,2 - 1,2
1,1 bitpos:7  biliear:1,1 - 2,1 - 1,2 - 2,2

from function getCircularLBPFeature():
1,1 bitpos:7  biliear:1,2 - 1,2 - 1,2 - 1,2
1,1 bitpos:6  biliear:0,1 - 1,1 - 0,2 - 1,2
1,1 bitpos:5  biliear:0,1 - 0,1 - 0,1 - 0,1
1,1 bitpos:4  biliear:0,0 - 1,0 - 0,1 - 1,1
1,1 bitpos:3  biliear:1,0 - 1,0 - 1,0 - 1,0
1,1 bitpos:2  biliear:1,0 - 2,0 - 1,1 - 2,1
1,1 bitpos:1  biliear:2,1 - 2,1 - 2,1 - 2,1
1,1 bitpos:0  biliear:1,1 - 2,1 - 1,2 - 2,2

为什么elbp_函数中二进制位2的时候,怎么是由(1,0)、(2,0)这两个点插值的结果作为bitpos2的结果呢?!明显不对啊,然后这几个点画出来也不是圆形。再看getCircularLBPFeature()中二进制位2上的结果是由(1,0)、(2,0)、(1,1)、(2,1)插值得到的,就是符合我上面画的“圆形LBP”的图,的确组合成了圆形。(更新:不好意思 这个elbp_函数是我大意了,是没问题的,毕竟opencv的源码可信度还是高的,原因如下,我之前没有看权重,输出权重后可以看到基本是一个圆形)
在这里插入图片描述所以可opencv的函数elbp_是可以使用的:

template <typename _Tp> static
inline void elbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) {
    //get matrices
    Mat src = _src.getMat();
    // allocate memory for result
    _dst.create(src.rows-2*radius, src.cols-2*radius, CV_32SC1);
    Mat dst = _dst.getMat();
    // zero
    dst.setTo(0);
    for(int n=0; n<neighbors; n++) {
        // sample points
        float x = static_cast<float>(radius * cos(2.0*CV_PI*n/static_cast<float>(neighbors)));
        float y = static_cast<float>(-radius * sin(2.0*CV_PI*n/static_cast<float>(neighbors)));
        // relative indices
        int fx = static_cast<int>(floor(x));
        int fy = static_cast<int>(floor(y));
        int cx = static_cast<int>(ceil(x));
        int cy = static_cast<int>(ceil(y));
        // fractional part
        float ty = y - fy;
        float tx = x - fx;
        // set interpolation weights
        float w1 = (1 - tx) * (1 - ty);
        float w2 =      tx  * (1 - ty);
        float w3 = (1 - tx) *      ty;
        float w4 =      tx  *      ty;
        // iterate through your data
        for(int i=radius; i < src.rows-radius;i++) {
            for(int j=radius;j < src.cols-radius;j++) {
                // calculate interpolated value
                float t = static_cast<float>(w1*src.at<_Tp>(i+fy,j+fx) + w2*src.at<_Tp>(i+fy,j+cx) + w3*src.at<_Tp>(i+cy,j+fx) + w4*src.at<_Tp>(i+cy,j+cx));
                // floating point precision, so check some machine-dependent epsilon
                dst.at<int>(i-radius,j-radius) += ((t > src.at<_Tp>(i,j)) || (std::abs(t-src.at<_Tp>(i,j)) < std::numeric_limits<float>::epsilon())) << n;
            }
        }
    }
}

等价LBP

参考https://blog.csdn.net/zfjBIT/article/details/90638844 这个博文讲述很详细,等价LBP其实是对上面的原理得到的结果进行降维,比如上面radius=1,neighbors=8时总共有256种情况,即取值范围是[0,255]。等价LBP即uniform LBP则是统计一串二进制数从0到1或从1到0的跳变次数times,如00000000(0次跳变),00000111(只含一次从0到1的跳变,参考的这个博文作者这里笔误写错了,因为这是没考虑首尾所以只有1次跳变。而实际应该是2次跳变,因为考虑首尾后还有1次 0到1的跳变,所以总共这里有2次跳变),10001111(先由1跳到0,再由0跳到1,共两次跳变)。如果times<3,则是等价模式,否则则是混合模式(混合模式则直接赋值为0即可)。依据这个原理,对于采样点P或者说neighbors,LBP的情况直接从2^P种减少为 (等价模式:(P ( P-1)+2)+ 混合模式:1)种,实现了降维。如P=8时,原来的LBP总共有256种情况,现在则只有58+1种情况了。
下图以P=3和4分别画了等价模式的图(一定要考虑首尾),很好理解。同时也证明了P(P-1)+2的正确性。
在这里插入图片描述
编程出来就是,运行如下图p=3时跳变0次的有2种,跳变1次的0种,跳变2次的有6种,故总共8=p(p-1)+2种,符合规律:
在这里插入图片描述再试下p=4时如下图所示,跳变0次的2种,跳变1次的0种,跳变2次的是12种,总共14=p(p-1)+2种,符合规律。count=4是混合模式,不纳入计算范围内:
在这里插入图片描述
以此类推到p=8,如下图,可以看到等价模式有2+0+56=58=p(p-1)+2,也符合规律:
在这里插入图片描述大家可以看到对于p=8有跳变次数为8次的情况,出现2次,就是下面这两个数:
在这里插入图片描述
在这里插入图片描述利用我之前画的图,考虑首尾,大家很容易知道这两个数的确跳变次数都为8。
刚刚参考的这篇博文中作者给了一个函数,可是getUniformPatternLBPFeature(srcimg, dst,1,8)求出来:

template <typename _tp>
void getUniformPatternLBPFeature(cv::Mat src, cv::Mat &dst, int radius, int neighbors)
{
 
	//LBP特征图像的行数和列数的计算要准确
	dst = cv::Mat::zeros(src.rows - 2 * radius, src.cols - 2 * radius, CV_8UC1);
 
	//LBP特征值对应图像灰度编码表,直接默认采样点为8位
	uchar temp = 1;
	uchar table[256] = { 0 };
	for (int i = 0; i<256; i++)
	{
		if (getHopTimes(i)<3)
		{
			table[i] = temp;
			temp++;
		}
	}
	//是否进行UniformPattern编码的标志
	bool flag = false;
	//计算LBP特征图
	for (int k = 0; k<neighbors; k++)
	{
		if (k == neighbors - 1)
		{
			flag = true;
		}
		//计算采样点对于中心点坐标的偏移量rx,ry
		float rx = static_cast<float>(radius * cos(2.0 * CV_PI * k / neighbors));
		float ry = -static_cast<float>(radius * sin(2.0 * CV_PI * k / neighbors));
		//为双线性插值做准备
		//对采样点偏移量分别进行上下取整
		int x1 = static_cast<int>(floor(rx));
		int x2 = static_cast<int>(ceil(rx));
		int y1 = static_cast<int>(floor(ry));
		int y2 = static_cast<int>(ceil(ry));
		//将坐标偏移量映射到0-1之间
		float tx = rx - x1;
		float ty = ry - y1;
		//根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关
		float w1 = (1 - tx) * (1 - ty);
		float w2 = tx  * (1 - ty);
		float w3 = (1 - tx) *    ty;
		float w4 = tx  *    ty;
		//循环处理每个像素
		for (int i = radius; i<src.rows - radius; i++)
		{
			for (int j = radius; j<src.cols - radius; j++)
			{
				//获得中心像素点的灰度值
				_tp center = src.at<_tp>(i, j);
				//根据双线性插值公式计算第k个采样点的灰度值
				float neighbor = src.at<_tp>(i + x1, j + y1) * w1 + src.at<_tp>(i + x1, j + y2) *w2 \
					+ src.at<_tp>(i + x2, j + y1) * w3 + src.at<_tp>(i + x2, j + y2) *w4;
				//LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得
				dst.at<uchar>(i - radius, j - radius) |= (neighbor>center) << (neighbors - k - 1);
				//进行LBP特征的UniformPattern编码
				if (flag)
				{
					dst.at<uchar>(i - radius, j - radius) = table[dst.at<uchar>(i - radius, j - radius)];
				}
			}
		}
	}
}
//计算跳变次数
int getHopTimes(int n)
{
	int count = 0;
	bitset<8> binaryCode = n;//头文件#include<bitset>
	for (int i = 0; i<8; i++)
	{
		if (binaryCode[i] != binaryCode[(i + 1) % 8])
		{
			count++;
		}
	}
	return count;
}

//from https://blog.csdn.net/zfjBIT/article/details/90638844

以中心点(1,1)为例:

from function getUniformPatternLBPFeature(srcimg, dst,1,8):
1,1 bitpos:7  biliear:1,2 - 1,2 - 1,2 - 1,2
1,1 bitpos:6  biliear:0,1 - 1,1 - 0,2 - 1,2
1,1 bitpos:5  biliear:0,1 - 0,1 - 0,2 - 0,2
1,1 bitpos:4  biliear:0,0 - 1,0 - 0,1 - 1,1
1,1 bitpos:3  biliear:0,0 - 1,0 - 0,0 - 1,0
1,1 bitpos:2  biliear:1,0 - 2,0 - 1,1 - 2,1
1,1 bitpos:1  biliear:2,0 - 2,0 - 2,1 - 2,1
1,1 bitpos:0  biliear:1,1 - 2,1 - 1,2 - 2,2

在这里插入图片描述
以中心点(1,1)为例,取的就是上图这8个采样点,这不对吧?怎么是这个形状?!(更新:其实上图是因为没考虑权重,考虑权重后是正确的,是圆形。)大家重新看之前getCircularLBPFeature()中就是8个采样点组成一个圆形,我觉得那才是正确的。所以将作者这个函数改成下面这样:

//by wd
void changeUniformLBPFeature(InputArray _src,OutputArray _dst,int radius,int neighbors)
{
    Mat src = _src.getMat();
    //LBP特征图像的行数和列数的计算要准确
    _dst.create(src.rows-2*radius,src.cols-2*radius,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);

    //LBP特征值对应图像灰度编码表,直接默认采样点为8位
	uchar temp = 1;
	uchar table[256] = { 0 };
	for (int i = 0; i<256; i++)
	{
		if (getHop_Times(i,neighbors)<3)
		{
			table[i] = temp;
			temp++;
		}
	}

    //循环处理每个像素
    for(int i=radius;i<src.rows-radius;i++)
    {
        for(int j=radius;j<src.cols-radius;j++)
        {
            //获得中心像素点的灰度值
        	ushort center = src.at<ushort>(i,j);
            unsigned char lbpCode = 0;
            for(int k=0;k<neighbors;k++)
            {
                //根据公式计算第k个采样点的坐标,这个地方可以优化,不必每次都进行计算radius*cos,radius*sin
                float x = i + static_cast<float>(radius * \
                    cos(2.0 * CV_PI * k / neighbors));
                float y = j - static_cast<float>(radius * \
                    sin(2.0 * CV_PI * k / neighbors));
                //根据取整结果进行双线性插值,得到第k个采样点的灰度值

                //1.分别对x,y进行上下取整
                int x1 = static_cast<int>(floor(x));
                int x2 = static_cast<int>(ceil(x));
                int y1 = static_cast<int>(floor(y));
                int y2 = static_cast<int>(ceil(y));

                //2.计算四个点(x1,y1),(x1,y2),(x2,y1),(x2,y2)的权重
                //将坐标映射到0-1之间
                float tx = x - x1;
                float ty = y - y1;
                //根据0-1之间的x,y的权重计算公式计算权重
                float w1 = (1-tx) * (1-ty);
                float w2 =    tx  * (1-ty);
                float w3 = (1-tx) *    ty;
                float w4 =    tx  *    ty;
                //3.根据双线性插值公式计算第k个采样点的灰度值
                float neighbor = src.at<ushort>(x1,y1) * w1 + src.at<ushort>(x1,y2) *w2 \
                    + src.at<ushort>(x2,y1) * w3 +src.at<ushort>(x2,y2) *w4;
                //通过比较获得LBP值,并按顺序排列起来
                if(i==radius && j==radius)
                {
                	cout<<j<<","<<i<<" bitpos:"<<neighbors-k-1<<"  biliear:"<<y1<<","<<x1<<" - "<<y2<<","<<x1<<" - "<<y1<<","<<x2<<" - "<<y2<<","<<x2<<endl;
                }
                lbpCode |= (neighbor>center) <<(neighbors-k-1);
            }
            //此像素为中心周围neighbors个采样点序列计算完毕后 取出对应编码为最终结果
            dst.at<uchar>(i-radius,j-radius) = table[lbpCode];
        }
    }

    double minvalue,maxvalue;
    cv::minMaxLoc(dst,&minvalue,&maxvalue);
    cout<<"uniform LBP data,during: "<<minvalue<<"~"<<maxvalue<<endl;
}

在这里插入图片描述
看这个结果、这些插值后形成的8个采样点才符合圆形,也表达了uniform LBP是基于圆形LBP的结果进行降维。

旋转不变性等价LBP

在python中的计算uniform LBP的函数为:

getlbp=skimage.feature.local_binary_pattern(图像,采样点数neighbors,半径radius,模式'uniform')

在这里插入图片描述
这个就是python中求LBP的函数,可以看到当选择uniform时,是具有灰度不变性和旋转不变性的。而我们上面写的那个uniform LBP还不具备旋转不变性,所以现在就是要在之前写的“等价LBP”的基础上增加“旋转不变性”。而我看到https://blog.csdn.net/q1007729991/article/details/52995734 这个作者提供的getRotationInvariantLBPFeature函数中是直接对基本LBP的结果图的数值循环左移来达到旋转不变性的目的。但是他这样处理只是出来的LBP数值种类/情况变少了由p(p-1)+2减少到p+1,但取值范围仍旧是[0,255]不变!!!而这与python这个函数出来的结果图数值取值范围只有0~9不符合,说明不能像这个作者一样处理。结合我之前画的图,经过推理可知,旋转不变性应该像下面这样增加才能实现数值种类/情况变少(下图所示)的同时 取值范围也减少(下下图):
在这里插入图片描述
由上图可知P=3时,旋转不变性后,等价模式的取值种类从p(p-1)+2变成了p+1,P=4时的证明大家也可这样画出来。易证明,跳变0次的一定有2种,这两种旋转后仍旧是times0=2种!而上图跳变2次的有6种,旋转后种类有2种。所以此时P=3时旋转不变性后种类为4=P+1。所以如果P=8,那么旋转不变性的uniform LBP应该取值范围是0~8+1(这里的0是混合模式都取值为0)!大家可以去看python下的这个函数就是如此。编程时为了方便,我们可根据原理先将下图(此时不是种类,而是将LBP数值范围降到了p+1,注意我说的取值情况/种类与取值范围的区别)画出(可以看到data中取值范围已经从[1,8]变到[1,4]):
在这里插入图片描述
由上图可以看到p=3时,id是序号或者说是下标或者说是二进制转十进制后的数值,times是二进制数的跳变次数,data就是最后的LBP数值。可以从上图看到等价LBP加入旋转不变性后范围如何从[1,8]变成[1,4]。下面我们根据上图的原理编程后输出p=3时id经过旋转不变性后由0~7即8个值变成了0、1、3、7共4个值(与我上面画的图中一致),符合p+1规律:
在这里插入图片描述
我们将代码p改成4试试,如下图可知由原来的0~15(排除红色线所示的2种混合模式后)共14种,旋转不变性后变成了0、1、3、7、15共5种,符合p+1规律。大家可类推到p=8,道理相同:
在这里插入图片描述全部编写完毕后,输出如下,可以看到加入旋转不变性后,输出的LBP特征图取值范围由[0,58]变成了[0,9]。:
在这里插入图片描述写成更通用一点的函数,因为上面的changewithRotateUniformLBPFeature没有适用于不同类型的原图以及更大的采样点,因为采样点不一定是8啊,还可能是9、10、11等等更大的数。所以应该改成更通用的版本如下:
在这里插入图片描述看p=3时与我上面推理的是一样的,LBP的数值已经从[1,8]变成了[1,4],再看p=4时如下:
在这里插入图片描述从[1,14]变成了[1,5],继续看p=8、p=10时均与之前所述相符:

radius=3 , P=8
primer uniform LBP table:
0:1 1:2 2:3 3:4 4:5 5:0 6:6 7:7 8:8 9:0 10:0 11:0 12:9 13:0 14:10 15:11 16:12 17:0 18:0 19:0 20:0 21:0 22:0 23:0 24:13 25:0 26:0 27:0 28:14 29:0 30:15 31:16 32:17 33:0 34:0 35:0 36:0 37:0 38:0 39:0 40:0 41:0 42:0 43:0 44:0 45:0 46:0 47:0 48:18 49:0 50:0 51:0 52:0 53:0 54:0 55:0 56:19 57:0 58:0 59:0 60:20 61:0 62:21 63:22 64:23 65:0 66:0 67:0 68:0 69:0 70:0 71:0 72:0 73:0 74:0 75:0 76:0 77:0 78:0 79:0 80:0 81:0 82:0 83:0 84:0 85:0 86:0 87:0 88:0 89:0 90:0 91:0 92:0 93:0 94:0 95:0 96:24 97:0 98:0 99:0 100:0 101:0 102:0 103:0 104:0 105:0 106:0 107:0 108:0 109:0 110:0 111:0 112:25 113:0 114:0 115:0 116:0 117:0 118:0 119:0 120:26 121:0 122:0 123:0 124:27 125:0 126:28 127:29 128:30 129:31 130:0 131:32 132:0 133:0 134:0 135:33 136:0 137:0 138:0 139:0 140:0 141:0 142:0 143:34 144:0 145:0 146:0 147:0 148:0 149:0 150:0 151:0 152:0 153:0 154:0 155:0 156:0 157:0 158:0 159:35 160:0 161:0 162:0 163:0 164:0 165:0 166:0 167:0 168:0 169:0 170:0 171:0 172:0 173:0 174:0 175:0 176:0 177:0 178:0 179:0 180:0 181:0 182:0 183:0 184:0 185:0 186:0 187:0 188:0 189:0 190:0 191:36 192:37 193:38 194:0 195:39 196:0 197:0 198:0 199:40 200:0 201:0 202:0 203:0 204:0 205:0 206:0 207:41 208:0 209:0 210:0 211:0 212:0 213:0 214:0 215:0 216:0 217:0 218:0 219:0 220:0 221:0 222:0 223:42 224:43 225:44 226:0 227:45 228:0 229:0 230:0 231:46 232:0 233:0 234:0 235:0 236:0 237:0 238:0 239:47 240:48 241:49 242:0 243:50 244:0 245:0 246:0 247:51 248:52 249:53 250:0 251:54 252:55 253:56 254:57 255:58 
new uniform LBP table after rotation:
0:1 1:2 2:0 3:3 4:0 5:0 6:0 7:4 8:0 9:0 10:0 11:0 12:0 13:0 14:0 15:5 16:0 17:0 18:0 19:0 20:0 21:0 22:0 23:0 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:6 32:0 33:0 34:0 35:0 36:0 37:0 38:0 39:0 40:0 41:0 42:0 43:0 44:0 45:0 46:0 47:0 48:0 49:0 50:0 51:0 52:0 53:0 54:0 55:0 56:0 57:0 58:0 59:0 60:0 61:0 62:0 63:7 64:0 65:0 66:0 67:0 68:0 69:0 70:0 71:0 72:0 73:0 74:0 75:0 76:0 77:0 78:0 79:0 80:0 81:0 82:0 83:0 84:0 85:0 86:0 87:0 88:0 89:0 90:0 91:0 92:0 93:0 94:0 95:0 96:0 97:0 98:0 99:0 100:0 101:0 102:0 103:0 104:0 105:0 106:0 107:0 108:0 109:0 110:0 111:0 112:0 113:0 114:0 115:0 116:0 117:0 118:0 119:0 120:0 121:0 122:0 123:0 124:0 125:0 126:0 127:8 128:0 129:0 130:0 131:0 132:0 133:0 134:0 135:0 136:0 137:0 138:0 139:0 140:0 141:0 142:0 143:0 144:0 145:0 146:0 147:0 148:0 149:0 150:0 151:0 152:0 153:0 154:0 155:0 156:0 157:0 158:0 159:0 160:0 161:0 162:0 163:0 164:0 165:0 166:0 167:0 168:0 169:0 170:0 171:0 172:0 173:0 174:0 175:0 176:0 177:0 178:0 179:0 180:0 181:0 182:0 183:0 184:0 185:0 186:0 187:0 188:0 189:0 190:0 191:0 192:0 193:0 194:0 195:0 196:0 197:0 198:0 199:0 200:0 201:0 202:0 203:0 204:0 205:0 206:0 207:0 208:0 209:0 210:0 211:0 212:0 213:0 214:0 215:0 216:0 217:0 218:0 219:0 220:0 221:0 222:0 223:0 224:0 225:0 226:0 227:0 228:0 229:0 230:0 231:0 232:0 233:0 234:0 235:0 236:0 237:0 238:0 239:0 240:0 241:0 242:0 243:0 244:0 245:0 246:0 247:0 248:0 249:0 250:0 251:0 252:0 253:0 254:0 255:9 

radius=2 , P=10
primer uniform LBP table:
0:1 1:2 2:3 3:4 4:5 5:0 6:6 7:7 8:8 9:0 10:0 11:0 12:9 13:0 14:10 15:11 16:12 17:0 18:0 19:0 20:0 21:0 22:0 23:0 24:13 25:0 26:0 27:0 28:14 29:0 30:15 31:16 32:17 33:0 34:0 35:0 36:0 37:0 38:0 39:0 40:0 41:0 42:0 43:0 44:0 45:0 46:0 47:0 48:18 49:0 50:0 51:0 52:0 53:0 54:0 55:0 56:19 57:0 58:0 59:0 60:20 61:0 62:21 63:22 64:23 65:0 66:0 67:0 68:0 69:0 70:0 71:0 72:0 73:0 74:0 75:0 76:0 77:0 78:0 79:0 80:0 81:0 82:0 83:0 84:0 85:0 86:0 87:0 88:0 89:0 90:0 91:0 92:0 93:0 94:0 95:0 96:24 97:0 98:0 99:0 100:0 101:0 102:0 103:0 104:0 105:0 106:0 107:0 108:0 109:0 110:0 111:0 112:25 113:0 114:0 115:0 116:0 117:0 118:0 119:0 120:26 121:0 122:0 123:0 124:27 125:0 126:28 127:29 128:30 129:0 130:0 131:0 132:0 133:0 134:0 135:0 136:0 137:0 138:0 139:0 140:0 141:0 142:0 143:0 144:0 145:0 146:0 147:0 148:0 149:0 150:0 151:0 152:0 153:0 154:0 155:0 156:0 157:0 158:0 159:0 160:0 161:0 162:0 163:0 164:0 165:0 166:0 167:0 168:0 169:0 170:0 171:0 172:0 173:0 174:0 175:0 176:0 177:0 178:0 179:0 180:0 181:0 182:0 183:0 184:0 185:0 186:0 187:0 188:0 189:0 190:0 191:0 192:31 193:0 194:0 195:0 196:0 197:0 198:0 199:0 200:0 201:0 202:0 203:0 204:0 205:0 206:0 207:0 208:0 209:0 210:0 211:0 212:0 213:0 214:0 215:0 216:0 217:0 218:0 219:0 220:0 221:0 222:0 223:0 224:32 225:0 226:0 227:0 228:0 229:0 230:0 231:0 232:0 233:0 234:0 235:0 236:0 237:0 238:0 239:0 240:33 241:0 242:0 243:0 244:0 245:0 246:0 247:0 248:34 249:0 250:0 251:0 252:35 253:0 254:36 255:37 256:38 257:0 258:0 259:0 260:0 261:0 262:0 263:0 264:0 265:0 266:0 267:0 268:0 269:0 270:0 271:0 272:0 273:0 274:0 275:0 276:0 277:0 278:0 279:0 280:0 281:0 282:0 283:0 284:0 285:0 286:0 287:0 288:0 289:0 290:0 291:0 292:0 293:0 294:0 295:0 296:0 297:0 298:0 299:0 300:0 301:0 302:0 303:0 304:0 305:0 306:0 307:0 308:0 309:0 310:0 311:0 312:0 313:0 314:0 315:0 316:0 317:0 318:0 319:0 320:0 321:0 322:0 323:0 324:0 325:0 326:0 327:0 328:0 329:0 330:0 331:0 332:0 333:0 334:0 335:0 336:0 337:0 338:0 339:0 340:0 341:0 342:0 343:0 344:0 345:0 346:0 347:0 348:0 349:0 350:0 351:0 352:0 353:0 354:0 355:0 356:0 357:0 358:0 359:0 360:0 361:0 362:0 363:0 364:0 365:0 366:0 367:0 368:0 369:0 370:0 371:0 372:0 373:0 374:0 375:0 376:0 377:0 378:0 379:0 380:0 381:0 382:0 383:0 384:39 385:0 386:0 387:0 388:0 389:0 390:0 391:0 392:0 393:0 394:0 395:0 396:0 397:0 398:0 399:0 400:0 401:0 402:0 403:0 404:0 405:0 406:0 407:0 408:0 409:0 410:0 411:0 412:0 413:0 414:0 415:0 416:0 417:0 418:0 419:0 420:0 421:0 422:0 423:0 424:0 425:0 426:0 427:0 428:0 429:0 430:0 431:0 432:0 433:0 434:0 435:0 436:0 437:0 438:0 439:0 440:0 441:0 442:0 443:0 444:0 445:0 446:0 447:0 448:40 449:0 450:0 451:0 452:0 453:0 454:0 455:0 456:0 457:0 458:0 459:0 460:0 461:0 462:0 463:0 464:0 465:0 466:0 467:0 468:0 469:0 470:0 471:0 472:0 473:0 474:0 475:0 476:0 477:0 478:0 479:0 480:41 481:0 482:0 483:0 484:0 485:0 486:0 487:0 488:0 489:0 490:0 491:0 492:0 493:0 494:0 495:0 496:42 497:0 498:0 499:0 500:0 501:0 502:0 503:0 504:43 505:0 506:0 507:0 508:44 509:0 510:45 511:46 512:47 513:48 514:0 515:49 516:0 517:0 518:0 519:50 520:0 521:0 522:0 523:0 524:0 525:0 526:0 527:51 528:0 529:0 530:0 531:0 532:0 533:0 534:0 535:0 536:0 537:0 538:0 539:0 540:0 541:0 542:0 543:52 544:0 545:0 546:0 547:0 548:0 549:0 550:0 551:0 552:0 553:0 554:0 555:0 556:0 557:0 558:0 559:0 560:0 561:0 562:0 563:0 564:0 565:0 566:0 567:0 568:0 569:0 570:0 571:0 572:0 573:0 574:0 575:53 576:0 577:0 578:0 579:0 580:0 581:0 582:0 583:0 584:0 585:0 586:0 587:0 588:0 589:0 590:0 591:0 592:0 593:0 594:0 595:0 596:0 597:0 598:0 599:0 600:0 601:0 602:0 603:0 604:0 605:0 606:0 607:0 608:0 609:0 610:0 611:0 612:0 613:0 614:0 615:0 616:0 617:0 618:0 619:0 620:0 621:0 622:0 623:0 624:0 625:0 626:0 627:0 628:0 629:0 630:0 631:0 632:0 633:0 634:0 635:0 636:0 637:0 638:0 639:54 640:0 641:0 642:0 643:0 644:0 645:0 646:0 647:0 648:0 649:0 650:0 651:0 652:0 653:0 654:0 655:0 656:0 657:0 658:0 659:0 660:0 661:0 662:0 663:0 664:0 665:0 666:0 667:0 668:0 669:0 670:0 671:0 672:0 673:0 674:0 675:0 676:0 677:0 678:0 679:0 680:0 681:0 682:0 683:0 684:0 685:0 686:0 687:0 688:0 689:0 690:0 691:0 692:0 693:0 694:0 695:0 696:0 697:0 698:0 699:0 700:0 701:0 702:0 703:0 704:0 705:0 706:0 707:0 708:0 709:0 710:0 711:0 712:0 713:0 714:0 715:0 716:0 717:0 718:0 719:0 720:0 721:0 722:0 723:0 724:0 725:0 726:0 727:0 728:0 729:0 730:0 731:0 732:0 733:0 734:0 735:0 736:0 737:0 738:0 739:0 740:0 741:0 742:0 743:0 744:0 745:0 746:0 747:0 748:0 749:0 750:0 751:0 752:0 753:0 754:0 755:0 756:0 757:0 758:0 759:0 760:0 761:0 762:0 763:0 764:0 765:0 766:0 767:55 768:56 769:57 770:0 771:58 772:0 773:0 774:0 775:59 776:0 777:0 778:0 779:0 780:0 781:0 782:0 783:60 784:0 785:0 786:0 787:0 788:0 789:0 790:0 791:0 792:0 793:0 794:0 795:0 796:0 797:0 798:0 799:61 800:0 801:0 802:0 803:0 804:0 805:0 806:0 807:0 808:0 809:0 810:0 811:0 812:0 813:0 814:0 815:0 816:0 817:0 818:0 819:0 820:0 821:0 822:0 823:0 824:0 825:0 826:0 827:0 828:0 829:0 830:0 831:62 832:0 833:0 834:0 835:0 836:0 837:0 838:0 839:0 840:0 841:0 842:0 843:0 844:0 845:0 846:0 847:0 848:0 849:0 850:0 851:0 852:0 853:0 854:0 855:0 856:0 857:0 858:0 859:0 860:0 861:0 862:0 863:0 864:0 865:0 866:0 867:0 868:0 869:0 870:0 871:0 872:0 873:0 874:0 875:0 876:0 877:0 878:0 879:0 880:0 881:0 882:0 883:0 884:0 885:0 886:0 887:0 888:0 889:0 890:0 891:0 892:0 893:0 894:0 895:63 896:64 897:65 898:0 899:66 900:0 901:0 902:0 903:67 904:0 905:0 906:0 907:0 908:0 909:0 910:0 911:68 912:0 913:0 914:0 915:0 916:0 917:0 918:0 919:0 920:0 921:0 922:0 923:0 924:0 925:0 926:0 927:69 928:0 929:0 930:0 931:0 932:0 933:0 934:0 935:0 936:0 937:0 938:0 939:0 940:0 941:0 942:0 943:0 944:0 945:0 946:0 947:0 948:0 949:0 950:0 951:0 952:0 953:0 954:0 955:0 956:0 957:0 958:0 959:70 960:71 961:72 962:0 963:73 964:0 965:0 966:0 967:74 968:0 969:0 970:0 971:0 972:0 973:0 974:0 975:75 976:0 977:0 978:0 979:0 980:0 981:0 982:0 983:0 984:0 985:0 986:0 987:0 988:0 989:0 990:0 991:76 992:77 993:78 994:0 995:79 996:0 997:0 998:0 999:80 1000:0 1001:0 1002:0 1003:0 1004:0 1005:0 1006:0 1007:81 1008:82 1009:83 1010:0 1011:84 1012:0 1013:0 1014:0 1015:85 1016:86 1017:87 1018:0 1019:88 1020:89 1021:90 1022:91 1023:92 
new uniform LBP table after rotation:
0:1 1:2 2:0 3:3 4:0 5:0 6:0 7:4 8:0 9:0 10:0 11:0 12:0 13:0 14:0 15:5 16:0 17:0 18:0 19:0 20:0 21:0 22:0 23:0 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:6 32:0 33:0 34:0 35:0 36:0 37:0 38:0 39:0 40:0 41:0 42:0 43:0 44:0 45:0 46:0 47:0 48:0 49:0 50:0 51:0 52:0 53:0 54:0 55:0 56:0 57:0 58:0 59:0 60:0 61:0 62:0 63:7 64:0 65:0 66:0 67:0 68:0 69:0 70:0 71:0 72:0 73:0 74:0 75:0 76:0 77:0 78:0 79:0 80:0 81:0 82:0 83:0 84:0 85:0 86:0 87:0 88:0 89:0 90:0 91:0 92:0 93:0 94:0 95:0 96:0 97:0 98:0 99:0 100:0 101:0 102:0 103:0 104:0 105:0 106:0 107:0 108:0 109:0 110:0 111:0 112:0 113:0 114:0 115:0 116:0 117:0 118:0 119:0 120:0 121:0 122:0 123:0 124:0 125:0 126:0 127:8 128:0 129:0 130:0 131:0 132:0 133:0 134:0 135:0 136:0 137:0 138:0 139:0 140:0 141:0 142:0 143:0 144:0 145:0 146:0 147:0 148:0 149:0 150:0 151:0 152:0 153:0 154:0 155:0 156:0 157:0 158:0 159:0 160:0 161:0 162:0 163:0 164:0 165:0 166:0 167:0 168:0 169:0 170:0 171:0 172:0 173:0 174:0 175:0 176:0 177:0 178:0 179:0 180:0 181:0 182:0 183:0 184:0 185:0 186:0 187:0 188:0 189:0 190:0 191:0 192:0 193:0 194:0 195:0 196:0 197:0 198:0 199:0 200:0 201:0 202:0 203:0 204:0 205:0 206:0 207:0 208:0 209:0 210:0 211:0 212:0 213:0 214:0 215:0 216:0 217:0 218:0 219:0 220:0 221:0 222:0 223:0 224:0 225:0 226:0 227:0 228:0 229:0 230:0 231:0 232:0 233:0 234:0 235:0 236:0 237:0 238:0 239:0 240:0 241:0 242:0 243:0 244:0 245:0 246:0 247:0 248:0 249:0 250:0 251:0 252:0 253:0 254:0 255:9 256:0 257:0 258:0 259:0 260:0 261:0 262:0 263:0 264:0 265:0 266:0 267:0 268:0 269:0 270:0 271:0 272:0 273:0 274:0 275:0 276:0 277:0 278:0 279:0 280:0 281:0 282:0 283:0 284:0 285:0 286:0 287:0 288:0 289:0 290:0 291:0 292:0 293:0 294:0 295:0 296:0 297:0 298:0 299:0 300:0 301:0 302:0 303:0 304:0 305:0 306:0 307:0 308:0 309:0 310:0 311:0 312:0 313:0 314:0 315:0 316:0 317:0 318:0 319:0 320:0 321:0 322:0 323:0 324:0 325:0 326:0 327:0 328:0 329:0 330:0 331:0 332:0 333:0 334:0 335:0 336:0 337:0 338:0 339:0 340:0 341:0 342:0 343:0 344:0 345:0 346:0 347:0 348:0 349:0 350:0 351:0 352:0 353:0 354:0 355:0 356:0 357:0 358:0 359:0 360:0 361:0 362:0 363:0 364:0 365:0 366:0 367:0 368:0 369:0 370:0 371:0 372:0 373:0 374:0 375:0 376:0 377:0 378:0 379:0 380:0 381:0 382:0 383:0 384:0 385:0 386:0 387:0 388:0 389:0 390:0 391:0 392:0 393:0 394:0 395:0 396:0 397:0 398:0 399:0 400:0 401:0 402:0 403:0 404:0 405:0 406:0 407:0 408:0 409:0 410:0 411:0 412:0 413:0 414:0 415:0 416:0 417:0 418:0 419:0 420:0 421:0 422:0 423:0 424:0 425:0 426:0 427:0 428:0 429:0 430:0 431:0 432:0 433:0 434:0 435:0 436:0 437:0 438:0 439:0 440:0 441:0 442:0 443:0 444:0 445:0 446:0 447:0 448:0 449:0 450:0 451:0 452:0 453:0 454:0 455:0 456:0 457:0 458:0 459:0 460:0 461:0 462:0 463:0 464:0 465:0 466:0 467:0 468:0 469:0 470:0 471:0 472:0 473:0 474:0 475:0 476:0 477:0 478:0 479:0 480:0 481:0 482:0 483:0 484:0 485:0 486:0 487:0 488:0 489:0 490:0 491:0 492:0 493:0 494:0 495:0 496:0 497:0 498:0 499:0 500:0 501:0 502:0 503:0 504:0 505:0 506:0 507:0 508:0 509:0 510:0 511:10 512:0 513:0 514:0 515:0 516:0 517:0 518:0 519:0 520:0 521:0 522:0 523:0 524:0 525:0 526:0 527:0 528:0 529:0 530:0 531:0 532:0 533:0 534:0 535:0 536:0 537:0 538:0 539:0 540:0 541:0 542:0 543:0 544:0 545:0 546:0 547:0 548:0 549:0 550:0 551:0 552:0 553:0 554:0 555:0 556:0 557:0 558:0 559:0 560:0 561:0 562:0 563:0 564:0 565:0 566:0 567:0 568:0 569:0 570:0 571:0 572:0 573:0 574:0 575:0 576:0 577:0 578:0 579:0 580:0 581:0 582:0 583:0 584:0 585:0 586:0 587:0 588:0 589:0 590:0 591:0 592:0 593:0 594:0 595:0 596:0 597:0 598:0 599:0 600:0 601:0 602:0 603:0 604:0 605:0 606:0 607:0 608:0 609:0 610:0 611:0 612:0 613:0 614:0 615:0 616:0 617:0 618:0 619:0 620:0 621:0 622:0 623:0 624:0 625:0 626:0 627:0 628:0 629:0 630:0 631:0 632:0 633:0 634:0 635:0 636:0 637:0 638:0 639:0 640:0 641:0 642:0 643:0 644:0 645:0 646:0 647:0 648:0 649:0 650:0 651:0 652:0 653:0 654:0 655:0 656:0 657:0 658:0 659:0 660:0 661:0 662:0 663:0 664:0 665:0 666:0 667:0 668:0 669:0 670:0 671:0 672:0 673:0 674:0 675:0 676:0 677:0 678:0 679:0 680:0 681:0 682:0 683:0 684:0 685:0 686:0 687:0 688:0 689:0 690:0 691:0 692:0 693:0 694:0 695:0 696:0 697:0 698:0 699:0 700:0 701:0 702:0 703:0 704:0 705:0 706:0 707:0 708:0 709:0 710:0 711:0 712:0 713:0 714:0 715:0 716:0 717:0 718:0 719:0 720:0 721:0 722:0 723:0 724:0 725:0 726:0 727:0 728:0 729:0 730:0 731:0 732:0 733:0 734:0 735:0 736:0 737:0 738:0 739:0 740:0 741:0 742:0 743:0 744:0 745:0 746:0 747:0 748:0 749:0 750:0 751:0 752:0 753:0 754:0 755:0 756:0 757:0 758:0 759:0 760:0 761:0 762:0 763:0 764:0 765:0 766:0 767:0 768:0 769:0 770:0 771:0 772:0 773:0 774:0 775:0 776:0 777:0 778:0 779:0 780:0 781:0 782:0 783:0 784:0 785:0 786:0 787:0 788:0 789:0 790:0 791:0 792:0 793:0 794:0 795:0 796:0 797:0 798:0 799:0 800:0 801:0 802:0 803:0 804:0 805:0 806:0 807:0 808:0 809:0 810:0 811:0 812:0 813:0 814:0 815:0 816:0 817:0 818:0 819:0 820:0 821:0 822:0 823:0 824:0 825:0 826:0 827:0 828:0 829:0 830:0 831:0 832:0 833:0 834:0 835:0 836:0 837:0 838:0 839:0 840:0 841:0 842:0 843:0 844:0 845:0 846:0 847:0 848:0 849:0 850:0 851:0 852:0 853:0 854:0 855:0 856:0 857:0 858:0 859:0 860:0 861:0 862:0 863:0 864:0 865:0 866:0 867:0 868:0 869:0 870:0 871:0 872:0 873:0 874:0 875:0 876:0 877:0 878:0 879:0 880:0 881:0 882:0 883:0 884:0 885:0 886:0 887:0 888:0 889:0 890:0 891:0 892:0 893:0 894:0 895:0 896:0 897:0 898:0 899:0 900:0 901:0 902:0 903:0 904:0 905:0 906:0 907:0 908:0 909:0 910:0 911:0 912:0 913:0 914:0 915:0 916:0 917:0 918:0 919:0 920:0 921:0 922:0 923:0 924:0 925:0 926:0 927:0 928:0 929:0 930:0 931:0 932:0 933:0 934:0 935:0 936:0 937:0 938:0 939:0 940:0 941:0 942:0 943:0 944:0 945:0 946:0 947:0 948:0 949:0 950:0 951:0 952:0 953:0 954:0 955:0 956:0 957:0 958:0 959:0 960:0 961:0 962:0 963:0 964:0 965:0 966:0 967:0 968:0 969:0 970:0 971:0 972:0 973:0 974:0 975:0 976:0 977:0 978:0 979:0 980:0 981:0 982:0 983:0 984:0 985:0 986:0 987:0 988:0 989:0 990:0 991:0 992:0 993:0 994:0 995:0 996:0 997:0 998:0 999:0 1000:0 1001:0 1002:0 1003:0 1004:0 1005:0 1006:0 1007:0 1008:0 1009:0 1010:0 1011:0 1012:0 1013:0 1014:0 1015:0 1016:0 1017:0 1018:0 1019:0 1020:0 1021:0 1022:0 1023:11 

此函数若实在要设置比16更大的采样点,则只需改三处:旧、新LBP table的类型从uchar改成更大数据类型,结果图的数据类型也改大即可。 至此,我们已理解了旋转不变性等价LBP。

接下来我们看下上面提到的python计算LBP的函数

skimage.feature.local_binary_pattern

(看这个函数前,大家可以忘记上面所有内容,因为这个函数的原理与上面大多数博主所述略有不同)python的这个函数上面已发过有下面这几种模式:

import numpy as np
from skimage.feature import local_binary_pattern

image = np.array([[7, 9, 10, 3, 1, 6],
                  [4, 7, 9, 3, 2, 8],
                  [2, 9, 5, 2, 2, 6],
                  [3, 9, 9, 3, 8, 2],
                  [9, 4, 7, 9, 9, 1],
                  [1, 4, 9, 4, 6, 3]]).astype(np.uint8)

defaultlbp=local_binary_pattern(image, 4, 1, "default")
#只对default结果 旋转的最小值作为最终结果
defaultrotalbp=local_binary_pattern(image, 4, 1, "ror")
nri_uniformlbp = local_binary_pattern(image, 4, 1, "nri_uniform")
uniformlbp = local_binary_pattern(image,4, 1, "uniform")
varlbp = local_binary_pattern(image, 4, 1, "var")
print("image =")
print(image)
print("default lbp =")
print(defaultlbp)
print("default ratate lbp =")
print(defaultrotalbp)
print("nri_uniform lbp =")
print(nri_uniformlbp)
print("uniformlbp lbp =")
print(uniformlbp)
print("var lbp =")
print(varlbp)

运行完,结果如下:

image =
[[ 7  9 10  3  1  6]
 [ 4  7  9  3  2  8]
 [ 2  9  5  2  2  6]
 [ 3  9  9  3  8  2]
 [ 9  4  7  9  9  1]
 [ 1  4  9  4  6  3]]
default lbp =
[[ 1.  1.  0. 12. 13.  8.]
 [ 3. 11.  2.  6. 13.  0.]
 [11.  8. 14. 15. 15.  2.]
 [ 9.  3.  4. 13.  8.  6.]
 [ 0. 15. 11.  1.  4. 14.]
 [ 3.  3.  0.  7.  2.  4.]]
default ratate lbp =
[[ 1.  1.  0.  3.  7.  1.]
 [ 3.  7.  1.  3.  7.  0.]
 [ 7.  1.  7. 15. 15.  1.]
 [ 3.  3.  1.  7.  1.  3.]
 [ 0. 15.  7.  1.  1.  7.]
 [ 3.  3.  0.  7.  1.  1.]]
nri_uniform lbp =
[[ 1.  1.  0.  7. 11.  2.]
 [ 5. 10.  4.  8. 11.  0.]
 [10.  2. 12. 13. 13.  4.]
 [ 6.  5.  3. 11.  2.  8.]
 [ 0. 13. 10.  1.  3. 12.]
 [ 5.  5.  0.  9.  4.  3.]]
uniformlbp lbp =
[[1. 1. 0. 2. 3. 1.]
 [2. 3. 1. 2. 3. 0.]
 [3. 1. 3. 4. 4. 1.]
 [2. 2. 1. 3. 1. 2.]
 [0. 4. 3. 1. 1. 3.]
 [2. 2. 0. 3. 1. 1.]]
var lbp =
[[13.6875 13.5    15.1875 15.25    4.6875 11.1875]
 [ 9.5     4.6875  6.6875  8.5     7.25    6.75  ]
 [10.5     6.6875  9.1875  1.1875  6.75    9.    ]
 [16.5     7.6875  5.      8.5     8.5    11.1875]
 [ 2.5     4.1875  4.6875  5.6875  9.5    11.25  ]
 [13.6875 12.25    6.1875 13.5    10.5     6.1875]]

上面是以半径r=1,采样点p=4(即不用插值,像p=8等其他情况根据原论文指导需要插值得到几个采样点,但原理与p=4一样,此处只以p=4讲述)为例。由原论文可知,如下图所示,default模式是:中心点正下方的比较后放在最高位,然后顺时针转,转成十进制后作为default的最终结果:
在这里插入图片描述

default lbp =
[[ 1.  1.  0. 12. 13.  8.]
 [ 3. 11.  2.  6. 13.  0.]
 [11.  8. 14. 15. 15.  2.]
 [ 9.  3.  4. 13.  8.  6.]
 [ 0. 15. 11.  1.  4. 14.]
 [ 3.  3.  0.  7.  2.  4.]]

由此结果可知,图像四周填充r距离,全都填0,这样LBP结果图与原图大小一致。以(1,1)=7这个点为例,四个采样点值为9,4,9,9,那么二进制为1011=11 结果正确。
然后再看"ror"模式,这个模式是在default模式结果图的基础上对数值的二进制进行旋转,旋转的最小值作为最终结果:

default ratate lbp =
[[ 1.  1.  0.  3.  7.  1.]
 [ 3.  7.  1.  3.  7.  0.]
 [ 7.  1.  7. 15. 15.  1.]
 [ 3.  3.  1.  7.  1.  3.]
 [ 0. 15.  7.  1.  1.  7.]
 [ 3.  3.  0.  7.  1.  1.]]

依旧以(1,1)=11这个点为例,旋转1011到最小即0111=7可以看到结果正确。
接下来,我们看uniform模式,根据原论文我们知道,这个模式具有灰度不变性和旋转不变性:
在这里插入图片描述
由论文中的公式我们知道,这与之前大部分博主所述略有不同,所以我们就直接按这个论文来讲以下内容,这个模式的结果为:

uniformlbp lbp =
[[1. 1. 0. 2. 3. 1.]
 [2. 3. 1. 2. 3. 0.]
 [3. 1. 3. 4. 4. 1.]
 [2. 2. 1. 3. 1. 2.]
 [0. 4. 3. 1. 1. 3.]
 [2. 2. 0. 3. 1. 1.]]

这个函数的"uniform"模式是在原图的基础上,对采样点比较后的结果相加,所以不用在乎哪个放二进制的高位、低位,直接比较后的结果相加即可。依旧以(1,1)=7为例,四个采样点为9,4,9,9,那么结果就是(9>7)+(4>7)+(9>7)+(9>7)=3。结果正确!我们编程完再试一次p=8,r=3时,如下图左边是python的结果,右边是C++我编完跑的结果,可以看到几乎一致,略有差别的原因我估计是插值导致的(测试代码与图片放在此链接: https://download.csdn.net/download/wd1603926823/86892032 ):
在这里插入图片描述
对于这个uniform模式,我们由上图的原理知道,网上很多人讲的都是错的,不是直接将比较结果转化为二进制,如下图论文作者说第一行只有0和8跳变次数是0,其它7个都是2次跳变,以我高亮出来的5为例,并不是将5转成二进制00000101(跳变4次,这与论文作者所述不符合),而是按顺时针/逆时针去比较每个采样点结果之间的跳变次数。(其实也可以说是转成二进制,但是不是将结果转二进制,而是按每个采样点结果转,如高亮部分应转成00011111,这样跳变次数就是2次。这个点的uniform lbp结果就是5):
在这里插入图片描述即编程出来与之前的差别就是不要直接转二进制的:

//from <Multiresolution Gray Scale and Rotation Invariant Texture Classification with Local Binary Patterns>
tmp += (neighbor>=center) ;

接下来我们看下一个模式var模式,这个模式的原理如下,由公式知道这个模式也不用考虑高位、低位:
在这里插入图片描述运行结果如下:

var lbp =
[[13.6875 13.5    15.1875 15.25    4.6875 11.1875]
 [ 9.5     4.6875  6.6875  8.5     7.25    6.75  ]
 [10.5     6.6875  9.1875  1.1875  6.75    9.    ]
 [16.5     7.6875  5.      8.5     8.5    11.1875]
 [ 2.5     4.1875  4.6875  5.6875  9.5    11.25  ]
 [13.6875 12.25    6.1875 13.5    10.5     6.1875]]

依旧以(1,1)这个点为例,每个采样点与所有采样点的均值的平方和的均值,作为最终结果。带入计算后可知结果正确。接下来继续看最后一个模式nri_uniform 模式:对于这个模式是非旋转不变性的等价LBP,网上资料比较少,我要先去看原论文再实现

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元气少女缘结神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值