转自:

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

在上篇的博文中,我们重点讨论了基于霍夫变换的线段和圆检测。其实在图像的变换中,还有一部分是几何操作,这些操作包括各种方式的拉伸,包括一致性缩放和非一致性缩放(即扭曲)。对于平面区域,有两种方式的几何转换:一种是基于2×3矩阵进行的变换,叫仿射变换;另一种是基于3×3矩阵进行的变换,叫透视变换或者单应性映射。关于仿射变换和透射变换的矩阵变换,这篇博文不做重点讨论,因为图像本质就是矩阵,对矩阵的变换就是对图像像素的操作,很简单的数学知识。

仿射变换可以形象的表示成以下形式。一个平面内的任意平行四边形ABCD可以被仿射变换映射为另一个平行四边形A’B’C’D’。通俗的解释就是,可以将仿射变换想象成一幅图像画到一个胶版上,在胶版的角上推或拉,使其变形而得到不同类型的平行四边形。相比较仿射变换,透射变换更具有灵活性,一个透射变换可以将矩形转变成梯形。如下图: 

下面关于OpenCV中进行仿射变换和透射变换的函数进行介绍下:

//仿射变换函数
void cvWarpAffine(const CvArr* src,//输入图像CvArr* dst,//输出图像const CvMat* map_matrix,//2×3变换矩阵->传个矩阵进来?int flags=CV_INTER_LINEAR|CV_WARP_FILL_OUTLIERS,//插值方法CvScalar fillval=cvScalarAll(0)
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

从上面的函数中,我们可以看到其中需要传进去一个2×3变换矩阵,因此我们在调用cvWarpAffine()函数之前,要计算仿射映射矩阵,因此在OpenCV中有函数cvGetAffineTransform()来计算仿射映射矩阵。

CvMat* cvGetAffineTransform(const CvPoint2D32f* pts_src,const CvPoint2D32f* pts_dst,//src,dst三个二维点(x,y)的数组CvMat* map_matrix//得到的仿射映射矩阵参数
)
  • 1
  • 2
  • 3
  • 4
  • 5

下面给出这个仿射变换的完整程序示例:

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;int main()
{//数组声明CvPoint2D32f srcTri[3], dstTri[3];//创建指针CvMat* warp_mat = cvCreateMat(2, 3, CV_32FC1);CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1);//载入和显示图像IplImage *src;src = cvLoadImage("1.jpg", CV_LOAD_IMAGE_UNCHANGED);cvNamedWindow("原图", CV_WINDOW_AUTOSIZE);cvShowImage("原图", src);IplImage *dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);dst=cvCloneImage(src);dst->origin = src->origin;cvZero(dst);//计算变换矩阵srcTri[0].x = 0;srcTri[0].y = 0;srcTri[1].x = src->width - 1;srcTri[1].y = 0;srcTri[2].x = 0;srcTri[2].y = src->height - 1;dstTri[0].x = src->width*0.0;dstTri[0].y = src->height*0.33;dstTri[1].x = src->width*0.85;dstTri[1].y = src->height*0.25;dstTri[2].x = src->width*0.15;dstTri[2].y = src->height*0.7;cvGetAffineTransform(srcTri, dstTri, warp_mat);//调用函数cvWarpAffine()cvWarpAffine(src, dst, warp_mat);cvNamedWindow("仿射图1", CV_WINDOW_AUTOSIZE);cvShowImage("仿射图1", dst);cvCopy(dst, src);//用另外一种方法得到变换矩阵,并进行仿射变换CvPoint2D32f center = cvPoint2D32f(src->height / 2, src->width / 2);double angle = -50.0;double scale =- 0.6;cv2DRotationMatrix(center, angle, scale, rot_mat);cvWarpAffine(src, dst, rot_mat);cvNamedWindow("仿射图2", CV_WINDOW_AUTOSIZE);cvShowImage("仿射图2", dst);cvWaitKey();cvReleaseImage(&src);cvReleaseImage(&dst);cvDestroyWindow("原图");cvDestroyWindow("仿射图1");cvDestroyWindow("仿射图2");cvReleaseMat(&rot_mat);cvReleaseMat(&warp_mat);return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

程序运行的结果为下图: 

透视变换的函数和得到透视映射矩阵的函数同仿射变换没有太大区别,主要是仿射变换用到的是2×3矩阵,而透视变换用到的是3×3矩阵,关于函数的细节,在这里我就不做细致的介绍了,下面就直接给出程序示例:

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;int main()
{//数组声明CvPoint2D32f srcTri[4], dstTri[4];//创建数组指针CvMat *warp_mat = cvCreateMat(3, 3, CV_32FC1);IplImage *src, *dst;//载入和显示图像src = cvLoadImage("1.jpg", CV_LOAD_IMAGE_UNCHANGED);cvNamedWindow("原图", CV_WINDOW_AUTOSIZE);cvShowImage("原图", src);dst = cvCloneImage(src);dst->origin = src->origin;cvZero(dst);//构造变换矩阵srcTri[0].x = 0;srcTri[0].y = 0;srcTri[1].x = src->width - 1;srcTri[1].y = 0;srcTri[2].x = 0;srcTri[2].y = src->height - 1;srcTri[3].x = src->width - 1;srcTri[3].y = src->height - 1;dstTri[0].x = src->width*0.05;dstTri[0].y = src->height*0.33;dstTri[1].x = src->width*0.9;dstTri[1].y = src->height*0.25;dstTri[2].x = src->width*0.2;dstTri[2].y = src->height*0.7;dstTri[3].x = src->width*0.8;dstTri[3].y = src->height*0.9;//计算透视映射矩阵cvGetPerspectiveTransform(srcTri, dstTri, warp_mat);//调用函数cvWarpPerspective()cvWarpPerspective(src, dst, warp_mat);//显示透视变换后的图像cvNamedWindow("透视变换", CV_WINDOW_AUTOSIZE);cvShowImage("透视变换", dst);cvWaitKey();cvReleaseImage(&src);cvReleaseImage(&dst);cvDestroyWindow("原图");cvDestroyWindow("透视变换");cvReleaseMat(&warp_mat);return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

最后运行的结果如下: 

另外可以参考:【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑

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

  1. opencv 仿射变换与透视变换详解

    常见的2D图像变换从原理上讲主要包括基于2×3矩阵的仿射变换和基于3×3矩阵透视变换. 仿射变换 原理 基本的图像变换就是二维坐标的变换:从一种二维坐标(x,y)到另一种二维坐标(u,v)的线性变换: ...

  2. opencv仿射变换和透视变换门牌号实践总结

    前几日在门牌号识别优化过程中发现当摄像头拍摄角度倾斜或者相机仰头拍摄出来的门牌号发生了畸变,即使能够找到门牌号区域也大大降低了识别的准确度,因此想到了倾斜矫正--仿射变换和透视变换,关于这两个概念网上 ...

  3. z变换判断稳定性和因果性_图像处理的仿射变换与透视变换

    原文首发于微信公众号:[3D视觉工坊]. 引言 这一周主要在研究图像的放射变换与透视变换,目前出现的主要问题是需要正确识别如下图中的编码标志点圆心. 1.当倾斜角较小时: 倾斜角较小 2.倾斜角较大时 ...

  4. 图像处理的仿射变换与透视变换

    引言   这一周主要在研究图像的放射变换与透视变换,目前出现的主要问题是需要正确识别如下图中的编码标志点圆心. 1.当倾斜角较小时: 2.倾斜角较大时:   由上面两幅图可以看出,当倾斜角较大时,中间 ...

  5. 图像处理之_仿射变换与透视变换

    1.      仿射变换 1) 用途 旋转 (线性变换),平移 (向量加).缩放(线性变换),错切,反转 2) 方法 仿射变换是一种二维坐标到二维坐标之间的线性变换,它保持了二维图形的"平直 ...

  6. 仿射变换与透视变换区别

    仿射变换 1) 用途 旋转 (线性变换),平移 (向量加).缩放(线性变换),错切,反转 2) 方法 仿射变换是一种二维坐标到二维坐标之间的线性变换,它保持了二维图形的"平直性"( ...

  7. opencv:畸变矫正:透视变换算法的思想与实现

    畸变矫正 注意:虽然能够成功矫正但是也会损失了部分图像! 透视变换(Perspective Transformation) 概念: 透视变换是将图片投影到一个新的视平面(Viewing Plane), ...

  8. 相机标定(四)—— 仿射变换和透视变换

    仿射变换和透视变换 0. 概述 1. 线性变换 2. 从代数角度看线性变换 3. 仿射变换 4. 从代数角度看仿射变换 5. 通过线性变换来完成仿射变换 6. 仿射变换的一系列原子变换 6.1 平移变 ...

  9. python怎么让x轴45°展示_python opencv实现任意角度的透视变换实例代码

    本文主要分享的是一则python+opencv实现任意角度的透视变换的实例,具体如下: # -*- coding:utf-8 -*- import cv2 import numpy as np def ...

  10. OpenCV学习:仿射变换+投射变换+单应性矩阵

    OpenCV学习:仿射变换+投射变换+单应性矩阵 estimateRigidTransform():计算多个二维点对或者图像之间的最优仿射变换矩阵 (2行x3列),H可以是部分自由度,比如各向一致的切 ...

最新文章

  1. 1560F1. Nearest Beautiful Number (easy version)
  2. aws rds监控慢sql_探索AWS RDS SQL Server上SQL Server集成服务(SSIS)
  3. 使用Ext Designer 设计简单计算器
  4. 计算机第二道启动密码怎么设置,电脑一道密码怎么设置
  5. 百万数据查询优化技巧三十则
  6. scala下载和环境搭建
  7. Python API接口压力测试简单实现(并发测试)
  8. 认证协议RADIUS篇
  9. Android入门之本地音乐播放器
  10. 【资料】分享北京某培训机构全部学习课程加个人的一些学习上的建议
  11. Windows 11正式版来了!一文带你免费升级、镜像下载、最低系统要求
  12. pandas - 时间天数计算-实现excel中IF(ROUNDDOWN(),,)函数
  13. Debian搭建SVN服务器
  14. Transformer Architectures and Pre-training Strategies for Fast and Accurate Multi-sentence Scoring
  15. KafkaConsumer is not safe for multi-threaded access
  16. 计算机毕业设计ssm临沂旅游咨询系统
  17. Redis之Vs Memcached
  18. iOS获取设备的唯一标识的方法
  19. 电视android已停止运行是什么意思,智能电视提示应用停止运行,三种方法亲测有效!...
  20. 慧数汽车大数据洞察:汽车垂直媒体的现状与趋势

热门文章

  1. 27. 二叉搜索树与双向链表(C++版本)
  2. Ajax方法详解以及多个Ajax并发执行
  3. FISCO BCOS(五)———部署安装jdk1.8
  4. php动态添加属性,php – Yii2.动态添加属性和规则到模型
  5. layUI:垂直导航栏点击某个导航时关闭其他已开启导航
  6. SQL:pgsql查询一段时间内每个小时的首条数据,为空返回0
  7. Cesium:实现漫游飞行
  8. 数据抓取的艺术(三)
  9. e2e_cli遇坑记录
  10. 自动驾驶高精地图-概述与分析