圖像旋轉(zhuǎn)及c++實現(xiàn)

主要還是考慮面試的時候會不會用到斤富,剛才好好看了下旋轉(zhuǎn)的這個思路淤袜,其實和圖像縮放的思路差不多的,主要的問題是要找到坐標的映射方式持偏。
因為還是包含了一部分的公式砍的,所以我再word里寫好然后截圖上來吧痹筛。
(我錯了,簡書已經(jīng)支持輸入公式了挨约,latex語法就好味混,這是寫完之后才發(fā)現(xiàn)的!!)

圖像旋轉(zhuǎn)的變換公式。

這個實際上很簡單诫惭,主要是一些三角函數(shù)方面的推導:

假設(x1,y1)旋轉(zhuǎn)a到達(x2,y2),那么根據(jù)上圖可以寫出下面的式子:

展開:

替換蔓挖,得到后向映射公式:

由這個式子也很容易解出前向映射的公式:

這便是全部的公式了夕土,圖像旋轉(zhuǎn)是可以用矩陣來表示的,我們把后向映射表示出來:

圖像旋轉(zhuǎn)實現(xiàn)的思路。

其實只要是圖像變換怨绣,無論是旋轉(zhuǎn)還是放大縮小角溃,思路都是基本相同的,就是要尋找一種映射關系篮撑,前向映射是由原圖映射到目標圖减细,后向映射是從目標圖映射到原圖,就寫程序和復雜度來說赢笨,后向映射的復雜度更低未蝌,寫起來也更容易理解。

后向映射的主要思路:

  • 建立目標圖茧妒。
  • 對于目標圖中的每一點萧吠,映射到原圖中的一個點,這個點可能是不存在的(比如小數(shù)坐標)桐筏,所以需要進行插值處理纸型。
  • 插值重建目標圖。

對于旋轉(zhuǎn)來說梅忌,一般我們習慣繞著中心點進行旋轉(zhuǎn)狰腌,所以還要進行坐標變換。

C++實現(xiàn)牧氮。

借助了opencv的Mat數(shù)據(jù)類型琼腔,主要的還是希望用到其索引的方式,把重點放在旋轉(zhuǎn)本身蹋笼,如果給定的是數(shù)組類型的圖像展姐,那么只需要根據(jù)行,列剖毯,通道這三參數(shù)進行變換即可圾笨。

  • 讀入圖像,并且進行坐標變換逊谋。
    Mat img = imread("2.jpg");
    cout << "原圖尺寸:" << img.size() << endl;
    imshow("source_img", img);
 
    double angle =-10/180.0f*PI;         //這里就是除的180少寫個f擂达,以至于兩個int相除肯定是不對的
    int height = img.rows;
    int width = img.cols;   

    //四個定點在旋轉(zhuǎn)坐標系中的位置
    //  1  2
    //  3  4
    int SrcX1 = -width / 2;
    int SrcY1 = height / 2;
    int SrcX2 = width / 2;
    int SrcY2 = height / 2;
    int SrcX3 = -width / 2;
    int SrcY3 = -height / 2;
    int SrcX4 = width / 2;
    int SrcY4 = -height / 2;
    
    double cosAn = std::cos(angle);
    double sinAn = std::sin(angle);

這個坐標變換是為了計算目標圖像的最小尺寸,這里使用前向映射,由原圖映射到目標圖:

  • 計算目標尺寸并開辟存儲空間胶滋。
    int DstX1 = (int)(SrcX1*cosAn - SrcY1*sinAn +0.5);
    int DstY1 = (int)(SrcX1*sinAn + SrcY1*cosAn +0.5);

    int DstX2 = (int)(SrcX2*cosAn - SrcY2*sinAn +0.5);
    int DstY2 = (int)(SrcX2*sinAn + SrcY2*cosAn +0.5);

    int DstX3 = (int)(SrcX3*cosAn - SrcY3*sin(angle)+0.5);
    int DstY3 = (int)(SrcX3*sinAn + SrcY3*cosAn +0.5);

    int DstX4 = (int)(SrcX4*cosAn - SrcY4*sinAn + 0.5);
    int DstY4 = (int)(SrcX4*sinAn + SrcY4*cosAn + 0.5);

    int DstWidth = max(abs(DstX1 - DstX4), abs(DstX2 - DstX3))+1;
    int DstHeight = max(abs(DstY1 - DstY4), abs(DstY2 - DstY3))+1;
    
    //旋轉(zhuǎn)后的最合適的寬度和高度

    Mat Dst=Mat::zeros(DstHeight,DstWidth, img.type());
    
    //Dst.create(DstHeight, DstWidth, img.type());    //創(chuàng)建DST圖像

