熱線電話:0755-23712116
郵箱:contact@legoupos.cn
地(di)址:深圳(zhen)市寶(bao)安區沙井街道后亭茅(mao)洲(zhou)山工(gong)業(ye)園工(gong)業(ye)大(da)廈(sha)全至(zhi)科技(ji)創新園科創大(da)廈(sha)2層2A

仿射變換(huan)和透視(shi)變換(huan)更直(zhi)觀的叫法可以(yi)叫做「平面變換(huan)」和「空(kong)間變換(huan)」或者「二(er)維(wei)(wei)(wei)坐標變換(huan)」和「三維(wei)(wei)(wei)坐標變換(huan)」。一個是(shi)二(er)維(wei)(wei)(wei)坐標(x,y),一個是(shi)三維(wei)(wei)(wei)坐標(x,y,z)。也(ye)就(jiu)是(shi):
仿射(she)變換:


透視變換:






??從另一個角度也能說明三維變換和二維變換的意思,仿射變換的方程組有6個未知數,所以要求解就需要找到3組映射點,三個點剛好確定一個平面。透視變換的方程組有8個未知數,所以要求解就需要找到4組映射點,四個點就剛好確定了一個三維空間。
??仿射變換和透視變換的數學原理也不需要深究,其計算方法為坐標向量和變換矩陣的乘積,換言之就是矩陣運算。在應用層面,放射變換是圖像基于3個固定頂點的變換,如圖1.1所示:

??圖中紅點即為固定頂點,在變換先后固定頂點的像素值不變,圖像整體則根據變換規則進行變換同理,透視變換是圖像基于4個固定頂點的變換,如圖1.2所示:

??在OpenCV中,放射變換和透視變換均有(you)封裝好(hao)的函數,分別(bie)為:
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
與
void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
??兩種變換函數(shu)形式完全相同,因此(ci)以仿射變換為例:
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar()) 參數InputArray src:輸入變換前的圖像; 參數OutputArray dst:輸出變換后圖像,需要初始化一個空矩陣用來保存結果,不用設定矩陣尺寸; 參數Size dsize:設置輸出圖像大小; 參數int flags=INTER_LINEAR:設置插值方式,默認方式為線性插值; 后兩個參數不常用,在此不贅述。
關于生成變換矩陣InputArray M的函數getAffineTransform():
Mat getAffineTransform(const Point2f* src, const Point2f* dst) 參數const Point2f* src:原圖的三個固定頂點 參數const Point2f* dst:目標圖像的三個固定頂點 返回值:Mat型變換矩陣,可直接用于warpAffine()函數 注意,頂點數組長度超過3個,則會自動以前3個為變換頂點;數組可用Point2f[]或Point2f*表示
??示例代碼如下:
//讀取原圖
Mat I = imread("..//img.jpg");
//設置空矩陣用于保存目標圖像
Mat dst;
//設置原圖變換頂點
Point2f AffinePoints0[3] = { Point2f(100, 50), Point2f(100, 390), Point2f(600, 50) };
//設置目標圖像變換頂點
Point2f AffinePoints1[3] = { Point2f(200, 100), Point2f(200, 330), Point2f(500, 50) };
//計算變換矩陣
Mat Trans = getAffineTransform(AffinePoints0, AffinePoints1);
//矩陣仿射變換
warpAffine(I, dst, Trans, Size(I.cols, I.rows));
//分別顯示變換先后圖像進行對比
imshow("src", I);
imshow("dst", dst);
waitKey();??同理,透視變(bian)換與仿(fang)射變(bian)換函(han)數(shu)類似:
void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
??生成(cheng)變換(huan)矩陣函數為:
Mat getPerspectiveTransform(const Point2f* src, const Point2f* dst)
??注意透(tou)視變換頂點為(wei)4個。
??兩種變(bian)換完整代碼及(ji)結果(guo)比較:
#include <iostream>
#include <opencv.hpp>
using namespace std;
using namespace cv;
Mat AffineTrans(Mat src, Point2f* scrPoints, Point2f* dstPoints)
{
Mat dst;
Mat Trans = getAffineTransform(scrPoints, dstPoints);
warpAffine(src, dst, Trans, Size(src.cols, src.rows), CV_INTER_CUBIC);
return dst;
}
Mat PerspectiveTrans(Mat src, Point2f* scrPoints, Point2f* dstPoints)
{
Mat dst;
Mat Trans = getPerspectiveTransform(scrPoints, dstPoints);
warpPerspective(src, dst, Trans, Size(src.cols, src.rows), CV_INTER_CUBIC);
return dst;
}
void main()
{
Mat I = imread("..//img.jpg"); //700*438
Point2f AffinePoints0[4] = { Point2f(100, 50), Point2f(100, 390), Point2f(600, 50), Point2f(600, 390) };
Point2f AffinePoints1[4] = { Point2f(200, 100), Point2f(200, 330), Point2f(500, 50), Point2f(600, 390) };
Mat dst_affine = AffineTrans(I, AffinePoints0, AffinePoints1);
Mat dst_perspective = PerspectiveTrans(I, AffinePoints0, AffinePoints1);
for (int i = 0; i < 4; i++)
{
circle(I, AffinePoints0[i], 2, Scalar(0, 0, 255), 2);
circle(dst_affine, AffinePoints1[i], 2, Scalar(0, 0, 255), 2);
circle(dst_perspective, AffinePoints1[i], 2, Scalar(0, 0, 255), 2);
}
imshow("origin", I);
imshow("affine", dst_affine);
imshow("perspective", dst_perspective);
waitKey();
}