LBP特征(4)Uniform Pattern LBP特征

参考:https://blog.csdn.net/quincuntial/article/details/50541815

Uniform Pattern LBP特征

Uniform Pattern,也被称为等价模式或均匀模式,由于一个LBP特征有多种不同的二进制形式,对于半径为R的圆形区域内含有P个采样点的LBP算子将会产生2^P种模式。很显然,随着邻域集内采样点数的增加,二进制模式的种类是以指数形式增加的。

例如:5×5邻域内20个采样点,有220220=1,048,576种二进制模式。这么多的二进制模式不利于纹理的提取、分类、识别及存取。例如,将LBP算子用于纹理分类或人脸识别时,常采用LBP模式的统计直方图来表达图像的信息,而较多的模式种类将使得数据量过大,且直方图过于稀疏。因此,需要对原始的LBP模式进行降维,使得数据量减少的情况下能最好的表示图像的信息。 

为了解决二进制模式过多的问题,提高统计性,Ojala提出了采用一种“等价模式”(Uniform Pattern)来对LBP算子的模式种类进行降维。Ojala等认为,在实际图像中,绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此,Ojala将“等价模式”定义为:当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类如00000000(0次跳变),00000111(只含一次从0到1的跳变),10001111(先由1跳到0,再由0跳到1,共两次跳变)都是等价模式类。除等价模式类以外的模式都归为另一类,称为混合模式类,例如10010111(共四次跳变)。通过这样的改进,二进制模式的种类大大减少,而不会丢失任何信息。模式数量由原来的2^P种减少为 P ( P-1)+2种,其中P表示邻域集内的采样点数。对于3×3邻域内8个采样点来说,二进制模式由原始的256种减少为58种,即:它把值分为59类,58个uniform pattern为一类,其它的所有值为第59类。这样直方图从原来的256维变成59维。这使得特征向量的维数更少,并且可以减少高频噪声带来的影响。 

具体实现:采样点数目为8个,即LBP特征值有2^8种,共256个值,正好对应灰度图像的0-255,因此原始的LBP特征图像是一幅正常的灰度图像,而等价模式LBP特征,根据0-1跳变次数,将这256个LBP特征值分为了59类,从跳变次数上划分:跳变0次—2个,跳变1次—0个,跳变2次—56个,跳变3次—0个,跳变4次—140个,跳变5次—0个,跳变6次—56个,跳变7次—0个,跳变8次—2个。共9种跳变情况,将这256个值进行分配,跳变小于2次的为等价模式类,共58个,他们对应的值按照从小到大分别编码为1—58,即它们在LBP特征图像中的灰度值为1—58,而除了等价模式类之外的混合模式类被编码为0,即它们在LBP特征中的灰度值为0,因此等价模式LBP特征图像整体偏暗。

//等价模式LBP特征计算
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;
}

int main()
{
	cv::Mat src = imread("..\\..\\image\\keliamoniz1.jpg", 0);
	cv::Mat dst;

	//getOriginLBPFeature<uchar>(src, dst);

	//getCircularLBPFeatureOptimization<uchar>(src, dst, 1, 8);

	//getRotationInvariantLBPFeature<uchar>(src, dst, 1, 8);

	getUniformPatternLBPFeature<uchar>(src, dst, 1, 8);

	return 0;
}

 
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JoannaJuanCV

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

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

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

打赏作者

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

抵扣说明:

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

余额充值