OpenC学习笔记之十四——仿射变换

首先感谢@浅墨_毛星云本篇博文是小武通过学习@浅墨_毛星云的博客以及书籍《opencv3.0编程入门》整理的笔记及疑问心得,小武水平有限,欢迎交流。

@浅墨_毛星云博文:https://blog.csdn.net/poem_qianmo/article/category/1923021


一、仿射变换概述

官网描述:https://docs.opencv.org/2.4.9/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.html?highlight=warpaffined

仿射变换(Affine Transformation或 Affine Map),又称仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。它保持了二维图形的“平直性”(即:直线经过变换之后依然是直线)和“平行性”(即:二维图形之间的相对位置关系保持不变,平行线依然是平行线,且直线上点的位置顺序不变)。

一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式。

那么, 我们能够用仿射变换来表示如下三种常见的变换形式:

  • 旋转,rotation (线性变换)
  • 平移,translation(向量加)
  • 缩放,scale(线性变换)

如果进行更深层次的理解,仿射变换代表的是两幅图之间的一种映射关系。

而我们通常使用2 x 3的矩阵来表示仿射变换。



 

考虑到我们要使用矩阵 A 和 B 对二维向量 做变换, 所以也能表示为下列形式:


  或者     


 

即:       


  • <1>已知 X和T,而且我们知道他们是有联系的. 接下来我们的工作就是求出矩阵 M
  • <2>已知 M和X,要想求得 T. 我们只要应用算式即可. 对于这种联系的信息可以用矩阵 M 清晰的表达 (即给出明确的2×3矩阵) 或者也可以用两幅图片点之间几何关系来表达。
我们形象地说明一下,因为矩阵 M 联系着两幅图片, 我们就以其表示两图中各三点直接的联系为例。

见下图:


其中,点1, 2 和 3 (在图一中形成一个三角形) 与图二中三个点是一一映射的关系, 且他们仍然形成三角形, 但形状已经和之前不一样了。我们能通过这样两组三点求出仿射变换 (可以选择自己喜欢的点), 接着就可以把仿射变换应用到图像中去。


二、仿射变换函数

OpenCV仿射变换相关的函数一般涉及到warpAffine和getRotationMatrix2D这两个:

  • 使用OpenCV函数warpAffine 来实现一些简单的重映射.
  • 使用OpenCV函数getRotationMatrix2D 来获得旋转矩阵。


1、warpAffined函数详解

C++: void warpAffine(InputArray src, 
                     OutputArray dst, 
                     InputArray M, 
                     Size dsize,
                     int flags=INTER_LINEAR,
                     int borderMode=BORDER_CONSTANT,
                     const Scalar& borderValue=Scalar())

参数:

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
  • 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的M,2×3的变换矩阵。
  • 第四个参数,Size类型的dsize,表示输出图像的尺寸。
  • 第五个参数,int类型的flags,插值方法的标识符。此参数有默认值INTER_LINEAR(线性插值),可选的插值方式如下:
    • INTER_NEAREST - 最近邻插值
    • INTER_LINEAR - 线性插值(默认值)
    • INTER_AREA - 区域插值
    • INTER_CUBIC –三次样条插值
    • INTER_LANCZOS4 -Lanczos插值
    • CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
    • CV_WARP_INVERSE_MAP –表示M为输出图像到输入图像的反变换,即 。因此可以直接用来做象素插值。否则, warpAffine函数从M矩阵得到反变换。
  • 第六个参数,int类型的borderMode,边界像素模式,默认值为BORDER_CONSTANT。
  • 第七个参数,const Scalar&类型的borderValue,在恒定的边界情况下取的值,默认值为Scalar(),即0。

另外提一点,我们的WarpAffine函数与一个叫做cvGetQuadrangleSubPix( )的函数类似,但是不完全相同。 WarpAffine要求输入和输出图像具有同样的数据类型,有更大的资源开销(因此对小图像不太合适)而且输出图像的部分可以保留不变。而 cvGetQuadrangleSubPix 可以精确地从8位图像中提取四边形到浮点数缓存区中,具有比较小的系统开销,而且总是全部改变输出图像的内容。


2、getRotationMatrix2D函数详解

C++: Mat getRotationMatrix2D(Point2f center, double angle, double scale)

参数:

  • 第一个参数,Point2f类型的center,表示源图像的旋转中心。
  • 第二个参数,double类型的angle,旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)。
  • 第三个参数,double类型的scale,缩放系数。

此函数计算以下矩阵:

 

其中:



代码

  //添加头文件  
#include<opencv/cxcore.hpp>
#include<opencv2/core/core.hpp>  
#include<opencv2/highgui/highgui.hpp>  
#include<opencv2/imgproc/imgproc.hpp>  
#include<iostream>  
  
using namespace std;  
using namespace cv;

/// Global variables
char* source_window= "source_img";
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;

   /// Load the image
   src = imread( "harris.jpg", 1 );

   /// Set the dst image the same type and size as src
   warp_dst = Mat::zeros( src.rows, src.cols, src.type() );

   /// Set your 3 points to calculate the  Affine Transform
   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 );

   /// Get the Affine Transform
   warp_mat = getAffineTransform( srcTri, dstTri );

   /// Apply the Affine Transform just found to the src image
   warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

   /** Rotating the image after Warp */

   /// Compute a rotation matrix with respect to the center of the image
   Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
   double angle = -50.0;
   double scale = 0.6;

   /// Get the rotation matrix with the specifications above
   rot_mat = getRotationMatrix2D( center, angle, scale );

   /// Rotate the warped image
   warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );

   /// Show what you got
   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 );

   /// Wait until user exits the program
   waitKey(0);

   return 0;
  }

效果








猜你喜欢

转载自blog.csdn.net/weixin_40647819/article/details/80099953