opencv学习(三十五)之仿射变换warpAffine
1.仿射變換介紹
仿射變換是指在向量空間中進行一次線性變換(乘以一個矩陣)并加上一個平移(加上一個向量),變換為另一個向量空間的過程。在有限維的情況下,每個仿射變換可以由一個矩陣A和一個向量b給出,它可以寫作A和一個附加的列b。一個仿射變換對應于一個矩陣和一個向量的乘法,而仿射變換的復合對應于普通的矩陣乘法,只要加入一個額外的行到矩陣的底下,這一行全部是0除了最右邊是一個1,而列向量的底下要加上一個1.
Affine Transform描述了一種二維仿射變換的功能,它是一種二維坐標之間的線性變換,保持二維圖形的“平直性”(即變換后直線還是直線,圓弧還是圓弧)和“平行性”(其實是保持二維圖形間的相對位置關系不變,平行線還是平行線,而直線上的點位置順序不變,另特別注意向量間夾角可能會發生變化)。仿射變換可以通過一系列的原子變換的復合來實現包括:平移(Translation)、縮放(Scale)、翻轉(Flip)、旋轉(Rotation)和錯切(Shear).
事實上,仿射變換代表的是兩幅圖之間的關系,我們通常使用2x3矩陣來表示仿射變換如下:
考慮到我們要使用矩陣A和B對二維向量做變換,所以也能表示為下列形式:
或
得到如下結果:
2.仿射變換求法
從上面解釋中我們得知仿射變換表示的就是兩幅圖片的一種聯系,關于這種聯系的信息大致可以從以下兩種場景獲得。
a. 我們已知X和T而且我們知道他們是有聯系的,接下來的工作就是求解矩陣M
b. 我們一致M和X要求得T,我們只需要應用算式T=M.X即可。對于這種聯系的信息可以用矩陣M清晰的表達(即給出明確的2x3矩陣)或者也可以用兩幅圖片點之間幾何關系來表達。
因為矩陣M聯系著兩幅圖片,我們以其表示兩圖中各三點直接的聯系為例,如下:
點1,2和3(在圖一中形成一個三角)與圖二中三個點一一映射,仍然形成三角形,但形狀已經大大改變。如果我們能通過這樣兩組三點求出仿射變換(你能選擇自己喜歡的點),接下來我們就能把仿射變換應用到圖像中所有的點。
3.opencv實現仿射變換
利用opencv實現仿射變換一般會涉及到warpAffine和getRotationMatrix2D兩個函數,其中warpAffine可以實現一些簡單的重映射,而getRotationMatrix2D可以獲得旋轉矩陣。
warpAffine函數
參數解釋
. src: 輸入圖像
. dst: 輸出圖像,尺寸由dsize指定,圖像類型與原圖像一致
. M: 2X3的變換矩陣
. dsize: 指定圖像輸出尺寸
. flags: 插值算法標識符,有默認值INTER_LINEAR,如果插值算法為WARP_INVERSE_MAP, warpAffine函數使用如下矩陣進行圖像轉換
常用的插值算法如下:
. borderMode: 邊界像素模式,有默認值BORDER_CONSTANT
. borderValue: 邊界取值,有默認值Scalar()即0
getRotationMatrix2D函數
Mat cv::getRotationMatrix2D ( Point2f center,double angle,double scale )參數解釋
. center: Point2f類型,表示原圖像的旋轉中心
. angle: double類型,表示圖像旋轉角度,角度為正則表示逆時針旋轉,角度為負表示逆時針旋轉(坐標原點是圖像左上角)
. scale: 縮放系數
函數計算如下矩陣:
其中
示例代碼
#include <iostream> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp>using namespace std; using namespace cv;//全局變量 String src_windowName = "原圖像"; String warp_windowName = "仿射變換"; String warp_rotate_windowName = "仿射旋轉變換"; String rotate_windowName = "圖像旋轉";int main() {Point2f srcTri[3];Point2f dstTri[3];Mat rot_mat(2, 3, CV_32FC1);Mat warp_mat(2, 3, CV_32FC1);Mat srcImage, warp_dstImage, warp_rotate_dstImage, rotate_dstImage;//加載圖像srcImage = imread("dog.jpg");//判斷文件是否加載成功if(srcImage.empty()){cout << "圖像加載失敗!" << endl;return -1;}elsecout << "圖像加載成功!" << endl << endl;//創建仿射變換目標圖像與原圖像尺寸類型相同warp_dstImage = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type());//設置三個點來計算仿射變換srcTri[0] = Point2f(0, 0);srcTri[1] = Point2f(srcImage.cols - 1, 0);srcTri[2] = Point2f(0, srcImage.rows - 1);dstTri[0] = Point2f(srcImage.cols*0.0, srcImage.rows*0.33);dstTri[1] = Point2f(srcImage.cols*0.85, srcImage.rows*0.25);dstTri[2] = Point2f(srcImage.cols*0.15, srcImage.rows*0.7);//計算仿射變換矩陣warp_mat = getAffineTransform(srcTri, dstTri);//對加載圖形進行仿射變換操作warpAffine(srcImage, warp_dstImage, warp_mat, warp_dstImage.size());//計算圖像中點順時針旋轉50度,縮放因子為0.6的旋轉矩陣Point center = Point(warp_dstImage.cols/2, warp_dstImage.rows/2);double angle = -50.0;double scale = 0.6;//計算旋轉矩陣rot_mat = getRotationMatrix2D(center, angle, scale);//旋轉已扭曲圖像warpAffine(warp_dstImage, warp_rotate_dstImage, rot_mat, warp_dstImage.size());//將原圖像旋轉warpAffine(srcImage, rotate_dstImage, rot_mat, srcImage.size());//顯示變換結果namedWindow(src_windowName, WINDOW_AUTOSIZE);imshow(src_windowName, srcImage);namedWindow(warp_windowName, WINDOW_AUTOSIZE);imshow(warp_windowName, warp_dstImage);namedWindow(warp_rotate_windowName, WINDOW_AUTOSIZE);imshow(warp_rotate_windowName, warp_rotate_dstImage);namedWindow(rotate_windowName, WINDOW_AUTOSIZE);imshow(rotate_windowName, rotate_dstImage);waitKey(0);return 0; }運行結果
總結
以上是生活随笔為你收集整理的opencv学习(三十五)之仿射变换warpAffine的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哈工大 软件构造Lab1的设计实现
- 下一篇: 分享文章:如何提高你的学习能力,也许对你