加0.5的目的是四舍五入板鬓。

  • 后向映射,插值處理究恤,為了簡單這里直接用的最鄰近插值俭令。
    坐標變換是重點:
D2S_x = round(double(i - DstWidth / 2.0f)* cosAn  +  double(j - DstHeight / 2.0f)*sinAn + width / 2.0f);
D2S_y = round(-double(i - DstWidth / 2.0f)*sinAn  +  double(j - DstHeight / 2.0f)* cosAn + height / 2.0f);

四步走:

  1. 變換原點到中心。
  2. 后向映射找對應原圖中的坐標(可能是小數(shù)部宿,也是原點在中心)
  3. 映射后的點變換原點到原圖左上角抄腔。
  4. 插值瓢湃,這里直接用的round取四舍五入,就是最鄰近插值了赫蛇。

    //映射回去的原圖中的坐標
    int D2S_x=0;     
    int D2S_y=0;

    for (int i = 0; i < DstWidth; i++)
    {
        for (int j = 0; j < DstHeight; j++)
        {
            D2S_x = round(double(i - DstWidth / 2.0f)* cosAn  +  double(j - DstHeight / 2.0f)*sinAn + width / 2.0f);
            D2S_y = round(-double(i - DstWidth / 2.0f)*sinAn  +  double(j - DstHeight / 2.0f)* cosAn + height / 2.0f);
        

            if (Dst.channels() == 1)
            {
                if (D2S_x < 0 || D2S_x >= width || D2S_y < 0 || D2S_y >= height)
                    Dst.at<uchar>(j, i) = 0;
                else
                    Dst.at<uchar>(j, i) = img.at<uchar>(D2S_y,D2S_x);
            }
            else if (Dst.channels() == 3)
            {
                if (D2S_x < 0 || D2S_x >= width || D2S_y < 0 || D2S_y >= height)
                    Dst.at<Vec3b>(j, i) = Vec3b(0, 0, 0);
                else
                    Dst.at<Vec3b>(j, i) = img.at<Vec3b>(D2S_y,D2S_x);
            }
        }
    }

遇見的坑绵患。

  • 整型除整型得到的還是整型。
    這種錯誤按理說不該犯悟耘,但是matlab寫多了就是會犯這種錯誤落蝙。如果需得到double型的數(shù)據(jù),記得加上.f暂幼。
  • Mat數(shù)據(jù)坐標系統(tǒng)筏勒。
    at操作符里面的是先行后列而不是坐標
    Mat的坐標系統(tǒng)是橫軸為x,縱軸為y,分別對應列和行粟誓。
    這些東西不確定的時候一定要查一下定義奏寨,要不還是很容易出錯。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鹰服,一起剝皮案震驚了整個濱河市病瞳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悲酷,老刑警劉巖套菜,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異设易,居然都是意外死亡逗柴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門顿肺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戏溺,“玉大人,你說我怎么就攤上這事屠尊】趸觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵讼昆,是天一觀的道長托享。 經(jīng)常有香客問我,道長浸赫,這世上最難降的妖魔是什么闰围? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮既峡,結果婚禮上羡榴,老公的妹妹穿的比我還像新娘。我一直安慰自己运敢,他們只是感情好炕矮,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布么夫。 她就那樣靜靜地躺著者冤,像睡著了一般肤视。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涉枫,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天邢滑,我揣著相機與錄音,去河邊找鬼愿汰。 笑死困后,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的衬廷。 我是一名探鬼主播摇予,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吗跋!你這毒婦竟也來了侧戴?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤跌宛,失蹤者是張志新(化名)和其女友劉穎酗宋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疆拘,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡蜕猫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哎迄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片回右。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漱挚,靈堂內(nèi)的尸體忽然破棺而出翔烁,到底是詐尸還是另有隱情,我是刑警寧澤棱烂,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布租漂,位于F島的核電站,受9級特大地震影響颊糜,放射性物質(zhì)發(fā)生泄漏哩治。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一衬鱼、第九天 我趴在偏房一處隱蔽的房頂上張望业筏。 院中可真熱鬧,春花似錦鸟赫、人聲如沸蒜胖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽台谢。三九已至寻狂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朋沮,已是汗流浹背蛇券。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留樊拓,地道東北人纠亚。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像筋夏,于是被迫代替她去往敵國和親蒂胞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容