OpenCV—仿射变换warpAffine--旋转和缩放

首先用一个图来演示仿射变换:

来自维基百科:https://zh.wikipedia.org/wiki/%E4%BB%BF%E5%B0%84%E5%8F%98%E6%8D%A2

OpenCV—仿射变换warpAffine--旋转和缩放_第1张图片

本文介绍仿射变换的两个应用:

旋转和缩放

仿射变换的API函数如下:

void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
参数含义参见官方手册:https://docs.opencv.org/2.4.9/modules/imgproc/doc/geometric_transformations.html#warpaffine

几点补充:

1、旋转变换的原理:原图像素坐标乘以旋转矩阵。

旋转矩阵通过如下API获得:

Mat getRotationMatrix2D(Point2f center, double angle, double scale)
参数含义参见官方手册:https://docs.opencv.org/2.4.9/modules/imgproc/doc/geometric_transformations.html#getrotationmatrix2d

该函数返回值为一个2×3的矩阵,其中矩阵前两列代表旋转,最后一列代表平移

旋转矩阵的求解过程可参见博文:http://blog.csdn.net/csxiaoshui/article/details/65446125

2、由于图像旋转之后,部分数据就会超出原来图像的位置,出现截断,如下所示。

OpenCV—仿射变换warpAffine--旋转和缩放_第2张图片

为了避免上面的问题,引入类RotatedRect,采用如下的构造函数:

RotatedRect(const Point2f& center, const Size2f& size, float angle)
使用成员函数boundingRect()返回包含此旋转举行的最小up-right矩形。


下面的示例代码来自opencv官方示例代码:https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp

做了适当修改和注释如下:

#include "opencv2/opencv.hpp"
#include 

using namespace cv;
using namespace std;

/// 全局变量
const char* source_window = "Source image";;
const char* rotate_window = "Rotate+Resize";

/**
 * @主函数
 */
int main( )
{
  Mat rot_mat( 2, 3, CV_32FC1 );
  Mat src, rotate_dst;

  /// 载入图像
  src = imread("lena.bmp", IMREAD_COLOR );

  /** 图像旋转 */

  /// 计算关于图像中心的旋转矩阵
  Point center = Point( src.cols/2, src.rows/2 );
  double angle = 35.0;
  //旋转的同时也可以放缩
  double scale = 0.8;

  /// 根据以上参数得到旋转矩阵
  rot_mat = getRotationMatrix2D( center, angle, scale );
  cout<<"旋转矩阵为:\n"<(0, 2) += bbox.width / 2.0 - center.x;
  rot_mat.at(1, 2) += bbox.height / 2.0 - center.y;

  /// 旋转图像
  warpAffine( src, rotate_dst, rot_mat, bbox.size());

  /// 显示原图和旋转结果
  namedWindow( source_window, WINDOW_AUTOSIZE );
  imshow( source_window, src );

  namedWindow( rotate_window, WINDOW_AUTOSIZE );
  imshow( rotate_window, rotate_dst );

  /// 等待,知道用户退出
  waitKey(0);

  return 0;
}

运行结果如下:


另外还有两个函数,分别为:

  • getAffineTransform():计算3个二维点对之间的仿射变换矩阵H(2行x3列),自由度为6.
详细参数参见官方文档: https://docs.opencv.org/2.4.9/modules/imgproc/doc/geometric_transformations.html#getaffinetransform

  • estimateRigidTransform():计算多个二维点对或者图像之间的最优仿射变换矩阵 (2行x3列),H可以是部分自由度,比如各向一致的切变。
详细参数参见官方文档: https://docs.opencv.org/2.4.9/modules/video/doc/motion_analysis_and_object_tracking.html#estimaterigidtransform

已知两张旋转了一定角度的图片,通过上面的两个函数便可求解出旋转矩阵。

OpenCV—仿射变换warpAffine--旋转和缩放_第3张图片

源代码如下所示:

#include "opencv2/opencv.hpp"
#include 

using namespace cv;
using namespace std;

/// 全局变量
const char* source_window = "Source image";;
const char* warp_window = "warp";

/**
 * @主函数
 */
int main( )
{
	Point2f srcTri[3];
	Point2f dstTri[3];

	vector srcTri7;
	vector dstTri7;

	Mat warp_mat( 2, 3, CV_32FC1 );
	Mat src, warp_dst, warp_rotate_dst;

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

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

	/// 设置三组点,求出变换矩阵
	srcTri[0] = Point2f( 300,481 );
	srcTri[1] = Point2f( 387,440 );
	srcTri[2] = Point2f( 293,284 );

	dstTri[0] = Point2f( 98,61 );
	dstTri[1] = Point2f( 70,140 );
	dstTri[2] = Point2f( 253,172 );

	//相关的7个点,采用拟合的方法求出变换矩阵
	srcTri7.push_back(Point2f( 300,481 ));
	srcTri7.push_back(Point2f( 387,440 ));
	srcTri7.push_back(Point2f( 293,284 ));
	srcTri7.push_back(Point2f( 497,286 ));
	srcTri7.push_back(Point2f( 369,123 ));
	srcTri7.push_back(Point2f( 383,35 ));
	srcTri7.push_back(Point2f( 51,136 ));

	dstTri7.push_back(Point2f( 98,61 ));
	dstTri7.push_back(Point2f( 70,140 ));
	dstTri7.push_back(Point2f( 253,172 ));
	dstTri7.push_back(Point2f( 120,310 ));
	dstTri7.push_back(Point2f( 326,329));
	dstTri7.push_back(Point2f( 382,397));
	dstTri7.push_back(Point2f( 511,92));

	//计算3个二维点对之间的仿射变换矩阵(2行x3列)
	warp_mat = getAffineTransform( srcTri, dstTri );
	//计算多个二维点对或者图像之间的最优仿射变换矩阵(2行x3列)
	//warp_mat = estimateRigidTransform(srcTri7,dstTri7,true);

	//扩大显示区域,以免显示不下
	Rect bbox = RotatedRect(Point(src.cols/2,src.rows/2), Size(src.cols*1.2, src.rows*1.2), 45).boundingRect();  
	warp_mat.at(0, 2) += bbox.width / 2.0 - src.cols/2;  
	warp_mat.at(1, 2) += bbox.height / 2.0 - src.rows/2; 

	///应用仿射变换,可以恢复出原图
	warpAffine( src, warp_dst, warp_mat, bbox.size() );

	//显示结果
	namedWindow( source_window, WINDOW_AUTOSIZE );
	imshow( source_window, src );

	namedWindow( warp_window, WINDOW_AUTOSIZE );
	imshow( warp_window, warp_dst );
  /// 等待,知道用户退出
  waitKey(0);
  return 0;
}

变换结果如下图所示:

OpenCV—仿射变换warpAffine--旋转和缩放_第4张图片

你可能感兴趣的:(OpenCV)