双线性插值图像旋转c语言,双线性插值(Bilinear interpolation)的图像旋转在mobile上面的C++实现...

这篇博客介绍了如何在移动设备上使用C++实现图像旋转,采用双线性插值算法,并围绕图像中心进行旋转。通过预计算的三角函数表避免浮点运算,提高效率。代码包括图像尺寸调整、旋转计算和颜色插值等步骤,适用于资源有限的环境。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

双线性插值(Bilinear interpolation)的图像旋转在mobile上面的C++实现

我们找来了图像旋转的公式:

X' =X cosθ -Y sinθ;

Y' =X sinθ+ Y cosθ;

这个图像公式大家在高中数学课都是会算滴。然后我们要扩展一下因为我们不是在原点做旋转,我们要围绕原来的图片中心做旋转,那么我们假定原来的图像中心是oldCenterX, oldCenterY.旋转完成以后,我们要对图像位置坐调整,调整到新的坐标中心,那么我们需要有个新的newCenterX, newCenterY;新的坐标就是新的图片的中心。那么我们的公式就可以转化成了:

X' =(X-oldCenterX) cosθ -(Y-oldCenterY) sinθ+ newCenterX;

Y' =(X-oldCenterX) sinθ+ (Y-oldCenterY) cosθ + newCenterY;

当然啦,关键我们的问题不是旋转后的位置,而是旋转以后位置对于到原来的位置关系,也就是说我们更需要的是一个X,Y关于X'和Y'的表达式。很简单的,我们把问题变成了2元一次方程!

X = Y'sinθ + X'cosθ + oldCenterY - newCenterX cosθ - newCenterY sinθ;

Y = Y'cosθ - X'sinθ + oldCenterY - newCenterY cosθ + newCenterX sinθ;

这样要写个合适的代码就变得简单了。但是另一个显著的问题就是没有三角函数怎么办呢?就像我们插值的时候用大数一样,我们用左移13位的大数来描述一下先,就像下面这样的:

view plaincopy to clipboardprint?

//test interface for math

const int K_CosineTable[24] =

{

8192,

8172,

8112,

8012,

7874,

7697,

7483,

7233,

6947,

6627,

6275,

5892,

5481,

5043,

4580,

4096,

3591,

3068,

2531,

1981,

1422,

856,

285,

-285

};

int ShiftCos(int y)

{

if (y<0) y*=-1;

y %= 360;

if ( y > 270 )

{

return ShiftCos((360 - y));

}

else if ( y > 180 )

{

return - ShiftCos((y - 180));

}

else if ( y > 90 )

{

return - ShiftCos((180 - y));

}

int index= (y >> 2);

int offset = (y % 4);

// on the borderline of overflowing if use JInt16

int cosVal = (4 - offset) * K_CosineTable[index]

+ offset * K_CosineTable[index + 1];

return cosVal >> 2;

}

int ShiftSin(int y)

{

return ShiftCos(y + 270);

}

有了这个三角函数的辅助:我们的最后的代码就是这个样子:

view plaincopy to clipboardprint?

/**

** method to remove sharp the raw image with unsharp mask

* @param src input grayscale binary array

* @param srcWidth width of the input grayscale image

* @param srcHeight height of the input grayscale image

* @param [output] dst output gray-scale image.

* @param [output] dstWidth width of the output grayscale image

* @param [output] dstHeight height of the output grayscale image

* @param angle, rotate angle.

*/

void rotateImage (const unsigned char* src, int srcWidth, int srcHeight, unsigned char*& dst, int& dstWidth, int& dstHeight, int angle)

{

// first calculate the new width and height;

const int SHIFT = 13;

dstWidth= ( abs (srcWidth*ShiftCos(angle)) + abs (srcHeight*ShiftSin(angle))) >> SHIFT;

dstHeight = ( abs (srcWidth*ShiftSin(angle)) + abs (srcHeight*ShiftCos(angle))) >> SHIFT;

dst = new unsigned char [dstWidth*dstHeight];

int xcenter = srcWidth >> 1;

int ycenter = srcHeight >> 1;

int xnew = dstWidth >> 1;

int ynew = dstHeight >> 1;

const int xFix = ( xcenter <<8 ) - ((ynew * ShiftSin (angle)) >> 5 ) - ((xnew * ShiftCos (angle)) >> 5) ;

const int yFix = ( ycenter <<8 ) + ((xnew * ShiftSin (angle)) >> 5 ) - ((ynew * ShiftCos (angle)) >> 5) ;

int ox;

int oy;

int x;

int y;

int kx;

int ky;

int color [2][2];

for (int j=0;j

{

for (int i=0;i

{

ox = ((i * ShiftCos (angle) + j * ShiftSin (angle)) >> 5) + xFix;

oy = (((-1) * i * ShiftSin(angle) + j * ShiftCos (angle)) >> 5) + yFix;

if ( (ox >> 8) <= srcWidth && (ox >> 8) >=0 && (oy >> 8) <= srcHeight && (oy >> 8) >= 0)

{

kx = ox >> 8;

ky = oy >> 8;

x = ox & 0xFF;

y = oy & 0xFF;

color[0][0] = src[ ky*srcWidth + kx ];

color[1][0] = src[ ky*srcWidth + kx +1 ];

color[0][1] = src[ (ky+1)*srcWidth + kx ];

color[1][1] = src[ (ky+1)*srcWidth + kx+1 ];

int final = (0x100 - x)*(0x100 - y)*color[0][0] + x*(0x100 - y)*color[1][0] + (0x100-x)*y*color[0][1] + x*y*color[1][1];

final = final >> 16;

if (final>255)

final = 255;

if (final<0)

final = 0;

dst [ j*dstWidth + i] = (unsigned char)final;

}

else

{

dst [j*dstWidth + i] = 0xff;

}

}

}

}

这里说明一下的是接口的定义,这里的和目标灰度图相关的参数都是引用类型的。表示都是输出的参数,因为图像旋转以后的大小会发生变化,函数外不是很方便事先分配好内存,所以这里采用了就地分配的模式。内存分配在函数内部完成。虽然没有用ticks去最后测速,但是想来没有浮点数的计算,这里的效率还是比较高的,当然这里一些细节的记录上还有可以再优化一下的,比如说这个常数5!!!Majic Number呵呵,其实就是原来的那些数字都希望是左移8的,所以三角函数中出来的数字需要左移5位!!除此以外就完全是公式的套用了呵呵。

最后来点各个角度的效果图看看:

20度

0818b9ca8b590ca3270a3433284dd417.png

40度

0818b9ca8b590ca3270a3433284dd417.png

60度

0818b9ca8b590ca3270a3433284dd417.png

80度

0818b9ca8b590ca3270a3433284dd417.png

100度

0818b9ca8b590ca3270a3433284dd417.png

120度

0818b9ca8b590ca3270a3433284dd417.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值