關於我自己

我的相片
累計超過15年的工作經驗,包括10年的設備製造業經驗,超過6年的光電零組件製造業經驗;10年的海外工作經驗,其中至今有5年以上的派駐經驗。 1.專注AOI檢測於10年以上(從光機設計、圖像分析、設備挑選、處理速度) 2.機器學習推論-onnx整合傳統演算法從瑕疵抓取、分析、分類 3.遷移式機器學習模式(工業應用、醫療應用) 4.整合:Python推論引擎、C++運算能力、C#友善介面 彈性使用 5.擅長利用專家模型推進專案,並熟悉使用OpenVINO、TensorRT、ONNXRUNTIME框架進行有效的實作與測試。

2011年10月6日 星期四

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

http://blog.csdn.net/cay22/article/details/5555585

雙線性插值(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
 

40

 

60
 

80
 

100

120

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/hhygcy/archive/2009/08/20/4465876.aspx

沒有留言: