OpenCV实现仿射变换
什么是仿射变换?¶
一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移).
综上所述, 我们能够用仿射变换来表示:
- 旋转 (线性变换)
- 平移 (向量加)
- 缩放操作 (线性变换)
你现在可以知道, 事实上, 仿射变换代表的是两幅图之间的 关系 .
定义一些需要用到的变量, 比如需要用来储存中间和目标图像的Mat和两个需要用来定义仿射变换的二维点数组.
Point2f srcTri[3];
Point2f dstTri[3]; Mat rot_mat( 2, 3, CV_32FC1 );
Mat warp_mat( 2, 3, CV_32FC1 );
Mat src, warp_dst, warp_rotate_dst;加载源图像:
src = imread( argv[1], 1 );
以与源图像同样的类型和大小来对目标图像初始化:
warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
仿射变换: 正如上文所说, 我们需要源图像和目标图像上分别一一映射的三个点来定义仿射变换:
srcTri[0] = Point2f( 0,0 );
srcTri[1] = Point2f( src.cols - 1, 0 );
srcTri[2] = Point2f( 0, src.rows - 1 ); dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );你可能想把这些点绘出来以获得对变换的更直观感受. 他们的位置大概就是在上面图例中的点的位置 (原理部分). 你会注意到由三点定义的三角形的大小和方向改变了.
通过这两组点, 我们能够使用OpenCV函数 getAffineTransform 来求出仿射变换:
warp_mat = getAffineTransform( srcTri, dstTri );
我们获得了用以描述仿射变换的 2X3 矩阵 (在这里是 warp_mat)
将刚刚求得的仿射变换应用到源图像
warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
函数有以下参数:
- src: 输入源图像
- warp_dst: 输出图像
- warp_mat: 仿射变换矩阵
- warp_dst.size(): 输出图像的尺寸
这样我们就获得了变换后的图像! 我们将会把它显示出来. 在此之前, 我们还想要旋转它...
旋转: 想要旋转一幅图像, 你需要两个参数:
- 旋转图像所要围绕的中心
- 旋转的角度. 在OpenCV中正角度是逆时针的
- 可选择: 缩放因子
我们通过下面的代码来定义这些参数:
Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
double angle = -50.0;
double scale = 0.6;我们利用OpenCV函数 getRotationMatrix2D 来获得旋转矩阵,
这个函数返回一个 2X3 矩阵 (这里是 rot_mat)rot_mat = getRotationMatrix2D( center, angle, scale );
现在把旋转应用到仿射变换的输出.
warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
最后我们把仿射变换和旋转的结果绘制在窗体中,源图像也绘制出来以作参照:
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src ); namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
imshow( warp_window, warp_dst ); namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
imshow( warp_rotate_window, warp_rotate_dst );等待用户退出程序
waitKey(0);
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h> using namespace cv;
using namespace std; /// 全局变量
char* source_window = "Source image";
char* warp_window = "Warp";
char* warp_rotate_window = "Warp + Rotate"; /** @function main */
int main( int argc, char** argv )
{
Point2f srcTri[3];
Point2f dstTri[3]; Mat rot_mat( 2, 3, CV_32FC1 );
Mat warp_mat( 2, 3, CV_32FC1 );
Mat src, warp_dst, warp_rotate_dst; /// 加载源图像
src = imread( argv[1], 1 ); /// 设置目标图像的大小和类型与源图像一致
warp_dst = Mat::zeros( src.rows, src.cols, src.type() ); /// 设置源图像和目标图像上的三组点以计算仿射变换
srcTri[0] = Point2f( 0,0 );
srcTri[1] = Point2f( src.cols - 1, 0 );
srcTri[2] = Point2f( 0, src.rows - 1 ); dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 ); /// 求得仿射变换
warp_mat = getAffineTransform( srcTri, dstTri ); /// 对源图像应用上面求得的仿射变换
warpAffine( src, warp_dst, warp_mat, warp_dst.size() ); /** 对图像扭曲后再旋转 */ /// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
double angle = -50.0;
double scale = 0.6; /// 通过上面的旋转细节信息求得旋转矩阵
rot_mat = getRotationMatrix2D( center, angle, scale ); /// 旋转已扭曲图像
warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() ); /// 显示结果
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src ); namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
imshow( warp_window, warp_dst ); namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
imshow( warp_rotate_window, warp_rotate_dst ); /// 等待用户按任意按键退出程序
waitKey(0); return 0;
}
说明¶
OpenCV实现仿射变换的更多相关文章
- 【转】【opencv】仿射变换
仿射变换 目标 在这个教程中你将学习到如何: 使用OpenCV函数 warpAffine 来实现一些简单的重映射. 使用OpenCV函数 getRotationMatrix2D 来获得一个 旋转矩阵 ...
- opencv 图像仿射变换 计算仿射变换后对应特征点的新坐标 图像旋转、缩放、平移
常常需要最图像进行仿射变换,仿射变换后,我们可能需要将原来图像中的特征点坐标进行重新计算,获得原来图像中例如眼睛瞳孔坐标的新的位置,用于在新得到图像中继续利用瞳孔位置坐标. 仿射变换在:http:// ...
- OpenCV图像变换(仿射变换与透视变换)
仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...
- 【OpenCV新手教程之十八】OpenCV仿射变换 & SURF特征点描写叙述合辑
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/33320997 作者:毛星云(浅墨) ...
- 计算机视觉2D几何基元及其变换介绍和OpenCV WarpPerspective源码分析
2D图像几何基元 一般的,表示一个2d几何基元只用两个维度(比如x,y)就可以表示了,但是在计算机视觉研究中,为了统一对2d几何基元的操作(后面讲到的仿射,透射变换),一般会以增广矢量的方式表示几何基 ...
- EasyPR--开发详解(5)颜色定位与偏斜扭转
本篇文章介绍EasyPR里新的定位功能:颜色定位与偏斜扭正.希望这篇文档可以帮助开发者与使用者更好的理解EasyPR的设计思想. 让我们先看一下示例图片,这幅图片中的车牌通过颜色的定位法进行定位并从偏 ...
- EasyPR--开发详解
我正在做一个开源的中文车牌识别系统,Git地址为:https://github.com/liuruoze/EasyPR. 我给它取的名字为EasyPR,也就是Easy to do Plate Reco ...
- opencv 用户文档 错误更正 仿射变换
今天在看opencv官方给出的仿射变换计算仿射变换矩阵的文档的时候,发现官方文档中有个很明显的错误,再次给大家提个醒. 官方文档连接: http://opencv.willowgarage.com/d ...
- OpenCV探索之路(八):重映射与仿射变换
重映射 重映射就是把一幅图像中某个位置的像素放置到另一个图片中指定位置的过程. 用一个数学公式来表示就是: 其中的 f 就是映射方式,也就说,像素点在另一个图像中的位置是由 f 来计算的. 在Open ...
随机推荐
- eval和列表解析的一处陷阱
>>> def f(): a=1 return [i+a for i in range(3)] >>> f() [1, 2, 3] >>> def ...
- cassandra 监控方案评估
摘要 最开始做cassandra monitor 方案的选型时,主要是从cassandra 本身入手,后来发现cassandra运行在JVM上,所有的metrics都是通过JMX 暴露出来.所以又可以 ...
- Android 玩转IOC,Retfotit源码解析,教你徒手实现自定义的Retrofit框架
CSDN:码小白 原文地址: http://blog.csdn.net/sk719887916/article/details/51957819 前言 Retrofit用法和介绍的文章实在是多的数不清 ...
- Spring之Enterprise JavaBeans (EJB) integration
原文地址:需要FQ https://translate.google.com/translate?hl=zh-CN&sl=zh-CN&tl=zh-CN&u=http%3A%2F ...
- Android简易实战教程--第二十四话《画画板》
今天完成一个画画板. 首先来个布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android ...
- 对LCS算法及其变种的初步研究
LCS的全称为Longest Common Subsequence,用于查找两个字符串中的最大公共子序列,这里需要注意区分子序列与子串,所谓子序列,指的是从前到后,可以跳跃元素筛选,而字串则必须连续筛 ...
- 【编程练习】最近准备开始找工作,这篇文章作为一个code练手题目的总结吧
找工作时候一般需要准备的算法题目类型,其实参考leetcode和poj或者剑指offer基本能够摆平大部分的题目了 1.图的遍历,BFS.DFS: 2.递归的回溯剪枝: 3.树的建立和遍历: 4.状态 ...
- 用API给用户添加职责
DECLARE lc_user_name VARCHAR2(100) := 'PRAJ_TEST'; lc_resp_appl_short_name VARCHAR2(100) := 'FND' ...
- 剑指Offer——二分查找算法
剑指Offer--二分查找算法 前言 本片博文主要讲解查找算法的相关知识.重点介绍二分查找. 二分查找算法是在有序数组中用到的较为频繁的一种查找算法,在未接触二分查找算法时,最通用的一种做法是,对数组 ...
- Dynamics CRM 2015Online Update1 new feature之表单页Tabs切换
CRM2011的界面相对于CRM4.0进行了比较大的改动,N久没见过4.0的界面了所以忘了表单是什么样子的了,但2011的表单中若含有多个tab的话,是可以通过左侧栏进行切换,话说2013的界面相对2 ...