【opencv實踐】仿射變換和透視變換

2021-03-02 Opencv視覺實踐

點擊上方"藍色小字"關注我哦~

上面這副圖就是我們今天要處理的了,我們想把它從拍照視角變成鳥瞰圖,這是機器人導航中的常用手段,以便在該平面上進行規劃和導航。

這種變換常常用到透視變換,但我們今天在講解透視變換時,需要普及一下其他的變換,包括平移旋轉錯切放縮,以及仿射變換

綜述

所有複雜的東西,都是由基本的組成的。所以我們需要先了解一下基礎的變換有哪些:

平移

我們對矩形(圖像)平移,需要怎麼做?

對每一個像素點坐標平移。可以讓每一個像素點的x,y坐標都加一個變量。

矩陣形式表示:

等式左邊[X,Y,1]是像素坐標的齊次形式。等式右邊是平移之後的坐標。

放縮

進行放縮,就是將矩形(圖像)放縮n倍,也就是長寬各乘一個變量。

旋轉

對矩形(圖片)進行旋轉,關於旋轉的數學推導在後面仿射會介紹:

錯切

前面的都比較直觀,那錯切是什麼呢?

我們可以看下矩形關於y方向的錯切:

看圖就很直觀了,那數學表達呢?

x軸上的錯切就是同理了,公式如下:

然後兩者和起來,就如下了:

好了,到此我們就了解了這四種變換了,那仿射變換是什麼呢?可以看下圖公式:

等式右邊就是仿射變換矩陣,是由原圖像平移,旋轉,放縮,錯切之後得來的。

在書上往往將仿射變換和透視變換放一起講,這兩者各是什麼呢?

在剛學仿射變換和透視變換時,我是有些分不清的。印象最深刻的就是下圖:

可以看到,仿射變換(下)是將矩形變換成平行四邊形(即變換後各邊依舊平行),而透視變換(上)可以變換成任意不規則四邊形

這樣看來,好像仿射變換是透視變換的子集。

那到底是不是呢?其實是的。仿射變換屬於線性變換,而透視變換則不僅僅是線性變換。仿射變換可以看做是透視變換的一種特例。

直觀上感受,我們可以認為:

仿射變換是單純對圖片進行縮放,傾斜和旋轉,因此圖片不論如何變化,線之間的平行性是不變的。如下圖。

可以感受到,右圖是可以通過左圖平移,旋轉,錯切,縮放之後得來。

而透視變換,則是當觀察者的視角發生變化時物體發生的透視變換,此轉換允許造成透視形變。

我們看下圖的公路,近處寬遠處窄,就是因為視角的原因,

而我們本文要做的,就是將視角改為鳥瞰,從而得到類似下圖的鳥瞰圖:

前文已經說了,仿射變換是單純對圖片進行平移,縮放,傾斜和旋轉,而這幾個操作都不會改變圖片線之間的平行關係。

opencv中給出了仿射變換的函數接口:

warpAffine(  InputArray  src,    輸入圖像  OutputArray  dst,    輸出圖像  InputArray  M,      仿射計算矩陣  Size    dsize,    輸出圖像大小  int      flags = INIET_LINEAR,   插值方法  int      borderMode = BORDER_CONSTANT,     const Scalar&  borderValue = Scalar()    );

這個函數很好理解,輸入一個圖像,輸出這個圖像的仿射變換。

但第三個參數需要我們輸入2*3的仿射計算矩陣,這是什麼鬼?

我們先看一下仿射計算矩陣長什麼樣子(可以去掉最後一行):

我們的輸出圖像G(x,y) = F(x,y)乘仿射矩陣。

我們可以看下圖推導出仿射計算矩陣。

一個點P在原始坐標系下的坐標是(Xsp,Ysp)。然後要完成旋轉操作,旋轉操作是基於原點的。如何得到旋轉之後的點的坐標,這裡用到一個技巧:

坐標系中某個點的旋轉可以等價地去旋轉坐標軸。

所以有了上圖中以(Xs0,Ys0)為中心的虛線與屏幕水平垂直的坐標系。在這個坐標系中確定P的坐標,和在藍色坐標系中確定旋轉之後P的坐標是等價的。

