雙線性插值(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++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat