重映射在圖像處理中主要的功能爲:將一個圖像中一個位置的像素放置到另一個圖像指定位置的過程,可以根據自己設定的函數將圖像進行變換,較常見的功能有關於x軸翻轉,關於y軸翻轉,關於x、y軸翻轉;仿射變換在圖像處理中的主要功能爲:對圖像進行縮放、旋轉、平移、扭曲等。
1、原理
從下面三個鏈接可以詳細的瞭解到重映射和仿射變換的原理
重映射:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/remap/remap.html#remap
學習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、運行結果
圖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操作