使用SSE4指令集优化双线性插值图像缩放

原理:

p = p(0) *(1-t) + p(1) * t = p(0) + (p(1) - p(0)) * t

水平方向和垂直方向均进行线性插值,缩放系数分别计算,由于水平和垂直成正交关系,因而与计算的先后次序无关。

 

缩放比例系数:

double scale_x = (des_width - 1)/(src_width - 1);

double scale_y = (des_height - 1)/(src_height - 1);

 

由于对图像进行采样时,索引从0开始,因而在计算缩放系数时应将宽高分别减1,以保证源和目的的最后一个采样点对齐。

 

计算权重和索引:

unsinged short* power;

unsinged short* map;

 

计算索引时,将浮点数进行截断取整,并保存为短整型。

计算权重时,将小数部分乘以16384并取整,即放大14位,这里采用整数计算而不是浮点计算。

 

缩放:

这里假设操作4通道32位颜色,如RGBA,其它颜色类似

以下代码为水平和垂直两个方向均进行缩放

void bl_hor_ver_out(int* des,
	int* src,
	int src_pitch,
	unsigned short* power_x,
	unsigned short* map_x, 
	unsigned short power_y, 
	int width)
{
	__asm
	{
		mov			edi, des;
		mov			esi, src;
		mov			edx, width;
		mov			eax, power_x;
		mov			ebx, map_x;
		movzx		ecx, power_y;
		movd		xmm7, ecx;
		pshuflw		xmm7, xmm7, 0;
		shufpd		xmm7, xmm7, 0;
		test		edx, edx;
		jz			loop_end;
loop_1:
		movzx		ecx, word ptr [ebx];	// 取出索引
		pmovzxbw	xmm0, [ecx * 4 + esi];	// 取出第一行两个像素
		add			esi, src_pitch;
		pmovzxbw	xmm1, [ecx * 4 + esi];	// 取出第二行两个像素
		sub			esi, src_pitch;
		movzx		ecx, word ptr [eax];	// 取出水平方向权重
		psubw		xmm1, xmm0;				// p(1) - p(0)
		movd		xmm2, ecx;
		psllw		xmm1, 2;				// 放大2位
		pshuflw		xmm2, xmm2, 0;
		pmulhw		xmm1, xmm7;        // (p(1) - p(0)) * ty,取高16位,得出未放大的结果
		paddw		xmm0, xmm1;	// p(0) + ((p(1) - p(0)) * ty
		pshufd		xmm1, xmm0, 0x0e;
		psubw		xmm1, xmm0;
		psllw		xmm1, 2;
		pmulhw		xmm1, xmm2;	// ((p(1) - p(0)) * tx
		paddw		xmm1, xmm0;	// p(0) + ((p(1) - p(0)) * tx
		packuswb	xmm1, xmm1;
		movd		[edi], xmm1;
		add			edi, 4;
		add			eax, 2;
		add			ebx, 2;
		dec			edx;
		jnz			loop_1;
loop_end:
	}
}



 

 

扩展:

(1)还可对上述代码进行优化,可采取一次计算两个像素,这样水平方向两个像素采用一个乘法指令(pmulhw);

(2)当只有水平方向或只有垂直方向进行缩放时,应该独立实现缩放函数,以提高效率,如函数名可为bl_hor_out, bl_ver_out;

(3)如果需要高精度,需要进行浮点计算,同时考虑补偿防止截断

 

英文链接:http://en.wikipedia.org/wiki/Bilinear_interpolation

你可能感兴趣的:(优化,扩展)