基於這個結論,我們可以通過簡單的立體幾何知識確定P在新坐標系中的坐標。P在新坐標系中的X坐標和Y坐標分別是

進而我們可以得到:

到此,我們完成了旋轉操作,如何平移呢?僅是加一個平移常數的事:

到此,我們的2*3大小的仿射變換便推導出來了。

推導知道了,但如何實現呢?

opencv同樣給我們提供了計算仿射矩陣的函數接口:

getAffineTransform(  const Point2f* src,   輸入圖像的點集  const Point2f* dst    輸出圖像的點集  );

這個函數可以計算出我們想要圖像變換的矩陣,但需要我們輸入至少三對點集,點集是什麼鬼?為什麼是至少三對?

我們可以看到上面公式裡有六個變量,因此自然需要至少列六個等式才可計算出該矩陣。

因此我們需要找輸入圖像和輸出圖像上一一對應的三對點(3個x,y對應計算式)來作為輸入。

這樣,我們就可以進行仿射變換啦。

透視變換原理

我們說仿射變換是在二維空間中的旋轉,平移和縮放。而透視變換則是在三維空間中視角的變化。

opencv中同樣給出了透視變換的函數接口:

void warpPerspective(InputArray src,  輸入圖像OutputArray dst,  輸出圖像InputArray M,   輸入透視變換矩陣MSize dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar());

和仿射變換基本相同,不同的是輸入透視變換矩陣M大小為3*3:

上面矩陣的未知量比仿射變換的矩陣多了一個透視變換矩陣T3(兩個未知量),因此我們需要給下面計算透視變換矩陣的函數提供四對以上的點來求解:

 Mat cv::getPerspectiveTransform ( const Point2f src[],    輸入圖像點集                         const Point2f dst[],    輸出圖像點集 );

T1為線性變換完成旋轉,錯切和放縮,T2完成平移操作。T3就是設了兩個變量來表示映射關係。

編程實現

理解了透視變換的原理後,我們就著手來實現了(代碼可以順次複製即可運行):

首先是讀取原圖片並顯示啦:

#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;int main(){  Mat dstImage,srcImage = imread("road.png");  cout<<srcImage.size;  //674 x 1020    imshow("原圖", srcImage);  waitKey();  return 0;}

然後我們需要選取原圖上的四個點,並計算出該四對點變換後的位置。

如何選點?我們可以選兩邊白條的四個定點。那變換後的位置就需要我們自己估算了,如下圖:

我們希望將藍色的透視變換為黃色的。

  Point2f imgPts[4], objPts[4];  //透視前和透視後  //原坐標  imgPts[0].x = 20 * 1020 / 230; imgPts[0].y = 95 * 647 / 145;  imgPts[1].x = 210 * 1020 / 230; imgPts[1].y = 95 * 647 / 145;  imgPts[2].x = 90 * 1020 / 230; imgPts[2].y = 65 * 647 / 145;  imgPts[3].x = 140 * 1020 / 230; imgPts[3].y = 65 * 647 / 145;  //透視後坐標  int road_w = 540; //將透視變換的圖片大小改變一下  int road_h = 850;  objPts[0].x = 50;  objPts[0].y = 780;  objPts[1].x = 490; objPts[1].y = 780;  objPts[2].x = 50 ; objPts[2].y = 150;  objPts[3].x = 490; objPts[3].y = 150;

我們選取了如圖四個點,首先計算透視變換矩陣:

//計算透視變換矩陣Mat H = getPerspectiveTransform(imgPts, objPts);

然後進行透視變換:

//進行透視變換warpPerspective(srcImage, dstImage, H, srcImage.size());//畫出透視變換後的四個點circle(dstImage, objPts[0], 9, Scalar(0, 0, 255), 3);circle(dstImage, objPts[1], 9, Scalar(0, 0, 255), 3);circle(dstImage, objPts[2], 9, Scalar(0, 0, 255), 3);circle(dstImage, objPts[3], 9, Scalar(0, 0, 255), 3);imshow("變換後", dstImage);

 

