一、透視變換簡介
透視變換作用:将圖檔映射到一個新的視平面,也稱為投影映射。
透視變換和仿射變換的差別:
(1)、仿射變換後還是平行四邊形,透視變換後是四邊形, 可以說仿射變換是透視變換的一個子集。仿射變換,它可以将矩形轉換成平行四邊形,也可以将矩形的邊壓扁但必須保持邊是平行的,也可以将矩形旋轉或者按比例縮放。透視變換除了能夠處理仿射變換的操作外,還可以将矩形轉換成梯形。
(2)、在OpenCV中,基于2*3矩陣進行的變換,是圖像的仿射變換;基于3*3矩陣進行的變換,是圖像的透視變換或者單應性映射。圖像透視變換多用于圖像校正

來自《Learning OpenCV》一書中的插圖
二、透視變換應用
0、簡單實作
(1)提供原圖像和目标圖像的4對點;
(2)使用getPerspectiveTransform(srcTri, dstTri)函數計算出透視變換的3*3的矩陣
(3)使用函數warpPerspective()對原圖執行透視變換,得到變換後的圖像。
1、摳圖代碼:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
struct userdata {
Mat im;
vector<Point2f> points;
};
void mouseHandle(int event, int x, int y, int flags, void* ptr)
{
if (event == EVENT_LBUTTONDOWN)
{
userdata* data = (userdata*)ptr;
circle(data->im, Point(x, y), 3, Scalar(0, 0, 255), 3, cv::LINE_AA);
imshow("dst", data->im);
if (data->points.size() < 4)
{
data->points.push_back(Point2f(x, y));
}
}
}
//透視變換之 摳圖應用
int main()
{
Mat Image = imread("C:/Users/qxq/Pictures/ad.jpg");
imshow("Image", Image);
//設定輸出的點為四個,即後面用滑鼠點選的點會取前四個,圍成一個多邊形。
Mat result = Mat::zeros(300, 500, CV_8UC3);
//隻實作4個點的情況
vector<Point2f> obj;
obj.push_back(Point2f(0, 0));
obj.push_back(Point2f(result.cols-1, 0));
obj.push_back(Point2f(result.cols-1, result.rows-1));
obj.push_back(Point2f(0, result.rows-1));
Mat dst = Image.clone();
userdata data;
data.im = dst;
imshow("dst", dst);
cout << "滑動滑鼠,順時針選擇4個點,選好後按enter" << endl;
setMouseCallback("dst", mouseHandle, &data);
waitKey(0);
Mat H = findHomography(data.points, obj, cv::RANSAC);
warpPerspective(Image, result, H, result.size());
imshow("result", result);
waitKey(0);
}
效果:(1)選擇的4個點;(2)摳出來的小圖;
2、實作換廣告牌
代碼實作:
/****************************
* 實作虛拟廣告牌的效果。
* 提供兩張圖,一張是目标圖,另外一張是帶廣告牌的原圖,請用單應矩陣實作将原圖中廣告牌替換為提供的笑臉圖的效果。
* 利用OpenCV函數,通過滑鼠點選來選擇要替換的廣告牌的四個頂點。
****************************/
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
struct userdata {
Mat im;
vector<Point2f> points;
};
void mouseHandler(int event, int x, int y, int flags, void* data_ptr)
{
if (event == EVENT_LBUTTONDOWN)
{
userdata* data = (userdata*)data_ptr;
circle(data->im, Point(x, y), 3, Scalar(0, 255, 255), 5, cv::LINE_AA);
imshow("Image", data->im);
if (data->points.size() < 4)
{
data->points.push_back(Point2f(x, y));
}
}
}
int main(int argc, char** argv)
{
Mat im_src = imread("C:/Users/qxq/Pictures/2.jpg");
Size size = im_src.size();
// Create a vector of points.
vector<Point2f> pts_src;
pts_src.push_back(Point2f(0, 0));
pts_src.push_back(Point2f(size.width - 1, 0));
pts_src.push_back(Point2f(size.width - 1, size.height - 1));
pts_src.push_back(Point2f(0, size.height - 1));
// Destination image
Mat im_dst = imread("C:/Users/qxq/Pictures/ad.jpg");
// Set data for mouse handler
Mat im_temp = im_dst.clone();
userdata data;
data.im = im_temp;
//show the image
imshow("Image", im_temp);
cout << "Click on four corners of a billboard and then press ENTER" << endl;
//set the callback function for any mouse event,依次點選圖檔上的四個點
setMouseCallback("Image", mouseHandler, &data);
waitKey(0);
// ---------- 開始你的代碼 --------------
// 計算原圖四個角點和目标圖區域對應角點的 Homography
Mat Homography = findHomography(pts_src, data.points); // 計算多個二維點對之間的最優單映射變換矩陣 H
// 用H對原圖做變換(與src圖像的角度相同)
warpPerspective(im_src, im_temp, Homography, im_temp.size());
// 提取滑鼠點選的四個角點
Point pts_dst[4];
for (int i = 0; i < 4; i++)
{
pts_dst[i] = data.points[i];
}
// 把目标圖中對應區域像素值設定為0
fillConvexPoly(im_dst, pts_dst, 4, Scalar(0), cv::LINE_AA); //填充凸多邊形
// 把原圖疊加到目标圖上
im_dst = im_dst + im_temp;
imshow("Image", im_dst);
imwrite("../Image.jpg", im_dst);
waitKey(0);
return 0;
}
效果圖:(1)選擇點的圖(2)換成功的圖
參考連結:
https://xiaohu.blog.csdn.net/article/details/100745097?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-5.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-5.control
https://blog.csdn.net/ganbelieve/article/details/91996326?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control
感謝部落客