基於OpenCV的圖像幾何變換小結 (仿射變換爲主)

參考:https://blog.csdn.net/keith_bb/article/details/56331356

圖片位移

    可手寫代碼實現矩陣搬移操作。

    也可使用仿射變換方法進行操作:

    例如,仿射矩陣可寫爲:

        [[1 0 100]

        [0 1 200]]     ,即表示x位移100y位移200像素點。

圖片縮放

        1、放大、縮小,使用cv.resize(src,(new,newH))

        2、常用的插值算法如下: 

              i.最近鄰域插值:選最近的點複製即可。

              ii.雙線性插值:

                     首先計算A1A2B1B2 。然後計算目標點(可根據A1 A2計算,也可根據B1B2計算)

圖片仿射

1、圖片仿射變換(位移+旋轉+縮放):

        仿射變換是指在向量空間中進行一次線性變換(乘以一個矩陣)並加上一個平移(加上一個向量),變換爲另一個向量空間的過程。在有限維的情況下,每個仿射變換可以由一個矩陣A和一個向量b給出,它可以寫作A和一個附加的列b。一個仿射變換對應於一個矩陣和一個向量的乘法,而仿射變換的複合對應於普通的矩陣乘法,只要加入一個額外的行到矩陣的底下,這一行全部是0除了最右邊是一個1,而列向量的底下要加上一個1.Affine Transform描述了一種二維仿射變換的功能,它是一種二維座標之間的線性變換,保持二維圖形的平直性”(即變換後直線還是直線,圓弧還是圓弧)平行性”(其實是保持二維圖形間的相對位置關係不變,平行線還是平行線,而直線上的點位置順序不變,另特別注意向量間夾角可能會發生變化)。仿射變換可以通過一系列的原子變換的複合來實現包括:平移(Translation)、縮放(Scale)、翻轉(Flip)、旋轉(Rotation)和錯切(Shear). 事實上,仿射變換代表的是兩幅圖之間的關係,我們通常使用2x3矩陣來表示仿射變換如下:

        考慮到我們要使用矩陣AB對二維向量做變換X=[x y]T

        得到如下結果:

2.仿射變換求法

        從上面解釋中我們得知仿射變換表示的就是兩幅圖片的一種聯繫,關於這種聯繫的信息大致可以從以下兩種場景獲得。 

a. 我們已知XT而且我們知道他們是有聯繫的,接下來的工作就是求解矩陣

b. 我們一致MX要求得T,我們只需要應用算式T=M·X即可。對於這種聯繫的信息可以用矩陣M清晰的表達(即給出明確的2x3矩陣)或者也可以用兩幅圖片點之間幾何關係來表達。 

        因爲矩陣M聯繫着兩幅圖片,我們以其表示兩圖中各三點直接的聯繫爲例,如下


       點1,23(在圖一中形成一個三角)與圖二中三個點一一映射,仍然形成三角形,但形狀已經大大改變。如果我們能通過這樣兩組三點求出仿射變換(你能選擇自己喜歡的點),接下來我們就能把仿射變換應用到圖像中所有的點。

openCV中有直接根據三個邊界點計算轉換矩陣的函數:

M = cv.getAffineTransform(matSrc_3Point,matDst_3Point)

3.opencv實現仿射變換

利用opencv實現仿射變換一般會涉及到warpAffinegetRotationMatrix2D兩個函數,其中warpAffine可以實現一些簡單的重映射,而getRotationMatrix2D可以獲得旋轉矩陣M 

getRotationMatrix2D函數

Matcv::getRotationMatrix2D     (   Point2f    center,

        double      angle,

        double      scale

    )  

參數解釋 

. center:Point2f類型,表示原圖像的旋轉中心 
. angle: double類型,表示圖像旋轉角度,角度爲正則表示逆時針旋轉,角度爲負表示逆時針旋轉(座標原點是圖像左上角) 
. scale: 縮放係數 

函數計算如下矩陣: 

 

其中,

 

warpAffine函數

void cv::warpAffine     (   InputArray      src,

        OutputArray     dst,

        InputArray      M,

        Size   dsize,

        int     flags =INTER_LINEAR,

        int     borderMode =BORDER_CONSTANT,

        const Scalar &     borderValue = Scalar()

    )

參數解釋 
. src: 輸入圖像 
. dst: 輸出圖像,尺寸由dsize指定,圖像類型與原圖像一致 
. M: 2X3的變換矩陣 
. dsize: 指定圖像輸出尺寸 

. flags: 插值算法標識符,有默認值INTER_LINEAR,如果插值算法爲WARP_INVERSE_MAP, warpAffine函數使用如下矩陣進行圖像轉換

示例代碼 

#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("D://timg.jpg");

	//判斷文件是否加載成功
	if (srcImage.empty())
	{
		cout << "圖像加載失敗!" << endl;
		return -1;
	}
	else
		cout << "圖像加載成功!" << 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());
	//保存結果圖像
	cv::imwrite("D://仿射後圖像.jpg", warp_dstImage);
	cv::imwrite("D://仿射後旋轉圖像.jpg", warp_rotate_dstImage);
	cv::imwrite("D://原圖像旋轉圖像.jpg", rotate_dstImage);


	//顯示變換結果
	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;
}

原圖:

仿射變換後圖像:


仿射變換後旋轉圖像:

原圖像旋轉後圖像:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章