1. 程式人生 > >學習OpenCV範例(十六)——重對映和仿射變換

學習OpenCV範例(十六)——重對映和仿射變換

重對映在影象處理中主要的功能為:將一個影象中一個位置的畫素放置到另一個影象指定位置的過程,可以根據自己設定的函式將影象進行變換,較常見的功能有關於x軸翻轉,關於y軸翻轉,關於x、y軸翻轉;仿射變換在影象處理中的主要功能為:對影象進行縮放、旋轉、平移、扭曲等。

1、原理

從下面三個連結可以詳細的瞭解到重對映和仿射變換的原理

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、執行結果

                                                 

                                                                                圖1、原圖                                                                    

 

                圖2、影象寬高縮小一半                                       圖3、  影象上下顛倒   

        

                         圖4、影象左右顛倒                                       圖5、影象上下左右顛倒

 

                     圖6、影象旋轉                                                       圖7、影象縮小


                 圖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 :插值數值

函式操作為:

\texttt{dst} (x,y) =  \texttt{src} (map_x(x,y),map_y(x,y))

函式不能in_place操作

getAffineTransform

功能:由三個不共線點計算仿射變換

結構:

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

src:輸入影象的三角形頂點座標

dst:輸出影象的相應的三角形頂點座標

函式操作為:

\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}  map_matrix為2*3的矩陣

 dst(i)=(x'_i,y'_i),src(i)=(x_i, y_i),i=0,1,2

getRotationMatrix2D

功能:計算二維旋轉的仿射變換矩陣

結構:

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

center:輸入影象的旋轉中心座標

angle:旋轉角度(度),正值表示逆時針旋轉

scale:縮放因子

函式操作為:

\begin{bmatrix} \alpha &  \beta & (1- \alpha )  \cdot \texttt{center.x} -  \beta \cdot \texttt{center.y} \\ - \beta &  \alpha &  \beta \cdot \texttt{center.x} + (1- \alpha )  \cdot \texttt{center.y} \end{bmatrix}

\begin{array}{l} \alpha =  \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta =  \texttt{scale} \cdot \sin \texttt{angle} \end{array}

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 :插值數值

函式操作為:

\texttt{dst} (x,y) =  \texttt{src} ( \texttt{M} _{11} x +  \texttt{M} _{12} y +  \texttt{M} _{13}, \texttt{M} _{21} x +  \texttt{M} _{22} y +  \texttt{M} _{23})

函式 WarpAffine 利用下面指定的矩陣變換輸入影象: dst(x',y') \leftarrow src(x,y)

  • 如果沒有指定 CV_WARP_INVERSE_MAP , (x',y')^T=map\_matrix \cdot (x,y,1)^T ,
  • 否則,(x, y)^T=map\_matrix \cdot (x',y',1)^T

函式不能in_place操作