今天要整理的笔记是关于图像的透视变换的内容。

首先需要了解什么是透视变换,这里引用百度百科上的内容:

透视变换(Perspective Transformation)是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。

emmmmmm从严谨的定义来看的话,可能会有一点点抽象,那么具体到图像方面的透视变换呢,其实可以理解成将同一物体在某一视角所成的像,变换到另一个视角所成的像。

假设我们使用多个摄像头在不同的视角对目标物体进行拍摄成像,那么这里形成的多张图像虽然包含的是同一个目标物体的信息,但是它们具有不同的视平面。那么将某一幅图像中的内容变换到另一幅图像中的内容,也就是将目标物体从一个摄像头的视平面转换到另一个摄像头的视平面,这就是对于图像的透视变换。
我们也可以说是将图像投影到一个新的视平面,所以透视变换也被称为投影变换。

透视变换经常用在图像矫正、全景拼接等场景,尤其是对于很多的文本扫描图像,有时候会因为放置的原因、或者是拍摄角度的原因而导致文本区域倾斜,这就影响了后续的文本分析识别工作,因此需要把类似这样不合视角要求的图像矫正为正确的、合适的视角,以方便下一步的布局分析与文字识别等工作。

对于图像的透视变换,其实说到底就是矩阵的变换,因为对于计算机而言,图像就是一个矩阵,只不过其数据具有一定的规范而已。对于两个矩阵之间的变换,我们需要找到他们之间具有的联系,也就是第三个矩阵——变换矩阵(单应矩阵)。我们通过这个变换矩阵,对输入的矩阵进行计算,得到的就是输出的变换完成后的矩阵。

那么具体到两张图像,输入图像是原始视角图像,输出图像就是透视变换后的另一视角图像。首先我们需要找到在这两张图像上的对应点集,然后计算这些对应点之间的联系,也就是一个变换矩阵,再使用这个变换矩阵去对输入的整幅图像进行计算,得到矫正后的图像。这就完成了一次图像的透视变换。

这个过程可以总结为:
1、寻找对应点集,也就是需要变换的区域;
2、计算对应点集之间的变换矩阵;
3、将对应点集之间的变换矩阵应用到两幅图像中;
4、完成图像的整体变换。

那么,其中非常重要的就是如何计算对应点集之间的变换矩阵,在OpenCV中提供了一个API来计算两个点集之间的3x3变换矩阵(单应矩阵),那就是findHomography(),其主要参数如下:
第一个参数src_point:原视平面的点集
第二个参数dst_point:目标视平面的点集
第三个参数method:计算变换矩阵的方式,有以下几种选择(在这里选用默认值即可,但是RANSAC和RHO相对来说很更常用一些):
(1)0 - 利用所有点的常规方法
(2)RANSAC - RANSAC - 基于RANSAC的鲁棒算法
(3)LMEDS - 最小中值鲁棒算法
(4)RHO - PROSAC - 基于PROSAC的鲁棒算法
后面的参数是和RANSAC与RHO这两种变换方法相关的,使用默认值即可。

通过这个API我们就能得到对应点集之间变换矩阵(单应矩阵),然后再通过warpPerspective()这个API完成将图像从一个视平面映射到另一个视平面的透视变换操作。
warpPerspective()这个API可以说是非常的见名知义了,函数名warpPerspective这个单词本身就是“透视”的意思。其参数如下:
第一个参数src:输入的需要透视变换的图像;
第二个参数dst:输出的透视变换后的图像;
第三个参数M: 先前得到的3x3 变换矩阵(单应矩阵);
第四个参数dsize:输出图像的尺寸;
第五个参数flsg:插值方式,默认值即可;
第六个参数borderMode:边界填充方式,默认值即可;
第七个参数borderValue:常量边界时的填充值,默认值即可。

