學習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 :插值數值
函式操作為:
函式不能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 得到反變換。
borderValue :插值數值
函式操作為:
函式 WarpAffine 利用下面指定的矩陣變換輸入影象:
- 如果沒有指定 CV_WARP_INVERSE_MAP , ,
- 否則,
函式不能in_place操作