欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

读书笔记-opencv-投影变换

程序员文章站 2023-12-27 09:02:39
...

读书笔记-opencv-投影变换

原理解析

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

​ 在公式两边同时除以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()

​ 结果处理的图片:
读书笔记-opencv-投影变换

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上面点击四个点作为输出矩阵,通过两个矩阵建立投影变换矩阵。

​ 处理的结果图片:
读书笔记-opencv-投影变换

相关标签: opencv 透视变换

上一篇:

下一篇: