学习OpenCV范例(十六)——重映射和仿射变换

重映射在图像处理中主要的功能为:将一个图像中一个位置的像素放置到另一个图像指定位置的过程,可以根据自己设定的函数将图像进行变换,较常见的功能有关于x轴翻转,关于y轴翻转,关于x、y轴翻转;仿射变换在图像处理中的主要功能为:对图像进行缩放、旋转、平移、扭曲等。

1、原理

从下面三个链接可以详细的了解到重映射和仿射变换的原理

重映射:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/remap/remap.html#remap

仿射变换:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.html#warp-affine

学习OpenCV:http://download.csdn.net/detail/chenjiazhou12/7083295

2、代码实现

程序的功能是:生成两个窗口分别显示重映射的结果和仿射变换的结果

重映射窗口上建立了一个滑动条

0表示:显示原图

1表示:图像宽高缩小一半,并显示在中间

2表示:图像上下颠倒

3表示:图像左右颠倒

4表示:同时执行上下和左右的颠倒

仿射变换窗口建立两个滑动条,一个为缩放功能,一个为旋转功能

旋转的角度为-180—180

缩放因子为:0.1-1.0

#include "stdafx.h"

 #include "opencv2/highgui/highgui.hpp"
 #include "opencv2/imgproc/imgproc.hpp"
 #include <iostream>
 #include <stdio.h>

 using namespace cv;


 /// Global variables
 Mat src;
 Mat warp_dst;
 const char* remaptrackbarname="remapvalue";
 const char* warprotatetrackbarname="warprotatevalue";
 const char* warpscaletrackbarname="warpscalevalue";
 const char* remap_window = "Remap demo";
 const char* warprotate_window="warprotate demo";
 const int remapmaxcount=4,warprotatemaxcount=360,warpscalemaxcount=10;
 int remapvalue,warprotatevalue=180, warpscalevalue=10;

 /// Function Headers
 void update_map( void );
 void remapcontrol(int,void*);
 void warprotatecontrol(int,void*);
 void warpaffinecontrol();

 /**
 * @function main
 */
 int main( int argc, char** argv )
 {
   /// Load the image
   src = imread( "scenery.jpg", 1 );

  /// Create dst, map_x and map_y with the same size as src:


  /// Create window
  namedWindow( remap_window, CV_WINDOW_AUTOSIZE );
  namedWindow(warprotate_window,CV_WINDOW_AUTOSIZE);
  createTrackbar(remaptrackbarname,remap_window,&remapvalue,remapmaxcount,remapcontrol);
  createTrackbar(warprotatetrackbarname,warprotate_window,&warprotatevalue,warprotatemaxcount,warprotatecontrol);
  createTrackbar(warpscaletrackbarname,warprotate_window,&warpscalevalue,warpscalemaxcount,warprotatecontrol); 
  remapcontrol(0,0);
  warpaffinecontrol();
  warprotatecontrol(0,0);
  waitKey();

  return 0;
 }

 /**
 * @function update_map
 * @brief Fill the map_x and map_y matrices with 4 types of mappings
 */
  void remapcontrol(int,void*)
  {
	  Mat  dst, map_x, map_y; 
	  dst.create( src.size(), src.type() );
	  map_x.create( src.size(), CV_32FC1 );
	  map_y.create( src.size(), CV_32FC1 );
	  for( int j = 0; j < src.rows; j++ )
	  { for( int i = 0; i < src.cols; i++ )
	  {
		  switch( remapvalue )
		  {
		  case 0:			  
			  map_x.at<float>(j,i) = i ;
			  map_y.at<float>(j,i) = j ;
			  break;

		  case 1:
			  if( i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 )
			  {
				  map_x.at<float>(j,i) = 2*( i - src.cols*0.25 ) + 0.5 ;
				  map_y.at<float>(j,i) = 2*( j - src.rows*0.25 ) + 0.5 ;
			  }
			  else
			  { map_x.at<float>(j,i) = 0 ;
			  map_y.at<float>(j,i) = 0 ;
			  }
			  break;
		  case 2:
			  map_x.at<float>(j,i) = i ;
			  map_y.at<float>(j,i) = src.rows - j ;
			  break;
		  case 3:
			  map_x.at<float>(j,i) = src.cols - i ;
			  map_y.at<float>(j,i) = j ;
			  break;
		  case 4:
			  map_x.at<float>(j,i) = src.cols - i ;
			  map_y.at<float>(j,i) = src.rows - j ;
			  break;
		  } // end of switch
	  }
	  }
	  remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );

	  /// Display results
	  imshow( remap_window, dst );
  }
  void warprotatecontrol(int,void*)
  {
	  Mat warp_rotate_dst;
	  Mat rot_mat( 2, 3, CV_32FC1 );
	  Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
	  double angle =warprotatevalue-180;
	  double scale =double(warpscalevalue)/10;
	  printf("%f\n",scale);
	  /// 通过上面的旋转细节信息求得旋转矩阵
	  rot_mat = getRotationMatrix2D( center, angle, scale );

	  /// 旋转已扭曲图像
	  warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
	  imshow(warprotate_window,warp_rotate_dst);
  }
   void warpaffinecontrol()
	{
		Point2f srcTri[3];
		Point2f dstTri[3];
		Mat warp_mat( 2, 3, CV_32FC1 );
		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() );
	};

