天天看點

opencv C艹:圖像拼接,尺寸變換,仿射,透視,極坐标變換

圖像變換

調整圖像尺寸,翻轉,旋轉

圖像拼接

将兩個具有相同高度或寬度的圖像連接配接一起,

縱向拼接
void cv::vconcat	(	const Mat * 	src,  // 存放Mat類型的數組,列數相同,資料類型通道數相同
						size_t 	nsrc,  // 數組中含有的Mat類型的數目,
						OutputArray 	dst  // 輸出結果
)

void cv::vconcat	(	InputArray 	src1,  // 對兩個Mat類型的資料進行連接配接。
InputArray 	src2,
OutputArray 	dst 
)

橫向拼接
void cv::hconcat	(	const Mat * 	src,
						size_t 	nsrc,
						OutputArray 	dst 
)

void cv::hconcat	(	InputArray 	src1,  // 
InputArray 	src2,
OutputArray 	dst 
)	


#include <opencv2\opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	//矩陣數組的橫豎連接配接
	Mat matArray[] = { Mat(1, 2, CV_32FC1, cv::Scalar(1)),  
								  Mat(1, 2, CV_32FC1, cv::Scalar(2)) };
	Mat vout, hout;
	vconcat(matArray, 2, vout);
	cout << "圖像數組豎向連接配接:" << endl << vout << endl;
	hconcat(matArray, 2, hout);
	cout << "圖像數組橫向連接配接:" << endl << hout << endl;

	//矩陣的橫豎拼接
	Mat A = (cv::Mat_<float>(2, 2) << 1, 7, 2, 8);
	Mat B = (cv::Mat_<float>(2, 2) << 4, 10, 5, 11);
	Mat vC, hC;
	vconcat(A, B, vC);
	cout << "多個圖像豎向連接配接:" << endl << vC << endl;
	hconcat(A, B, hC);
	cout << "多個圖像橫向連接配接:" << endl << hC << endl;

	//讀取4個子圖像,00表示左上角、01表示右上角、10表示左下角、11表示右下角
	Mat img00 = imread("lena00.png");
	Mat img01 = imread("lena01.png");
	Mat img10 = imread("lena10.png");
	Mat img11 = imread("lena11.png");
	if (img00.empty() || img01.empty() || img10.empty() || img11.empty())
	{
		cout << "請确認圖像檔案名稱是否正确" << endl;
		return -1;
	}
	//顯示4個子圖像
	imshow("img00", img00);
	imshow("img01", img01);
	imshow("img10", img10);
	imshow("img11", img11);

	//圖像連接配接
	Mat img, img0, img1;
	//圖像橫向連接配接
	hconcat(img00, img01, img0);
	hconcat(img10, img11, img1);
	//橫向連接配接結果再進行豎向連接配接
	vconcat(img0, img1, img);

	//顯示連接配接圖像的結果
	imshow("img0", img0);
	imshow("img1", img1);
	imshow("img", img);
	waitKey(0);
	return 0;
}
           

尺寸變換

改變長和寬,實作圖像的縮放。

void cv::resize	(	InputArray 	src,
					OutputArray 	dst,
					Size 	dsize,   // 輸出圖像的尺寸
					double 	fx = 0,  // 水準的比例因子,兩倍就是2
					double 	fy = 0,  // 以dsize為準
					int 	interpolation = INTER_LINEAR  // 插值方法
)	
           
opencv C艹:圖像拼接,尺寸變換,仿射,透視,極坐标變換

縮小圖像,用INTER_AREA , 放大圖像 INTER_CUBIC OR INTER_LINEAR。

void cv::flip(InputArray src, // 圖像翻轉
			OutputArray dst,
			int flipCode // 大于0 ,y軸翻轉 ,等于0 x軸翻轉, 小于0兩個軸翻轉
			}

