读书笔记-opencv-投影变换

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/aaron1996123456/article/details/100898850

读书笔记-opencv-投影变换

原理解析

​ 透视变换是将图片投影到一个新的视平面,也称作投影映射.它是二维(x,y)到三维(X,Y,Z),再到另一个二维(x′,y′)空间的映射.相对于仿射变换,它提供了更大的灵活性,将一个四边形区域映射到另一个四边形区域(不一定是平行四边形).它不止是线性变换.但也是通过矩阵乘法实现的,使用的是一个3x3的矩阵,矩阵的前两行与仿射矩阵相(m11,m12,m13,m21,m22,m23),也实现了线性变换和平移,第三行用于实现透视变换
在这里插入图片描述

​ 在公式两边同时除以m33,得到一个有关8个未知数的方程组,只需要四个点就可以求出相关系数。
具体的推理过程,可以参见单应性变换,透视变换相关帖子。

代码示例

​ opencv提供相关的函数:

cv2.getPerspectiveTransform(src, dst)

​ 其中src是变换前坐标,dst是变换后的坐标,返回33的矩阵src和dst是4 * 2的二维ndarry,数据必须为32位浮点型

python实例

src_points = np.array([[165., 270.], [835., 270.], [360., 125.], [615., 125.]], np.float32)
dst_points = np.array([[165., 270.], [835., 270.], [165., 30.], [835., 30.]], dtype = "float32")
M = cv2.getPerspectiveTransform(src_points, dst_points)

print(M)

​ 返回矩阵M是float64的数据类型

​ 对图片进行处理

if __name__ == "__main__":
	image_path = "c:\\users\\pictures\\saved pictures\\1.jpg"
	image = cv2.imread(image_path)

	#原图的宽高
	h,w = image.shape[:2]

	#原图的四个点与投影变换对应的点
	src = np.array([[0.0, 0.0],[w-1, 0], [0, h-1], [w-1, h-1]], np.float32)
	dst = np.array([[50, 50], [w/3, 50], [50, h-1], [w-1, h-1]], np.float32)

	#计算投影变换矩阵
	p = cv2.getPerspectiveTransform(src, dst)

	#利用计算出来的投影变换矩阵计算图像的投影变换
	r = cv2.warpPerspective(image, p, (w,h), borderValue=125)

	#显示原图和投影效果
	cv2.imshow("image", image);
	cv2.imshow("warpPersperctive", r)

	cv2.waitKey(0)
	cv2.destroyAllWindows()

​ 结果处理的图片:
在这里插入图片描述

C++实例

//method 1
//原矩阵
	Point2f src[] = { Point2f(0,0), Point2f(200.0, 0), Point2f(0,200.0), Point2f(200.0, 200.0) };
	//投影变换后的矩阵
	Point2f dst[] = { Point2f(100.0, 20.0), Point2f(200.0, 20.0), Point2f(50, 70), Point2f(250.0, 70.0) };

	//投影变换矩阵
	Mat M = getPerspectiveTransform(src, dst);

//method 2
//原矩阵
	Mat src = (Mat_<float>(4, 2) << 0, 0, 200, 0, 0, 200, 200, 200);
	//投影变换后的矩阵
	Mat dst = (Mat_<float>(4, 2) << 100, 20, 200, 20, 50, 70, 250, 70);
	//投影变换矩阵
	Mat M = getPerspectiveTransform(src, dst);

对图片进行处理:

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui_c.h> 
#include<iostream>
#include<string>
using namespace cv;

/************************************************************************/
/* 注意CV_EVENT_LBUTTONDOWN需要加载头文件 <opencv2/highgui/highgui_c.h> 
void circle(Mat & img, Point center, int radius, const Scalar & color, int thickness = 1, int lineType = 8, int shift = 0
该函数在途中用来画圆, img 代表输入图像, center代表圆心,color代表颜色, thickness代表线条的粗细, linetype线的类型,
opencv还提供rectangle, ellipse,line在图上画相应的线段*/
/************************************************************************/

Mat InitImage;					//原图
Mat convertImage;				//转换后的图像

Point2f IPoint, pIPoint;
int i = 0, j = 0;
Point2f src[4];					//存储原坐标
Point2f dst[4];					//存储对应的变换的坐标

//通过以下鼠标事件,在要原图上面取四个坐标
/**
* @鼠标点击事件
* @return void
*/
void mouse_I(int event, int x, int y, int flags, void *param)
{
	switch (event)
	{
		//记录左键
	case CV_EVENT_LBUTTONDOWN:
		IPoint = Point2f(x, y);					//记录坐标
		break;
	case CV_EVENT_LBUTTONUP:
		src[i] = IPoint;
		circle(InitImage, src[i], 7, Scalar(0), 3);		//标记
		i += 1;
		break;
	default:
		break;
	}
}

//通过以下鼠标事件,在要输出的画布上面取四个对应坐标
/**
* @鼠标点击事件,在要输出的画布上面取四个对应坐标
* @return void
*/
void mouse_pI(int event, int x, int y, int flags, void *param)
{
	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN:
		pIPoint = Point2f(x, y);
		break;
	case CV_EVENT_LBUTTONUP:
		dst[j] = pIPoint;
		circle(convertImage, dst[j], 7, Scalar(0), 3);
		j += 1;
		break;
	default:
		break;
	}
}


int main()
{
	//加载图片,imread(),第二个参加代表以何种方式加载,具体可以看Opencv的imread()函数解析
	std::string iamgePath = "C:\\Users\\huangxin\\Pictures\\Saved Pictures\\1.jpg";
	InitImage = imread(iamgePath, 1);

	if (!InitImage.data)
	{
		return -1;
	}

	//输出图像
	convertImage = 255 * Mat::ones(InitImage.size(), CV_8UC1);
	//在原图定义,鼠标事件
	namedWindow("InitImage", 1);
	setMouseCallback("InitImage", mouse_I, NULL);
	//在输出窗口定义,鼠标事件
	namedWindow("ConvertImage", 1);
	setMouseCallback("ConvertImage", mouse_pI, NULL);

	imshow("InitImage", InitImage);
	imshow("ConvertImage", convertImage);

	while (!(i == 4 && j == 4))
	{
		imshow("InitImage", InitImage);
		imshow("ConvertImage", convertImage);
		if (waitKey(50) == 'q')
		{
			break;
		}
	}

	imshow("InitImage", InitImage);
	imshow("ConvertImage", convertImage);

	//移除鼠标事件
	setMouseCallback("InitImage", NULL, NULL);
	setMouseCallback("ConvertImage", NULL, NULL);

	//计算投影变换矩阵
	Mat p = getPerspectiveTransform(src, dst);

	//投影变化
	Mat resultMat;
	warpPerspective(InitImage, resultMat, p, convertImage.size());

	imshow("result: ", resultMat);
	

	waitKey(0);
	return 0;

}

​ 在原图点击四个点,作为输入矩阵,在convertImage上面点击四个点作为输出矩阵,通过两个矩阵建立投影变换矩阵。

​ 处理的结果图片:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/aaron1996123456/article/details/100898850
今日推荐