opencv的透視變換(投影變換)

主要涉及兩個函數。

第一個,findHomography

計算多個二維點對之間的最優單映射變換矩陣 H(3行x3列) ,使用最小均方誤差或者RANSAC方法。函數功能:找到兩個平面之間的轉換矩陣。

Mat cv::findHomography	(	InputArray 	srcPoints,
                                InputArray 	dstPoints,
                                int 	method = 0,
                                double 	ransacReprojThreshold = 3,
                                OutputArray 	mask = noArray(),
                                const int 	maxIters = 2000,
                                const double 	confidence = 0.995 
)

參數詳解:

srcPoints 源平面中點的座標矩陣,可以是CV_32FC2類型,也可以是vector<Point2f>類型
dstPoints 目標平面中點的座標矩陣,可以是CV_32FC2類型,也可以是vector<Point2f>類型
method 計算單應矩陣所使用的方法。不同的方法對應不同的參數,具體如下:
  • 0 - 利用所有點的常規方法
  • RANSAC - RANSAC-基於RANSAC的魯棒算法
  • LMEDS - 最小中值魯棒算法
  • RHO - PROSAC-基於PROSAC的魯棒算法
ransacReprojThreshold

將點對視爲內點的最大允許重投影錯誤閾值(僅用於RANSAC和RHO方法)。如果

則點被認爲是個外點(即錯誤匹配點對)。若srcPoints和dstPoints是以像素爲單位的,則該參數通常設置在1到10的範圍內。

mask 可選輸出掩碼矩陣,通常由魯棒算法(RANSAC或LMEDS)設置。 請注意,輸入掩碼矩陣是不需要設置的。
maxIters RANSAC算法的最大迭代次數,默認值爲2000。
confidence 可信度值,取值範圍爲0到1.

第二個,warpPerspective

通過輸入變換矩陣得到透視圖片。

void cv::warpPerspective(InputArray src,
		OutputArray dst,
		InputArray M,
		Size dsize,
		int flags = INTER_LINEAR,
		int borderMode = BORDER_CONSTANT,
		const Scalar &borderValue = Scalar() 
	) 	

參數詳解:

src 輸入圖片
dst 輸出圖片
M 輸入的透視變換矩陣,大小是3*3
dsize 輸出圖片的大小
flags 插值方法(INTER_LINEAR或INTER_NEAREST)與可選標誌WARP_INVERSE_MAP的組合,將M設置爲逆變換(𝚍𝚜𝚝→𝚜𝚛𝚌)。
borderMode 邊界像素賦值操作(BORDER_CONSTANT or BORDER_REPLICATE),前者是定值,後者是複製周圍像素。
borderValue 指定定值具體是那個值,默認是0

具體例子

透視變換同時獲取ROI,代碼如下:

#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

struct callbackP
{
	Mat src;
	int clickTimes = 0;        //在圖像上單擊次數
	vector<Point2f> srcTri;
};

void onMouse(int event, int x, int y, int flags, void *utsc)
{
	callbackP cp = *(callbackP*)utsc;  // 先轉換類型,再取數據

	if (event == EVENT_LBUTTONUP)      //響應鼠標左鍵事件
	{
		circle((*(callbackP*)utsc).src, Point(x, y), 2, Scalar(0, 0, 255), 2);  //標記選中點
		imshow("wait ", (*(callbackP*)utsc).src);
		(*(callbackP*)utsc).srcTri.push_back(Point2f(x, y));
		cout << "x:" << x << " " << "y:" << y << endl;
		(*(callbackP*)utsc).clickTimes++;

		if ((*(callbackP*)utsc).clickTimes == 4)
		{
			cout << "按任意鍵繼續!" << endl;
		}
	}
}