#include <opencv2\opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat gray = imread("lena.png", 0);
	Mat smallImg, bigImg0, bigImg1, bigImg2;
	resize(gray, smallImg, Size(15, 15), 0, 0, INTER_AREA);  // 先縮小
	resize(smallImg, bigImg0, Size(30, 30), 0, 0, INTER_NEAREST);  //最近鄰內插補點
	resize(smallImg, bigImg1, Size(30, 30), 0, 0, INTER_LINEAR);  //雙線性內插補點
	resize(smallImg, bigImg2, Size(30, 30), 0, 0, INTER_CUBIC);  //雙三次內插補點
	namedWindow("smallImg", 0);  //圖像尺寸太小,一定要設定可以調節視窗大小标志
	imshow("smallImg", smallImg);
	namedWindow("bigImg0", 0);
	imshow("bigImg0", bigImg0);
	namedWindow("bigImg1", 0);
	imshow("bigImg1", bigImg1);
	namedWindow("bigImg2", 0);
	imshow("bigImg2", bigImg2);

	Mat img_x, img_y, img_xy;
	flip(gray, img_x, 0);       // 圖像翻轉,x, y, xy軸對稱
	flip(gray, img_y, 1);
	flip(gray, img_xy, -1);
	imshow("img_xy", img_xy);
	
	waitKey(0);
	return 0;
}
           

圖像放射變換

圖像的旋轉,通過仿射實作。首先确定旋轉角度和中心,确定旋轉矩陣,進行仿射變換。

Mat cv::getRotationMatrix2D	(	Point2f 	center, // 旋轉中心位置
								double 	angle, // 角度,機關度,正值逆時針旋轉
								double 	scale  // 兩個軸的比例因子,實作圖像的縮放
)	// 傳回旋轉矩陣,Mat類型
           
opencv C艹:圖像拼接,尺寸變換,仿射,透視,極坐标變換

得到旋轉矩陣後,通過warpAffine() 函數進行仿射變換,實作旋轉。

void cv::warpAffine	(	InputArray 	src,
						OutputArray 	dst,  // 結果圖,類型與輸入相同,尺寸與dsize相同
						InputArray 	M,  // 得到的旋轉矩陣
						Size 	dsize,
						int 	flags = INTER_LINEAR, // 插值方式
						int 	borderMode = BORDER_CONSTANT, //像素邊界外推方式
						const Scalar & 	borderValue = Scalar() // 填充邊界的值,預設0
)	
           
opencv C艹:圖像拼接,尺寸變換,仿射,透視,極坐标變換

仿射變換就是旋轉,平移,縮放操作的總稱,可以表示為線性變換和平移變換的疊加。數學表達就是先乘以一個線性變換矩陣(2 X 2),然後加上一個平移向量(2X1)。是以輸入一個(2X3)的變換矩陣。

M = [ A B ] = ∣ a 00 a 01 b 00 a 10 a 11 b 10 ∣ 像 素 值 [ x , y ] T T = A [ x y ] + B M = [A\quad B]= \left\vert\begin{matrix} a_{00} & a_{01} & b_{00} \\ a_{10} & a_{11} & b_{10} \end{matrix} \right\vert 像素值[x,y]^T \qquad T = A\left[\begin{matrix}x\\y\end{matrix}\right] + B M=[AB]=∣∣∣∣​a00​a10​​a01​a11​​b00​b10​​∣∣∣∣​像素值[x,y]TT=A[xy​]+B

如果知道變換後兩幅圖像中3個像素點坐标的對應關系,就可以求得變換矩陣M,getAffineTransform()利用三個對應的像素點确定M。

Mat cv::getAffineTransform	(	const Point2f 	src[], // 原圖像的3個像素坐标,與順序無關
								const Point2f 	dst[] 
)	


