关闭

【OpenCV3.3】通过透视变换矫正变形图像

11877人阅读 评论(1) 收藏 举报
分类:

        在平面图像处理中,因为镜头角度等原因,容易导致图像出现倾斜、变形等情况,为了方便后续处理我们常常需要进行图像矫正,其中主要技术原理是两种变换类型--仿射变换(Affine Transformation)和透视变换(Perspective Transformation)。

        仿射变换是二维坐标间的线性变换, 故而变换后的图像仍然具有原图的一些性质,包括“平直性”以及“平行性”,常用于图像翻转(Flip)、旋转(Rotations)、平移(Translations)、缩放(Scale operations)等,具体到代码应用可以参见OpenCV官方介绍说句题外话,如果没记错的话,仿射变换在高中数学的选修部分就出现过,它可以解决一些初等几何问题,比如部分椭圆题,使用仿射变换往往能得到优雅解法。
        但是仿射变换不能矫正一些变形,如矩形区域的部分发生变化最终变成梯形,这时候矫正就需要用到透视变换。透视变换(Perspective Transformation),又称投影映射(Projective Mapping)、投射变换等,是三维空间上的非线性变换,可看作是仿射变换的更一般形式,简单讲即通过一个3x3的变换矩阵将原图投影到一个新的视平面(Viewing Plane),在视觉上的直观表现就是产生或消除了远近感。落实到OpenCV,图像的透视变换由以下函数完成(该函数是针对图像的包装,其本质调用cv::perspectiveTransform进行向量坐标的变换):

void cv::warpPerspective (
		InputArray 	src, 
		OutputArray 	dst, 
		InputArray 	M, 
		Size 	dsize, 
		int 	flags = INTER_LINEAR, 
		int 	borderMode = BORDER_CONSTANT, 
		const Scalar &borderValue = Scalar(0))
        其中,src是输入图像,dst是输出图像,M是3x3变换矩阵,dsize是输出图像的大小,flags指定像素插补方法以及矩阵倒置标志cv::WARP_INVERSE_MAP,borderMode指定边沿像素的推算模式,其中BORDER_CONSTANT指示边沿像素用borderValue替换,因为默认是0,所以我们变换后的图像边界可能会出现黑边,此时可以指定BORDER_REPLICATE对边界像素进行复制,即`aaaaaa|abcdefgh|hhhhhhh`(a-h代表像素)。

        当WARP_INVERSE_MAP被指定时,warpPerspective使用输入的矩阵M对图像src进行如下变换(图片来自文档截图):


        否则,方法先计算矩阵M的倒置矩阵T,然后将T应用到上述形式的变换。该变换不能在原地进行(须分配额外空间)。

        关于变换矩阵M,OpenCV提供了两种方法计算,getPerspectiveTransformfindHomography,前者虽然有2个重载函数,但其实都是一样的形式,通过原图和变换后图像的4个对应点(即对应的四边形)计算出透视变换矩阵;后者则相对比较复杂,属于calib3d模块的内容,概括而言即通过变换前、后两个平面的点寻找出一个单应性变换矩阵H,满足,使得反向投影误差最小;这些在计算机视觉相关课程里应有详细介绍。

        下面来看一个具体例子:

static void testImageRectification(cv::Mat &image_original)
{
	CV_SHOW(image_original); // CV_SHOW是cv::imshow的一个自定义宏,忽略即可
	cv::Mat &&image = image_original.clone();

	cv::Mat image_gray;
	cv::cvtColor(image, image_gray, cv::COLOR_BGR2GRAY);
	cv::threshold(image_gray, image_gray, g_threshVal, g_threshMax, cv::THRESH_BINARY);

	std::vector< std::vector<cv::Point> > contours_list; 
	{
		std::vector<cv::Vec4i> hierarchy;
		// Since opencv 3.2 source image is not modified by this function
		cv::findContours(image_gray, contours_list, hierarchy,
						 cv::RetrievalModes::RETR_EXTERNAL, cv::ContourApproximationModes::CHAIN_APPROX_NONE);
	}
	
	for (uint32_t index = 0; index < contours_list.size(); ++index) {
		cv::RotatedRect &&rect = cv::minAreaRect(contours_list[index]);
		if (rect.size.area() > 1000) {
			if (rect.angle != 0.) {
 				// 此处可通过cv::warpAffine进行旋转矫正,本例不需要
			} //if

			cv::Mat &mask = image_gray;
			cv::drawContours(mask, contours_list, static_cast<int>(index), cv::Scalar(255), cv::FILLED);

			cv::Mat extracted(image_gray.rows, image_gray.cols, CV_8UC1, cv::Scalar(0));
			image.copyTo(extracted, mask);
			CV_SHOW(extracted);

			std::vector<cv::Point2f> poly;
			cv::approxPolyDP(contours_list[index], poly, 30, true); // 多边形逼近,精度(即最小边长)设为30是为了得到4个角点
			cv::Point2f pts_src[] = { // 此处顺序调整是为了和后面配对,仅作为示例
				poly[1],
				poly[0],
				poly[3],
				poly[2]
			};
	
			cv::Rect &&r = rect.boundingRect(); // 注意坐标可能超出图像范围
			cv::Point2f pts_dst[] = { 
				cv::Point(r.x, r.y),
				cv::Point(r.x + r.width, r.y),
				cv::Point(r.x + r.width, r.y + r.height) ,
				cv::Point(r.x, r.y + r.height)
			};
			cv::Mat &&M = cv::getPerspectiveTransform(pts_dst, pts_src); // 我这里交换了输入,因为后面指定了cv::WARP_INVERSE_MAP,你可以试试不交换的效果是什么

			cv::Mat warp;cv::warpPerspective(image, warp, M, image.size(), cv::INTER_LINEAR + cv::WARP_INVERSE_MAP, cv::BORDER_REPLICATE);
			CV_SHOW(warp);
		} //if
	}
}
        效果截图(原图变形不明显,将就吧,人眼还是很强大的):
