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

本文主要是介绍雙線性插值(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<dstHeight;j++)  

    {  

        for (int i=0;i<dstWidth;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

这篇关于雙線性插值(Bilinear interpolation)的圖像旋轉在mobile上面的C++實現的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/192186

相关文章

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(