int main(int argc, char *argv[])
{
	vector<Point2f> dstTri(4);
	Mat dst;
	callbackP utsc;

	utsc.src = imread("3.jpg");
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", utsc.src);
	cout << "從需要透視變換區域的左上角開始,順時針依次點矩形的四個角!" << endl;
	setMouseCallback("src", onMouse, (void*)&utsc);  //類型轉換
	waitKey();

	if (utsc.clickTimes == 4)
	{
		dstTri[0].x = 0;
		dstTri[0].y = 0;
		dstTri[1].x = utsc.srcTri[1].x - utsc.srcTri[0].x;
		dstTri[1].y = 0;
		dstTri[2].x = utsc.srcTri[1].x - utsc.srcTri[0].x;
		dstTri[2].y = utsc.srcTri[2].y - utsc.srcTri[1].y;
		dstTri[3].x = 0;
		dstTri[3].y = utsc.srcTri[2].y - utsc.srcTri[1].y;

		//計算透視矩陣
		Mat M = findHomography(utsc.srcTri, dstTri, RANSAC);
		//圖像透視變換
		warpPerspective(utsc.src, dst, M, Size((utsc.srcTri[1].x - utsc.srcTri[0].x), (utsc.srcTri[2].y - utsc.srcTri[1].y)));
		imshow("output", dst);
		imwrite("3p.jpg", dst);
		cout << "透視變換矩陣:"<< M << endl;
		waitKey();
	}
	else {
		cout << "需要從左上角開始,順時針依次點矩形的四個角!" << endl;
		cout << "現在點擊了" <<utsc.clickTimes << "次" <<endl;
	}

	return 0;
}

網上隨便找一張圖片,效果如下:注意,用鼠標描點時從左上角開始,順時針依次進行

只進行透視變換,代碼如下:

#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

struct callbackP
{
	Mat src;
	int clickTimes = 0;        //在圖像上單擊次數
	vector<Point2f> srcTri;
};

void onMouse(int event, int x, int y, int flags, void *utsc)
{
	callbackP cp = *(callbackP*)utsc;  // 先轉換類型,再取數據

	if (event == EVENT_LBUTTONUP)      //響應鼠標左鍵事件
	{
		circle((*(callbackP*)utsc).src, Point(x, y), 2, Scalar(0, 0, 255), 2);  //標記選中點
		imshow("wait ", (*(callbackP*)utsc).src);
		(*(callbackP*)utsc).srcTri.push_back(Point2f(x, y));
		cout << "x:" << x << " " << "y:" << y << endl;
		(*(callbackP*)utsc).clickTimes++;

		if ((*(callbackP*)utsc).clickTimes == 4)
		{
			cout << "按任意鍵繼續!" << endl;
		}
	}
}

int main(int argc, char *argv[])
{
	vector<Point2f> dstTri(4);
	Mat dst;
	callbackP utsc;

	utsc.src = imread("3.jpg");
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", utsc.src);
	cout << "從需要透視變換區域的左上角開始,順時針依次點矩形的四個角!" << endl;
	setMouseCallback("src", onMouse, (void*)&utsc);  //類型轉換
	waitKey();

	if (utsc.clickTimes == 4)
	{
		dstTri[0].x = utsc.srcTri[0].x;
		dstTri[0].y = utsc.srcTri[0].y;
		dstTri[1].x = utsc.srcTri[1].x;
		dstTri[1].y = utsc.srcTri[0].y;
		dstTri[2].x = utsc.srcTri[1].x;
		dstTri[2].y = utsc.srcTri[2].y;
		dstTri[3].x = utsc.srcTri[0].x;
		dstTri[3].y = utsc.srcTri[2].y;

		//計算透視矩陣
		Mat M = findHomography(utsc.srcTri, dstTri, RANSAC);
		//圖像透視變換
		warpPerspective(utsc.src, dst, M, utsc.src.size());
		imshow("output", dst);
		imwrite("3pp.jpg", dst);
		cout << "透視變換矩陣:"<< M << endl;
		waitKey();
	}
	else {
		cout << "需要從左上角開始,順時針依次點矩形的四個角!" << endl;
		cout << "現在點擊了" <<utsc.clickTimes << "次" <<endl;
	}

	return 0;
}

效果圖:

參考博客:

https://blog.csdn.net/fengyeer20120/article/details/87798638

https://blog.csdn.net/qq_24946843/article/details/82697364

發佈了75 篇原創文章 · 獲贊 119 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章