LBP理解

1.OLBP:

olbp即原始的LBP,就是比较(X,Y)周围的8个点,大于等于它就置为1,小于它就置为0,然后编码,再把这个编码后的值赋给该点。

void LBP(Mat src, Mat &dst)
{
	for (int i = 1; i < src.rows-1; ++i)
	{
		for (int j = 1; j < src.cols - 1; ++j)
		{
			uchar nei[9] = {0};
			nei[0] = src.at<uchar>(i, j);
			nei[1] = src.at<uchar>(i-1, j-1);
			nei[2] = src.at<uchar>(i-1, j);
			nei[3] = src.at<uchar>(i-1, j+1);
			nei[4] = src.at<uchar>(i, j+1);
			nei[5] = src.at<uchar>(i+1, j+1);
			nei[6] = src.at<uchar>(i+1, j);
			nei[7] = src.at<uchar>(i+1, j-1);
			nei[8] = src.at<uchar>(i, j-1);

			uchar value = 0;
			for (int n = 1; n <= 8; ++n)
			{
				value += (nei[n] >= nei[0]) << (8 - n);
			}
			dst.at<uchar>(i, j) = value;
		}
	}
}

2.ELBP:

为了防止溢出,在定义dst的时候,它的长宽要减2*radius。采样点(X,Y)的计算公式:x=radius * cos(2.0*\pi*n/neighbors)  y=-radius * sin(2.0*\pi *n/neighbors)。ELBP中使用了双线性插值,就简单介绍下双线性插值。

先在X轴方向插值(双线性插值,先X或者先Y都可以,与顺序无关):

f(R1)=\frac{x_{2}-x}{x_{2}-x_{1}}*f(Q11)+\frac{x-x_{1}}{x_{2}-x_{1}}*f(Q21)

f(R2)=\frac{x_{2}-x}{x_{2}-x_{1}}*f(Q12)+\frac{x-x_{1}}{x_{2}-x_{1}}*f(Q22)

然后Y轴方向插值:

f(P)=\frac{y_{2}-y}{y_{2}-y_{1}}*f(R1)+\frac{y-y_{1}}{y_{2}-y_{1}}*f(R2)

合并两个式子:

f(x,y)=\frac{(x_{2}-x)(y_{2}-y)}{(x_{2}-x_{1})(y_{2}-y_{1})}*f(Q11)+\frac{(x-x_{1})(y_{2}-y)}{(x_{2}-x_{1})(y_{2}-y_{1})}*f(Q21)+\frac{(x_{2}-x)(y-y_{1})}{(x_{2}-x_{1})(y_{2}-y_{1})}*f(Q12)+\frac{(x-x_{1})(y-y_{1})}{(x_{2}-x_{1})(y_{2}-y_{1})}*f(Q22)

为了方便计算,把这些点放到(0,1)之间,即Q11(0,0),Q21(1,0),Q12(0,1),Q22(1,1),则上式变为:

f=(1-x)(1-y)*f(Q11)+x(1-y)f(Q21)+(1-x)y*f(Q12)+xy*f(Q22)

具体的双线性插值可以看这里

void ELBP(Mat &src, Mat &dst, int radius, int neighbors)
{
	for (int n = 0; n < neighbors; ++n)
	{
		float x = static_cast<float>(radius*cos(2 * CV_PI*n / neighbors));
		float y = static_cast<float>(-radius*sin(2 * CV_PI*n / neighbors));

		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));

		float tx = x - fx;
		float ty = y - fy;

		float w1 = (1 - tx)*(1-ty);
		float w2 = tx*(1 - ty);
		float w3 = (1 - tx)*y;
		float w4 = tx*ty;

		for (int i = radius; i < src.rows - radius; ++i)
		{
			for (int j = radius; j < src.cols - radius; ++j)
			{
				float t = static_cast<float>(w1*src.at<uchar>(i + fy, j + fx) + w2*src.at<uchar>(i + fy, j + cx) + w3*src.at<uchar>(i + cy, j + fx) + w4*src.at<uchar>(i + cy, j + cx));
				
				dst.at<int>(i - radius, j - radius) += ((t > src.at<uchar>(i, j)) || (std::abs(t - src.at<uchar>(i, j)) < std::numeric_limits<float>::epsilon())) << n;
			}
		}
	}
}

最后算插值的公式是:

f(i,j)=w_{1}*f(i+fy,j+fx)+w_{2}*f(i+fy,j+cx)+w_{3}*f(i+cy,j+fy)+w_{4}*f(i+cy,j+cx)

好像是以左下角为坐标原点来算的。最后说说显示的问题,在定义dst时好像只能是 CV_32SC1 其它类型都会报错,直接显示ELBP的结果会出现一幅黑图,看了LBP原理加源码解析下面的评论,是要将ELBP的结果convertTo为CV_8UC1才能正常显示。经过试验,感觉ELBP显示的很慢。

这些源码在OpenCV的包中可以找到,具体位置:E:\opencv\sources\modules\contrib\src\facerec.cpp

参考:

OpenCV学习(39) OpenCV中的LBP图像

图像特征之LBP(OpenCV)

猜你喜欢

转载自blog.csdn.net/qq_40250862/article/details/82831652
LBP
今日推荐