這樣,我們就得到鳥瞰圖啦。                                                                        

本文中的部分公式截圖來自下面視頻的PPT:

這個視頻也是介紹仿射變換和透視變換的,大家可以和本文對比著看。     

本文如有表述錯誤的地方,還望批評指正!  

【opencv實踐】圖像增強基本操作

【opencv】帶你再學一遍直方圖

【opencv小項目】深入理解回調函數

   


點個在看,就可以評論啦~

相關焦點

  • 24、opencv圖像仿射變換
    執行這些操作的原因很多:例如,扭曲和旋轉圖像,以便它可以疊加在現有場景上或人為地放大用於對象識別的一組訓練圖像.可以執行的功能如拉伸,收縮,扭曲和旋轉圖像被稱為幾何變換。對於平面區域,有兩種風格的幾何變換:使用2×3矩陣的變換,稱為仿射變換;基於3×3矩陣進行變換,這被稱為透視變換。仿射變換是任何可以用矩陣乘法和矢量加法形式表示的變換。
  • 傅立葉變換、拉氏變換、z變換的含義
    (另一種說法)對於周期函數f,傅立葉變換就是把這個函數分解成很多個正弦函數fn的和,每個fn的頻率是f的n倍。所謂二次諧波,就是函數f2的頻率為f兩倍的那個函數。(另二種說法)周期信號的傅立葉級數的意義是信號在每一個離散頻率分量處的幅度;非周期信號的傅立葉變換可以理解為周期無窮大的周期信號的傅立葉級數。
  • 傅立葉變換與短時傅立葉變換
    :短時傅立葉變Gabor變換時頻分析小波變換Randon-Wiger 變換分數階傅立葉變換線調頻小波變換循環統計理論和調幅-調頻信號分析‥‥‥舉例1 有一信號主要頻率成分是50Hz和300Hz的正弦信號,該信號被一白噪聲汙染,現對該信號進行採樣
  • Python 圖像處理實戰 | 圖像的灰度非線性變換之對數變換、伽馬變換
    本篇文章主要講解非線性變換,使用自定義方法對圖像進行灰度化處理,包括對數變換和伽馬變換。本文主要講解灰度線性變換,基礎性知識希望對你有所幫助。圖像灰度非線性變換:DB=DA×DA/255圖像的灰度非線性變換主要包括對數變換、冪次變換、指數變換、分段函數變換,通過非線性關係對圖像進行灰度處理,下面主要講解三種常見類型的灰度非線性變換
  • OpenCV系列之SIFT尺度不變特徵變換 | 三十九
    因此,在2004年,不列顛哥倫比亞大學的D.Lowe在他的論文《尺度不變關鍵點中的獨特圖像特徵》中提出了一種新算法,即尺度不變特徵變換(SIFT),該算法提取關鍵點並計算其描述算符。 (改論文易於理解,被認為是學習SIFT的最佳材料。因此,本文只是該論文的簡短摘要)。SIFT算法主要包括四個步驟。我們將一一看到它們。
  • 幾何變換--圖像裁剪
    幾何變換:從新規定圖像內像素的幾何排列方式。幾何變換包括:縮放、旋轉、平移等。這些變換一般用於校正圖像處理引起的空間失真,或者通過將圖像配準到一個預定義的坐標系統中用於規範化該圖像(例如,將一幅航拍圖像配準到一個特定的地圖投影中,或者在立體視覺中對兩幅互相配對的圖像進行整形,使得行與外極限)。與點操作和局部濾波器不同,輸出圖像通常來說並不是來自同一個輸入像素位置。
  • halcon學習-相機標定與圖像徑向或透視畸變的校正
    1.初始化相機並設置相機內部參數和相機類型,確定校準目標。
  • 【圖像變換】DIBR-3D圖像變換(3D Image Warping)matlab源碼
    若m在u,v坐標系中的坐標為(mu,mv),每個像素在x和y軸方向上的物理尺寸為dx,dy。(3)這是從三維歐式空間到兩維歐式空間的一個映射。投影中心稱為攝像機中心,也稱為光心。攝像機中心到圖像平面的垂線稱為攝像機的主軸或主射線。
  • Hilbert 變換提取信號特徵的 Python 實現
    )的希爾伯特變換等於該信號通過具有衝激響應h(t)=1/πt的線性系統以後的輸出響應sh(t)。好的,這是Hilbert變換的定義,我們這裡討論它的一個具體用途,提取信號特徵值,提取信號特徵值有什麼用呢?設 A 是n階方陣,如果存在數m和非零n維列向量 x,使得 Ax=mx 成立,則稱 m 是A的一個特徵值或本徵值。
  • 完美通俗解讀小波變換:深入小波背後的一些原理
    我們還講了一般小波變換的三個特點,就是小波級數是二維的,能定位時域和頻域,計算很快。但我們並沒有深入講解,比如,如何理解這個二維?它是如何同時定位頻域和時域的?在這一篇文章裡,我們就來討論一下這些特性背後的原理。首先,我們一直都在講小波展開的近似形式。那什麼是完整形式呢?
  • 電能變換團隊獲國家科技進步一等獎 (創新團隊)
    大功率電能變換與控制技術是國防裝備、工業製造等領域的核心共性技術。
  • MATLAB實驗:圖像增強——灰度變換、直方圖均衡化
    空間域處理方法分為兩種:灰度級變換、空間濾波。空間域技術直接對像素進行操作其表達式為g(x,y)=T[f(x,y)]其中f(x,y)為輸入圖像,g(x,y)為輸出圖像,T是對圖像f進行處理的操作符,定義在點(x,y)的指定領域內。
  • 華為諾亞、北大提出GhostNet​,使用線性變換生成特徵圖,準確率超MobileNet v3 | CVPR 2020
    為此,作者對這些固有feature maps進行一系列簡單線性變換。具體公式為:其中, 表示固有feature maps中的第i個特徵圖, 表示對第i個feature map進行的第j個線性變換,也就是說,某一層feature map可能對應多個線性變換,得到多個變換結果。
  • 超詳講解圖像拼接/全景圖原理和應用 | 附源碼
    現在,我們需要獲取這些點並找到基於匹配點將2個圖像拼接在一起的變換矩陣。這種轉換稱為Homography matrix(單應性矩陣)。簡而言之,如果Homography是3x3矩陣,可用於許多應用,例如相機姿態估計,透視校正和圖像拼接。如果Homography是2D變換。它將點從一個平面(圖像)映射到另一個平面。讓我們看看我們是如何得到它的。
  • 第十五課 快速傅立葉變換及利用其進行簡單濾波
    FFT是離散傅立葉變換的快速算法,可以將一個信號變換到頻域。那其在實際應用中,有哪些用途呢?1.有些信號在時域上是很難看出什麼特徵的,但是如果變換到頻域之後,就很容易看出特徵(頻率,幅值,初相位);2.FFT可以將一個信號的頻譜提取出來,進行頻譜分析,為後續濾波準備;3.通過對一個系統的輸入信號和輸出信號進行快速傅立葉變換後,兩者進行對比,對系統可以有一個初步認識。  假設採樣頻率Fs,信號頻率F,信號長度L,採樣點數N。
  • MATLAB信號處理仿真-短時傅立葉變換,時、頻分辨力的蹺蹺板
    本次,我們將展示另外一個信號分析的有力工具,短時傅立葉變換。
  • FFT|示波器傅立葉變換功能在開關轉換器設計的應用
    現今的示波器除了能觀察信號的時域波形之外,還能經由內建的快速傅立葉變換(Fast Fourier Transform;FFT)功能觀察信號的頻譜。本文將介紹如何在示波器上設定快速傅立葉變換功能,並將此功能有效地應用於開關轉換器的設計與偵錯上。一.
  • 深度學習「CV」實踐指南!
    故其可以與opencv或pillow結合使用,只需要傳入像素值矩陣,matplotlib便可以接手處理接下來想要完成的操作。PIL即Python Imaging Library,而pillow是PIL的一個分支。pillow提供了常見的圖像讀取和處理的操作,它比opencv更為輕巧,且可以與ipython notebook無縫集成。