OpenCV实现仿射变换

什么是仿射变换?

  1. 一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移).
  2. 综上所述, 我们能够用仿射变换来表示:
    1. 旋转 (线性变换)
    2. 平移 (向量加)
    3. 缩放操作 (线性变换)

    你现在可以知道, 事实上, 仿射变换代表的是两幅图之间的 关系 .

 

 

 

#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;
  }

说明

  1. 定义一些需要用到的变量, 比如需要用来储存中间和目标图像的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;
    
  2. 加载源图像:
    src = imread( argv[1], 1 );
    
  3. 以与源图像同样的类型和大小来对目标图像初始化:
    warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
    
  4. 仿射变换: 正如上文所说, 我们需要源图像和目标图像上分别一一映射的三个点来定义仿射变换:
    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 );
    

    你可能想把这些点绘出来以获得对变换的更直观感受. 他们的位置大概就是在上面图例中的点的位置 (原理部分). 你会注意到由三点定义的三角形的大小和方向改变了.

  5. 通过这两组点, 我们能够使用OpenCV函数 getAffineTransform 来求出仿射变换:
    warp_mat = getAffineTransform( srcTri, dstTri );
    

    我们获得了用以描述仿射变换的 2X3 矩阵 (在这里是 warp_mat)

  6. 将刚刚求得的仿射变换应用到源图像
    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
    

    函数有以下参数:

    • src: 输入源图像
    • warp_dst: 输出图像
    • warp_mat: 仿射变换矩阵
    • warp_dst.size(): 输出图像的尺寸

    这样我们就获得了变换后的图像! 我们将会把它显示出来. 在此之前, 我们还想要旋转它...

  7. 旋转: 想要旋转一幅图像, 你需要两个参数:
    1. 旋转图像所要围绕的中心
    2. 旋转的角度. 在OpenCV中正角度是逆时针的
    3. 可选择: 缩放因子

    我们通过下面的代码来定义这些参数:

    Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
    double angle = -50.0;
    double scale = 0.6;
    
  8. 我们利用OpenCV函数 getRotationMatrix2D 来获得旋转矩阵,
    这个函数返回一个 2X3  矩阵 (这里是 rot_mat)

    rot_mat = getRotationMatrix2D( center, angle, scale );
    
  9. 现在把旋转应用到仿射变换的输出.
    warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
    
  10. 最后我们把仿射变换和旋转的结果绘制在窗体中,源图像也绘制出来以作参照:
    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 );
    
  11. 等待用户退出程序
    waitKey(0);

 

时间: 2024-09-21 01:29:00

OpenCV实现仿射变换的相关文章

《Master Opencv...读书笔记》非刚性人脸跟踪 IV (终)

一.我们目前为止拥有什么 为了有一个连续完整的认识,在介绍最后一节前,先梳理下至今我们训练了哪些数据特征,并且训练它们的目的是什么.   1.      ft_data:利用手工标注工具,获取最原始的样本训练数据,包括以下内容:  图像名称集合imnames:表明在哪幅图像上标注特征点: 二维坐标集合points:手工标准点,后续更高级别特征均围绕这些特征点展开: 对称坐标索引集合symmetry:标注样本图像的镜像图像上的特征点,扩大样本库:  连接索引集合connections:描述手工标注

图像处理-单个模板的多目标识别 OPENCV

问题描述 单个模板的多目标识别 OPENCV 初学图像处理, 请多多指教! 我现在想解决的是用单个模板去匹配测试图中的多个目标(目标有仿射变换),参照了现成的一些SURF算法提取特征值进行匹配,可是这样只能匹配到一个目标.后来发现匹配的knnmatch函数可以对一个 query descriptor返回k个最佳匹配,可是效果并不好, 不知有什么建议?十分感谢! 代码如下: Mat img1 = imread( ""q.jpg"" CV_LOAD_IMAGE_GRAY

《Master Opencv...读书笔记》非刚性人脸跟踪 III

   上篇文章中,我们获得了人脸的各种表情模式,也就是一堆标注点的形变参数.这次我们需要训练一中人脸特征(团块模型),它能够对人脸的不同部位(即"标注点")分别进行描述,作为后面人脸跟踪.表情识别的区分依据.本次博文的主要内容: a.      介绍下人脸特征检测器大概有哪些类别 b.      详细介绍随机梯度法,并介绍在人脸团块特征提取时的应用 c.      为了提高训练/跟踪的健壮性,利用上一讲对输入的图像进行大小.角度的约束   人脸特征检测器综述       人脸特征检测与

在Python下利用OpenCV来旋转图像的教程_python

OpenCV是应用最被广泛的的开源视觉库.他允许你使用很少的代码来检测图片或视频中的人脸. 这里有一些互联网上的教程来阐述怎么在OpenCV中使用仿射变换(affine transform)旋转图片--他们并没有处理旋转一个图片里的矩形一般会把矩形的边角切掉这一问题,所以产生的图片需要修改.当正确的使用一点代码时,这是一点瑕疵.   def rotate_about_center(src, angle, scale=1.): w = src.shape[1] h = src.shape[0] r

返回时C++内存问题opencv写的

问题描述 返回时C++内存问题opencv写的 //读取摄像头并保存为AVI文件 #include "cv.h" #include "highgui.h" int main(int argc,char**argv) { CvCapture* capture=0; IplImage *bgr_frame; int fps=25; int i; CvSize size; CvVideoWriter *writer; cvNamedWindow("Jimmy&q

openni opencv linux-如何在linux下建立一个着openni和opencv的工程?

问题描述 如何在linux下建立一个着openni和opencv的工程? 如何在linux下建立一个着openni和opencv的工程?麻烦大神们详细解说下,不胜感激!!!!

python结合opencv实现人脸检测与跟踪

  在Python下用起来OpenCV很爽,代码很简洁,很清晰易懂.使用的是Haar特征的分类器,训练之后得到的数据存在一个xml中.下面我们就来详细谈谈. 模式识别课上老师留了个实验,在VC++环境下利用OpenCV库编程实现人脸检测与跟踪. 然后就开始下载opencv和vs2012,再然后,配置了好几次还是配置不成功,这里不得不吐槽下微软,软件做这么大,这么难用真的好吗? 于是就尝试了一下使用python完成实验任务,大概过程就是这样子的: 首先,配置运行环境: 下载opencv和pytho

视频处理-我用qt+opencv 录制了视频

问题描述 我用qt+opencv 录制了视频 我用qt+opencv 录制了视频,问题一:录制了1分钟,视频中不到一分钟!用了定时器,ntimer= 1000/fps; 问题二,怎么录制音频? 谢谢 解决方案 OpenCV 录制视频QT OpenCV 播放视频Opencv + Qt 获取视频中任意一帧

【OpenCV】椭圆拟合

直接上代码吧: #include "cv.h" #include "highgui.h" int slider_pos=70;//阈值 IplImage *image02 =0,*image03 = 0,*image04 = 0; void process_image(int h); int main(int argc ,char **argv) { //const char *filename ="binaryGroup.bmp"; const