1. 程式人生 > 其它 >Affine And Perspective Transform(仿射變換和透視變換)

Affine And Perspective Transform(仿射變換和透視變換)

相關函式

Affine Transform 仿射變換

仿射變換將長方形影象轉化為平行四邊形。

void cv::warpAffine(
 cv::InputArray src, // Input image
 cv::OutputArray dst, // Result image
 cv::InputArray M, // 2-by-3 transform mtx
 cv::Size dsize, // Destination image size
 int flags = cv::INTER_LINEAR, // Interpolation, inverse
 int borderMode = cv::BORDER_CONSTANT, // Pixel extrapolation
 const cv::Scalar& borderValue = cv::Scalar() // For constant borders
);

其中,cv::InputArray M(2x3的轉換矩陣M)通過如下函式獲得

// 方法1 :通過人工設定**3個**原圖上的點 和 對應對映到目標影象的點,求得轉換矩陣。
cv::Mat cv::getAffineTransform( // Return 2-by-3 matrix
 const cv::Point2f* src, // Coordinates *three* of vertices
 const cv::Point2f* dst // Target coords, three vertices
);

//方法2 :設定旋轉中心,旋轉角度,縮放來求轉換矩陣 
cv::Mat cv::getRotationMatrix2D( // Return 2-by-3 matrix
 cv::Point2f center // Center of rotation
 double angle, // Angle of rotation
 double scale // Rescale after rotation
);

通過人工設定3個原圖上的點 和 對應對映到目標影象的點,求得轉換矩陣。該轉換矩陣用以轉換整幅影象。

轉換公式為:

\[dst(x,y) = src(M_{00}x+M_{01}y+M_{02},M_{10}x+M_{11}y+M_{12}) \]

Perspective Transform 透視變換

可以將長方形影象轉化為任意形狀。

void cv::warpPerspective(
 cv::InputArray src, // Input image
 cv::OutputArray dst, // Result image
 cv::InputArray M, // 3-by-3 transform mtx
 cv::Size dsize, // Destination image size
 int flags = cv::INTER_LINEAR, // Interpolation, inverse
 int borderMode = cv::BORDER_CONSTANT, // Extrapolation method
 const cv::Scalar& borderValue = cv::Scalar() // For constant borders
);

求轉化矩陣的函式,原始影象需要選4個點 對映到目標影象

cv::Mat cv::getPerspectiveTransform( // Return 3-by-3 matrix
 const cv::Point2f* src, // Coordinates of *four* vertices
 const cv::Point2f* dst // Target coords, four vertices
);

公式為:

\[dst(x,y) = src\big( \frac{M_{00}x+M_{01}y+M_{02}}{M_{20}x+M_{21}y+M_{22}} , \frac{M_{10}x+M_{11}y+M_{12}}{M_{20}x+M_{21}y+M_{22}}\big) \]

仿射變換和透視變換

流程圖

source code

//learning OpenCV3 11-1 / 11-2
/*
*執行首先出現的圖片是仿射變換
* 按任意鍵執行透視變換
* 再按任意鍵退出
*/

#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace std;

using namespace cv;

int main(int argc,char** argv)
{
	if (argc != 2) {
		cout << "vs在除錯-屬性除錯-除錯-命令引數 輸入影象路徑"
			<< "Clion在編輯執行/除錯對話方塊-配置編輯-程式實參 輸入影象路徑" << endl;
	}
	//1、仿射變換
	Mat imgOrg = imread(argv[1]), imgDis;

	const Point2f srcThreePoints[3] = {
		Point2f(0,0), //左上
		Point2f(imgOrg.cols-1,0), //右上
		Point2f(0,imgOrg.rows-1) //左下
	};
		
	const Point2f disThreePoints[3] = {
		cv::Point2f(imgOrg.cols * 0.f, imgOrg.rows * 0.33f),
		cv::Point2f(imgOrg.cols * 0.85f, imgOrg.rows * 0.25f),
		cv::Point2f(imgOrg.cols * 0.15f, imgOrg.rows * 0.7f)
	};

	Mat m = getAffineTransform(srcThreePoints, disThreePoints);

	warpAffine(imgOrg, imgDis, m, imgOrg.size());

	imshow("imgOrg", imgOrg);
	imshow("imgDis", imgDis);


	for (int i{ 0 }; ; i++) {
		Point2f center(imgOrg.cols * 0.5, imgOrg.rows * 0.5);
		double angle = i * 3 % 360;
		double scale = (cos((angle - 60) * CV_PI / 180) + 1.05) * 0.8;

		Mat M = getRotationMatrix2D(center, angle, scale), imgDisRotate;

		warpAffine(imgOrg,imgDisRotate,M,imgOrg.size());

		imshow("imgDisRotate", imgDisRotate);
		if (waitKey(30) >= 0) { break; }
	}

	//2、透視變換
	Point2f srcFourPoints[4] = {
		cv::Point2f(0, 0),                   // src Top left
		cv::Point2f(imgOrg.cols - 1, 0),          // src Top right
		cv::Point2f(imgOrg.cols - 1, imgOrg.rows - 1), // src Bottom right
		cv::Point2f(0, imgOrg.rows - 1)           // src Bottom left
	};

	cv::Point2f dstFourQuad[] = {
		cv::Point2f(imgOrg.cols * 0.05f, imgOrg.rows * 0.33f),
		cv::Point2f(imgOrg.cols * 0.9f, imgOrg.rows * 0.25f),
		cv::Point2f(imgOrg.cols * 0.8f, imgOrg.rows * 0.9f),
		cv::Point2f(imgOrg.cols * 0.2f, imgOrg.rows * 0.7f)
	};

	Mat m1 = getPerspectiveTransform(srcFourPoints, dstFourQuad),imgPerspective;

	warpPerspective(imgOrg, imgPerspective, m1,imgOrg.size());
	imshow("Perspective", imgPerspective);
	waitKey();

	destroyAllWindows();

	return 0;
}

結果