天天看點

C++_opencv透視變換應用—摳圖和換廣告牌

一、透視變換簡介

透視變換作用:将圖檔映射到一個新的視平面,也稱為投影映射。

透視變換和仿射變換的差別:

(1)、仿射變換後還是平行四邊形,透視變換後是四邊形, 可以說仿射變換是透視變換的一個子集。仿射變換,它可以将矩形轉換成平行四邊形,也可以将矩形的邊壓扁但必須保持邊是平行的,也可以将矩形旋轉或者按比例縮放。透視變換除了能夠處理仿射變換的操作外,還可以将矩形轉換成梯形。

(2)、在OpenCV中,基于2*3矩陣進行的變換,是圖像的仿射變換;基于3*3矩陣進行的變換,是圖像的透視變換或者單應性映射。圖像透視變換多用于圖像校正

C++_opencv透視變換應用—摳圖和換廣告牌

來自《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)摳出來的小圖;

C++_opencv透視變換應用—摳圖和換廣告牌
C++_opencv透視變換應用—摳圖和換廣告牌

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)換成功的圖

C++_opencv透視變換應用—摳圖和換廣告牌

參考連結:

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

感謝部落客 

繼續閱讀