本文內容參考了http://blog.csdn.net/xiaowei_cqu/article/details/7616044
幾何變換
幾何變換可以看成圖像中物體(或像素)空間位置改變,或者說是像素的移動。
幾何運算需要空間變換和灰度級差值兩個步驟的算法,像素通過變換映射到新的座標位置,新的位置可能是在幾個像素之間,即不一定爲整數座標。這時就需要灰度級差值將映射的新座標匹配到輸出像素之間。最簡單的插值方法是最近鄰插值,就是令輸出像素的灰度值等於映射最近的位置像素,該方法可能會產生鋸齒。這種方法也叫零階插值,相應比較複雜的還有一階和高階插值。
插值算法感覺只要瞭解就可以了,圖像處理中比較需要理解的還是空間變換。
空間變換
空間變換對應矩陣的仿射變換。一個座標通過函數變換的新的座標位置:
所以在程序中我們可以使用一個2*3的數組結構來存儲變換矩陣:
以最簡單的平移變換爲例,平移(b1,b2)座標可以表示爲:
因此,平移變換的變換矩陣及逆矩陣記爲:
縮放變換:將圖像橫座標放大(或縮小)sx倍,縱座標放大(或縮小)sy倍,變換矩陣及逆矩陣爲:
選擇變換:圖像繞原點逆時針旋轉a角,其變換矩陣及逆矩陣(順時針選擇)爲:
OpenCV中的圖像變換函數
基本的放射變換函數:
- void cvWarpAffine(
- const CvArr* src,//輸入圖像
- CvArr* dst, //輸出圖像
- const CvMat* map_matrix, //2*3的變換矩陣
- int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, //插值方法的組合
- CvScalar fillval=cvScalarAll(0) //用來填充邊界外的值
- );
- void cvGetQuadrangleSubPix(
- const CvArr* src, //輸入圖像
- CvArr* dst, // 提取的四邊形
- const CvMat* map_matrix //2*3的變換矩陣
- );
即對應每個點的變換:
WarpAffine與 GetQuadrangleSubPix 不同的在於cvWarpAffine 要求輸入和輸出圖像具有同樣的數據類型,有更大的資源開銷(因此對小圖像不太合適)而且輸出圖像的部分可以保留不變。而 cvGetQuadrangleSubPix 可以精確地從8位圖像中提取四邊形到浮點數緩存區中,具有比較小的系統開銷,而且總是全部改變輸出圖像的內容。
用cvWarpAffine實驗將圖像逆時針旋轉degree角度:
#include<cv.h>
#include<cxcore.h>
#include<highgui.h>
#include<iostream>
int main ( int argc ,char* argv)
{
IplImage* src = cvLoadImage("F:\\bb1.jpg");
IplImage* dst = cvCloneImage( src);
int degree = 30;//逆時針旋轉30度
CvPoint2D32f center ;//創建一箇中心點
center.x = src->width/2.0+0.5;
center.y = src->height/2.0+0.5;
float m[6];
CvMat M = cvMat( 2 , 3 , CV_32F , m);//構建一個2*3的矩陣
cv2DRotationMatrix( center , degree , 1 , &M);//計算圍繞中心點旋轉的映射矩陣
cvWarpAffine( src , dst , &M , CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0));//仿射變換
cvNamedWindow("src");
cvShowImage("src" ,src);
cvNamedWindow("dst");
cvShowImage("dst" ,dst);
cvWaitKey(0);
}
結果爲
實踐:圖像旋轉變換(保留原圖內容,放大尺寸)
int main ( int argc ,char* argv)
{
IplImage* src = cvLoadImage("F:\\bb1.jpg");
int degree = 30;
double angle = degree * CV_PI / 180.; // 弧度
double a = sin(angle), b = cos(angle);
int width = src ->width;
int height = src->height;
int width_rotate= int(height * fabs(a) + width * fabs(b));
int height_rotate=int(width * fabs(a) + height * fabs(b));
float map[6];
CvMat map_matrix = cvMat(2, 3, CV_32F, map);
// 旋轉中心
CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);
cv2DRotationMatrix(center, degree, 1.0, &map_matrix);
map[2] += (width_rotate - width) / 2; //對圖像進行平移
map[5] += (height_rotate - height) / 2; //對圖像進行平移
IplImage* dst = cvCreateImage(cvSize(width_rotate, height_rotate), 8, 3);
//對圖像做仿射變換
//CV_WARP_FILL_OUTLIERS - 填充所有輸出圖像的象素。
//如果部分象素落在輸入圖像的邊界外,那麼它們的值設定爲 fillval.
//CV_WARP_INVERSE_MAP - 指定 map_matrix 是輸出圖像到輸入圖像的反變換,
cvWarpAffine( src,dst, &map_matrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
cvNamedWindow("src");
cvShowImage("src" ,src);
cvNamedWindow("dst");
cvShowImage("dst" ,dst);
cvWaitKey(0);
return 0;
}
結果爲