3、运行结果

                                                 学习OpenCV范例(十六)——重映射和仿射变换_第1张图片

                                                                                图1、原图                                                                    

学习OpenCV范例(十六)——重映射和仿射变换_第2张图片 学习OpenCV范例(十六)——重映射和仿射变换_第3张图片

                图2、图像宽高缩小一半                                       图3、  图像上下颠倒   

 学习OpenCV范例(十六)——重映射和仿射变换_第4张图片 学习OpenCV范例(十六)——重映射和仿射变换_第5张图片      

                         图4、图像左右颠倒                                       图5、图像上下左右颠倒

学习OpenCV范例(十六)——重映射和仿射变换_第6张图片 学习OpenCV范例(十六)——重映射和仿射变换_第7张图片

                     图6、图像旋转                                                       图7、图像缩小

学习OpenCV范例(十六)——重映射和仿射变换_第8张图片

                 图8、图像仿射

4、用到的类和函数

remap

功能:对图像进行普通几何变换

结构:

void remap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

src :源图像
dst :目标图像,和map1有同样的size,和src有同样的type
map1 :(x,y)点坐标或者 x坐标,可以是CV_16SC2 , CV_32FC1 , 或者 CV_32FC2类型
map2 :y坐标,可以是 CV_16UC1 , CV_32FC1 类型,如果map1为(x,y)点,map2可以不用
interpolation :插值方法
borderMode:边界插值类型
borderValue :插值数值

函数操作为:


函数不能in_place操作

getAffineTransform

功能:由三个不共线点计算仿射变换

结构:

Mat getAffineTransform(const Point2f* src, const Point2f* dst)

src:输入图像的三角形顶点坐标

dst:输出图像的相应的三角形顶点坐标

函数操作为:

  map_matrix为2*3的矩阵

 

getRotationMatrix2D

功能:计算二维旋转的仿射变换矩阵

结构:

Mat getRotationMatrix2D(Point2f center, double angle, double scale)

center:输入图像的旋转中心坐标

angle:旋转角度(度),正值表示逆时针旋转

scale:缩放因子

函数操作为:



warpAffine

功能:对图像做仿射变换

结构:

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

src:源图像
dst :目标图像,和src有同样的size和type
M :2×3 变换矩阵
dsize :目标图像的size
flags : 插值方法和以下开关选项的组合:

  • CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
  • CV_WARP_INVERSE_MAP - 指定 map_matrix 是输出图像到输入图像的反变换,因此可以直接用来做象素插值。否则, 函数从 map_matrix 得到反变换。
borderMode :插值类型
borderValue :插值数值

函数操作为:


函数 WarpAffine 利用下面指定的矩阵变换输入图像: 

  • 如果没有指定 CV_WARP_INVERSE_MAP ,  ,
  • 否则,

函数不能in_place操作

你可能感兴趣的:(remap,重映射,warpAffine)