0
0
查看评论

【OpenCV】透视变换 Perspective Transformation(续)

透视变换的原理和矩阵求解请参见前一篇
  • xiaowei_cqu
  • xiaowei_cqu
  • 2014-05-27 09:39
  • 64675

【OpenCV】图像变换(五)-仿射变换和透视变换

在上篇的博文中,我们重点讨论了基于霍夫变换的线段和圆检测。其实在图像的变换中,还有一部分是几何操作,这些操作包括各种方式的拉伸,包括一致性缩放和非一致性缩放(即扭曲)。对于平面区域,有两种方式的几何转换:一种是基于2×3矩阵进行的变换,叫仿射变换;另一种是基于3×3矩阵进行的变换...
  • w12345_ww
  • w12345_ww
  • 2015-04-28 10:28
  • 14235

OpenCV 可自动调整参数的透视变换

转载地址:http://blog.csdn.net/wangyaninglm/article/details/41869535?locationNum=1&fps=1在shiter大牛的基础之上,对于他的程序做了一定的修改。 首先,通过两个循环使得霍夫变换两个参数:角度的分辨率和点个数的阈...
  • zszszs1994
  • zszszs1994
  • 2016-11-22 17:53
  • 1220

【图像处理】透视变换 Perspective Transformation

透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。通用的变换公式为:u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中。变换矩阵可以拆成4部分,表示线性变换,比如...
  • xiaowei_cqu
  • xiaowei_cqu
  • 2014-05-26 13:14
  • 85345

OpenCV 透视变换【图像归一化矫正】

OpenCV 透视变换【扑克牌矫正】                                    ...
  • form88
  • form88
  • 2015-06-19 19:12
  • 4893

OpenCV透视变换

1.什么是透视变换 透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。 2.换算公式 u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中。 变换矩阵...
  • u013498583
  • u013498583
  • 2017-05-12 17:46
  • 623

opencv 透视变换

来看透视变换是想用在 OpenCV 中的,但是由于太懒了,在 Matlab 中实现之后就没有再看,现在终于又看了看 OpenCV 的 API ,感觉比 Matlab 容易一些,在此写出与大家分享,样例图片跟在 Matlab 中的一样,这里就不再贴出来了,如果需要看的话可以看博主的前一篇文章在Matl...
  • huangli19870217
  • huangli19870217
  • 2014-08-18 18:55
  • 645

opencv-ios开发笔记9 使用透视变换矫正扭曲的图片

把摄像头从拍摄的梯形扭曲的图片矫正为正摄图片
  • baixiaozhe
  • baixiaozhe
  • 2016-06-26 12:08
  • 5768

opencv2413透视变换示例代码和图片

  • 2016-10-24 16:17
  • 12KB
  • 下载

图像的仿射变换与透视变换opencv

图像的仿射变换 两个向量空间之间的仿射变换(仿射映射)(Affine Transformation或Affine Map)是由一个线性变换接上一个平移组成。仿射变换可以理解为对坐标进行放缩、旋转、平移后取得的新坐标值,或者是经过坐标的放缩、旋转、平移后原坐标在新坐标领域中的值,可以用以下函数来描述:...
  • u012507022
  • u012507022
  • 2016-12-29 20:23
  • 1704
    联系作者
    通过QQ与我联系(全天候7*24小时基本不在线)
    最新评论
    免责声明
    如果转载的文章侵犯了您的版权,请务必告知,我将立刻删除;
    博客所有文章允许转载,原创类不要求注明出处,随意就好;
    如果是转载的文章,建议直接转载原始来源,因为原作者极可能有更新