下面是具体代码:

 //读取图像并进行预处理,将要矫正的区域提取出来Mat test_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\case1r.png");imshow("test_image", test_image);Mat binary_image, gray_image;cvtColor(test_image, gray_image, COLOR_BGR2GRAY);threshold(gray_image, binary_image, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);imshow("binary_image", binary_image);//轮廓发现vector<vector<Point>> contours;findContours(binary_image, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//寻找最大面积轮廓,也就是要进行矫正的区域轮廓vector<float> area;for (int i = 0; i < contours.size(); i++){area.push_back(contourArea(contours[i]));               //包含所有轮廓面积的集合}//获得最大面积轮廓的索引,获得的索引必须为二维数组[ col , row ]double minVal, maxVal;int minIdx[2], maxIdx[2];           //maxIdx中的row坐标即为最大面积轮廓的索引minMaxIdx(area, &minVal, &maxVal, minIdx, maxIdx);          RotatedRect min_rect = minAreaRect(contours[maxIdx[1]]);           //面积最大轮廓的最小外接旋转矩形//获取该矩形的尺寸int width = min_rect.size.width;int height = min_rect.size.height;//获取该矩形的四个点,获取顺序为:从右下角的点开始,顺时针获取各点Point2f min_rect_point[4];min_rect.points(min_rect_point);//将获取得到的四个Point2f类型的顶点转换为Point类型后存放到一个点向量中vector<Point> src_point;for (int j = 0; j < 4; j++){int x = min_rect_point[j].x;int y = min_rect_point[j].y;src_point.push_back(Point(x, y));}//定义要透视变换到的视平面,由四个顶点确定;存放顶点顺序决定透视变换时的方向vector<Point> dst_point;dst_point.push_back(Point(0, height));dst_point.push_back(Point(0, 0));dst_point.push_back(Point(width, 0));dst_point.push_back(Point(width, height));//计算对应点的 3x3 变换矩阵Mat M = findHomography(src_point, dst_point);//进行整幅图像的透视变换Mat result;warpPerspective(test_image, result, M, Size(width, height));imshow("result", result);

在上述代码中,使用了一张倾斜的文档图像,如下图:

我们要完成的效果就是将这份文档给矫正到正常的视角上来,所以需要先找到定位到这份文档的区域。我们使用二值分析来把最外层的边框给提取出来,然后再通过轮廓分析,来获取最大面积轮廓以及这个最大轮廓的最小外接旋转矩形的四个顶点。其二值图像如下:

接着将得到的这四个顶点,与我们需要转换到的视平面上的四个顶点进行对应,通过这两个视平面上的对应点集来获得变换矩阵(单应矩阵)。

最后将这个变换矩阵(单应矩阵)应用到整幅图像上,得到我们的最终结果图,效果如下图所示:

可以看到,我们成功的把文档该矫正到了正常视角上了,需要注意的是,我们进行透视变换时的输出尺寸选择的是最大轮廓的最小外接矩的宽和高,如果直接使用整幅图像的高和宽,就会将图像中的不感兴趣区域也进行透视变换了,输出结果中除了矫正后的文档,还会有其他的干扰元素。

今天的笔记整理到此结束,谢谢阅读~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

