雙線性插值(Bilinear interpolation)的映像旋轉在mobile上面的C++實現

來源:互聯網
上載者:User

在映像展開了以後, 很自然地我們想把映像的旋轉也做進來。我們找來了映像旋轉的公式:

 

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位的大數來描述一下先,就像下面這樣的:

//test interface for math<br />const int K_CosineTable[24] =<br />{<br />8192,<br />8172,<br />8112,<br />8012,<br />7874,<br />7697,<br />7483,<br />7233,<br />6947,<br />6627,<br />6275,<br />5892,<br />5481,<br />5043,<br />4580,<br />4096,<br />3591,<br />3068,<br />2531,<br />1981,<br />1422,<br />856,<br />285,<br />-285<br />};<br />int ShiftCos(int y)<br />{<br />if (y<0) y*=-1;<br />y %= 360;<br />if ( y > 270 )<br />{<br />return ShiftCos((360 - y));<br />}<br />else if ( y > 180 )<br />{<br />return - ShiftCos((y - 180));<br />}<br />else if ( y > 90 )<br />{<br />return - ShiftCos((180 - y));<br />}<br />int index = (y >> 2);<br />int offset = (y % 4);<br />// on the borderline of overflowing if use JInt16<br />int cosVal = (4 - offset) * K_CosineTable[index]<br />+ offset * K_CosineTable[index + 1];<br />return cosVal >> 2;<br />}<br />int ShiftSin(int y)<br />{<br />return ShiftCos(y + 270);<br />}

有了這個三角函數的輔助:我們的最後的代碼就是這個樣子:

/**<br />** method to remove sharp the raw image with unsharp mask<br />* @param src input grayscale binary array<br />* @param srcWidth width of the input grayscale image<br />* @param srcHeight height of the input grayscale image<br />* @param [output] dst output gray-scale image.<br />* @param [output] dstWidth width of the output grayscale image<br />* @param [output] dstHeight height of the output grayscale image<br />* @param angle, rotate angle.<br />*/<br />void rotateImage (const unsigned char* src, int srcWidth, int srcHeight, unsigned char*& dst, int& dstWidth, int& dstHeight, int angle)<br />{</p><p>// first calculate the new width and height;<br />const int SHIFT = 13;<br />dstWidth = ( abs (srcWidth*ShiftCos(angle)) + abs (srcHeight*ShiftSin(angle))) >> SHIFT;<br />dstHeight = ( abs (srcWidth*ShiftSin(angle)) + abs (srcHeight*ShiftCos(angle))) >> SHIFT;<br />dst = new unsigned char [dstWidth*dstHeight];<br />int xcenter = srcWidth >> 1;<br />int ycenter = srcHeight >> 1;<br />int xnew = dstWidth >> 1;<br />int ynew = dstHeight >> 1;<br />const int xFix = ( xcenter <<8 ) - ((ynew * ShiftSin (angle)) >> 5 ) - ((xnew * ShiftCos (angle)) >> 5) ;<br />const int yFix = ( ycenter <<8 ) + ((xnew * ShiftSin (angle)) >> 5 ) - ((ynew * ShiftCos (angle)) >> 5) ;</p><p>int ox;<br />int oy;<br />int x;<br />int y;<br />int kx;<br />int ky;<br />int color [2][2];<br />for (int j=0;j<dstHeight;j++)<br />{<br />for (int i=0;i<dstWidth;i++)<br />{<br />ox = ((i * ShiftCos (angle) + j * ShiftSin (angle)) >> 5) + xFix;<br />oy = (((-1) * i * ShiftSin(angle) + j * ShiftCos (angle)) >> 5) + yFix;<br />if ( (ox >> 8) <= srcWidth && (ox >> 8) >=0 && (oy >> 8) <= srcHeight && (oy >> 8) >= 0)<br />{<br />kx = ox >> 8;<br />ky = oy >> 8;<br />x = ox & 0xFF;<br />y = oy & 0xFF;<br />color[0][0] = src[ ky*srcWidth + kx ];<br />color[1][0] = src[ ky*srcWidth + kx +1 ];<br />color[0][1] = src[ (ky+1)*srcWidth + kx ];<br />color[1][1] = src[ (ky+1)*srcWidth + kx+1 ];<br />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];<br />final = final >> 16;<br />if (final>255)<br />final = 255;<br />if (final<0)<br />final = 0;<br />dst [ j*dstWidth + i] = (unsigned char)final;<br />}<br />else<br />{<br />dst [j*dstWidth + i] = 0xff;<br />}<br />}<br />}<br />}

這裡說明一下的是介面的定義,這裡的和目標灰階圖相關的參數都是參考型別的。表示都是輸出的參數,因為映像旋轉以後的大小會發生變化,函數外不是很方便事先分配好記憶體,所以這裡採用了就地分配的模式。記憶體配置在函數內部完成。雖然沒有用ticks去最後測速,但是想來沒有浮點數的計算,這裡的效率還是比較高的,當然這裡一些細節的記錄上還有可以再最佳化一下的,比如說這個常數5!!!Majic Number呵呵, 其實就是原來的那些數字都希望是左移8的, 所以三角函數中出來的數字需要左移5位!!除此以外就完全是公式的套用了 呵呵。

最後來點各個角度的看看:

20度

40度

60度

80度

100度

120度

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.