雙線性插值(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++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快