OpenCV4学习笔记(30)——透视变换(投影变换)相关推荐

  1. OpenCV4学习笔记(76)——基于ArUco模块+QT实现增强现实(AR)

    在<OpenCV4学习笔记(75)>中,整理记录了对于一副静态图像如何实现一个简单的增强现实效果,今天我们就结合ArUco模块和QT来实现对于实时视频流的AR效果. 我们需要先创建一个QT ...

  2. OPENCV-4 学习笔记

    OPENCV-4 学习笔记 ROI-设定感兴趣的区域(region of interest) 定义: Mat imageROI; //方法一:通过Rect指定矩形区域 imageROI=image(R ...

  3. OpenCV4学习笔记(57)——基于GrabCut图像分割算法实现背景替换与背景虚化效果

    在上一篇笔记<OpenCV4学习笔记(56)>中,整理了关于在OpenCV中使用GrabCut图像分割算法的相关内容,那么本次笔记就以GrabCut算法为基础来实现对图像的背景替换和背景虚 ...

  4. OpenCV4学习笔记(55)——基于KNN最近邻算法实现鼠标手写数字识别

    在上一篇博客<OpenCV4学习笔记(54)>中,整理了关于KNN最近邻算法的一些相关内容和一个手写体数字识别的例子.但是上次所实现的手写体数字识别,每次只能固定地输入测试图像进行预测,而 ...

  5. OpenCV4学习笔记(41)——ORB特征提取描述算法

    今天要整理记录的笔记内容是特征算法中比较常用的一种--ORB特征提取描述算法,顾名思义,ORB算法包含了对特征点的提取和描述这两个部分.而在上次的博文<OpenCV4学习笔记(39)>中, ...

  6. OpenCV4学习笔记(47)——BRISK特征提取描述算法

    今天要整理记录的是OpenCV中BRISK特征提取描述算法的运用. BRISK特征提取描述算法全称为 Binary Robust Invariant Scalable Keypoints(二进制鲁棒不 ...

  7. 影像组学视频学习笔记(30)-SMOTE解决数据不平衡的问题、Li‘s have a solution and plan.

    本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(30)主要介绍: SMOTE解决数据不平衡的问题 SMOTE基本介绍 SMOTE (Synthetic Minority Over-sa ...

  8. Flash/Flex学习笔记(30):不用startDrag和stopDrag的对象拖动

    对于从Sprite类继承来的对象,要实现拖放当然是Flash/Flex学习笔记(13):对象拖动(startDrag/stopDrag) 里讲的方法最方便,但是对于不是从Sprite类继承得来的对象, ...

  9. OpenCV4学习笔记(23)——几何矩、中心矩、归一化矩和Hu矩的计算,以及基于Hu矩的轮廓匹配

    在上次的笔记中,整理记录了有关轮廓发现及轮廓信息提取的一部分内容,同时还记录了Hu矩的计算方式,今天就来记录一下Hu矩的一个应用--轮廓匹配. 在<OpenCV学习笔记(19)--模板匹配> ...

最新文章

  1. Dremel - Interactive Analysis of WebScale Datasets
  2. python 深拷贝_python 深拷贝
  3. html5 自动生成迷宫,HTML5 Canvas随机迷宫生成动画
  4. 北航微软提出新型数据集TableBank,从图像中检测和识别表格
  5. 前端常用插件、工具类库汇总,新手必收藏!!!
  6. LuoguP1041 传染病控制
  7. Git学习笔记(九) 历史穿梭
  8. mysql_query is deprecated_Function mysql_db_query() is deprecated 错误解决
  9. 3D打印行业入行总结
  10. 用计算机刻盘,电脑怎么刻盘_怎么将电脑桌面的文件刻录到cd光盘
  11. android通过webview调起支付宝app支付
  12. [论文笔记] SSE-PT: Sequential Recommendation Via Personalized Transformed
  13. Halcon找圆系列(4)测量圆直径/半径的方法之暴力拟合法 vs 测量工具法
  14. deepin 15.11安装postgresql
  15. 两个服务器组虚拟机,linux 两台虚拟机
  16. R语言学习记录:聚类分析的R实现
  17. 冷冻大脑、量产蟋蟀...全球最聪明的人一起开脑洞是什么样?
  18. Linux centos7 搭建k8s集群步骤详解
  19. 该爬破解验证码,爬企信宝必须破解滑块验证
  20. 快速排序 java cutoff_排序之 快速排序

热门文章

  1. Ubuntu系统下利用anaconda创建虚拟环境
  2. python气象绘图速成_Python气象绘图教程(十六)—Cartopy_6
  3. 我的世界粘土服务器的虚拟键盘,我的世界boat全键盘版
  4. 浅谈百度地图的简单开发之结合方向传感器实现定位功能(三)
  5. 【设计模式学习笔记】组合模式与桥接模式案例详解(C++实现)
  6. uni.getLocation获取位置失败
  7. java 实现重定义数组类似于VB的ReDim
  8. 安化云台山风景区——我心底的桃花源
  9. MySQL如何自定义函数
  10. python爬虫豆瓣电影短评_【Python爬虫】BeautifulSoup爬取豆瓣电影短评