int main()
{
	Mat img = imread("lena.png");

	Mat rotation0, rotation1, img_warp0, img_warp1;
	double angle = 30;  //設定圖像旋轉的角度
	Size dst_size(img.rows, img.cols);  //設定輸出圖像的尺寸
	Point2f center(img.rows / 2.0, img.cols / 2.0);  //設定圖像的旋轉中心
	rotation0 = getRotationMatrix2D(center, angle, 1);  //計算放射變換矩陣
	warpAffine(img, img_warp0, rotation0, dst_size);  //進行仿射變換
	imshow("img_warp0", img_warp0);
	//根據定義的三個點進行仿射變換
	Point2f src_points[3];
	Point2f dst_points[3];
	src_points[0] = Point2f(0, 0);  //原始圖像中的三個點,三個角
	src_points[1] = Point2f(0, (float)(img.cols - 1));
	src_points[2] = Point2f((float)(img.rows - 1), (float)(img.cols - 1));
	dst_points[0] = Point2f((float)(img.rows)*0.11, (float)(img.cols)*0.20);  //放射變換後圖像中的三個點
	dst_points[1] = Point2f((float)(img.rows)*0.15, (float)(img.cols)*0.70);
	dst_points[2] = Point2f((float)(img.rows)*0.81, (float)(img.cols)*0.85);
	rotation1 = getAffineTransform(src_points, dst_points);  //根據對應點求取仿射變換矩陣
	warpAffine(img, img_warp1, rotation1, dst_size);  //進行仿射變換
	imshow("img_warp1", img_warp1);
	waitKey(0);
	return 0;
}
           

透視變換

将物體投影到新的平面。透視前後的變換關系可以使用一個 3X3 的變換矩陣表示,這個矩陣可以通過兩幅圖像中4 個對應點的坐标求取。getPerspectiveTransform() warpPerspective() 分别用于擷取矩陣,進行透視變換。

Mat cv::getPerspectiveTransform	(	const Point2f 	src[],
									const Point2f 	dst[],
									int 	solveMethod = DECOMP_LU // 預設就行
)		


void cv::warpPerspective	(	InputArray 	src,
								OutputArray 	dst,
								InputArray 	M,   // 3X3的變換矩陣
								Size 	dsize,   // 輸出圖像的尺寸
								int 	flags = INTER_LINEAR,  // 與仿射參數一樣
								int 	borderMode = BORDER_CONSTANT,
								const Scalar & 	borderValue = Scalar() 
)	
	Point2f src_points[4];
	Point2f dst_points[4];
	//通過Image Watch檢視的二維碼四個角點坐标
	src_points[0] = Point2f(94.0, 374.0);
	src_points[1] = Point2f(507.0, 380.0);
	src_points[2] = Point2f(1.0, 623.0);
	src_points[3] = Point2f(627.0, 627.0);
	//期望透視變換後二維碼四個角點的坐标
	dst_points[0] = Point2f(0.0, 0.0);
	dst_points[1] = Point2f(627.0, 0.0);
	dst_points[2] = Point2f(0.0, 627.0);
	dst_points[3] = Point2f(627.0, 627.0);
	Mat rotation, img_warp;
	rotation = getPerspectiveTransform(src_points, dst_points);  //計算透視變換矩陣
	warpPerspective(img, img_warp, rotation, img.size());  //透視變換投影
           

極坐标變換

直角坐标系和極坐标系中的變換,可以将一個圓形圖像變成一個矩形圖像。可以處理鐘表,圓盤等,圓形圖案邊緣上的文字經過極坐标變換後可以垂直的排列在新圖像的邊緣,便于對文字進行識别和檢測。

void cv::warpPolar	(	InputArray 	src,
						OutputArray 	dst,
						Size 	dsize,
						Point2f 	center,  // 極坐标的原點坐标
						double 	maxRadius, // 變換時邊界圓的半徑,決定了逆變換時的比例參數
						int 	flags // 插值方法,與極坐标映射方法标志,兩個方法通過+ |連接配接
)	
           
opencv C艹:圖像拼接,尺寸變換,仿射,透視,極坐标變換
int main()
{
	Mat img = imread("dial.png");

	Mat img1, img2;
	Point2f center = Point2f(img.cols / 2, img.rows / 2);  //極坐标在圖像中的原點
	//正極坐标變換
	warpPolar(img, img1, Size(300, 600), center, center.x, INTER_LINEAR + WARP_POLAR_LINEAR);
	//逆極坐标變換
	warpPolar(img1, img2, Size(img.rows, img.cols), center, center.x, 
				INTER_LINEAR + WARP_POLAR_LINEAR + WARP_INVERSE_MAP);

	imshow("原表盤圖", img);
	imshow("表盤極坐标變換結果", img1);
	imshow("逆變換結果", img2);
	waitKey(0);
	return 0;
}
           
opencv C艹:圖像拼接,尺寸變換,仿射,透視,極坐标變換

繼續閱讀