原理:
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