生活随笔
收集整理的這篇文章主要介紹了
OpenCV-图像几何变换:旋转,缩放,斜切 .
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
幾何變換
幾何變換可以看成圖像中物體(或像素)空間位置改變,或者說是像素的移動。
幾何運算需要空間變換和灰度級差值兩個步驟的算法,像素通過變換映射到新的坐標位置,新的位置可能是在幾個像素之間,即不一定為整數坐標。這時就需要灰度級差值將映射的新坐標匹配到輸出像素之間。最簡單的插值方法是最近鄰插值,就是令輸出像素的灰度值等于映射最近的位置像素,該方法可能會產生鋸齒。這種方法也叫零階插值,相應比較復雜的還有一階和高階插值。
插值算法感覺只要了解就可以了,圖像處理中比較需要理解的還是空間變換。
空間變換
空間變換對應矩陣的仿射變換。一個坐標通過函數變換的新的坐標位置:
所以在程序中我們可以使用一個2*3的數組結構來存儲變換矩陣:
以最簡單的平移變換為例,平移(b1,b2)坐標可以表示為:
因此,平移變換的變換矩陣及逆矩陣記為:
縮放變換:將圖像橫坐標放大(或縮小)sx倍,縱坐標放大(或縮小)sy倍,變換矩陣及逆矩陣為:
選擇變換:圖像繞原點逆時針旋轉a角,其變換矩陣及逆矩陣(順時針選擇)為:
OpenCV中的圖像變換函數
基本的放射變換函數:
[cpp]?view plaincopy
void?cvWarpAffine(??? ????const?CvArr*?src,?? ????CvArr*?dst,??? ????const?CvMat*?map_matrix,????? ????int?flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,????? ????CvScalar?fillval=cvScalarAll(0)????? );??
另外一個比較類似的函數是cvGetQuadrangleSubPix:
[cpp]?view plaincopy
void?cvGetQuadrangleSubPix(??? ???????const?CvArr*?src,???? ???????CvArr*?dst,????? ???????const?CvMat*?map_matrix??? );??
這個函數用以提取輸入圖像中的四邊形,并通過map_matrix變換存儲到dst中,與WarpAffine變換意義相同,
即對應每個點的變換:
WarpAffine與 GetQuadrangleSubPix 不同的在于cvWarpAffine 要求輸入和輸出圖像具有同樣的數據類型,有更大的資源開銷(因此對小圖像不太合適)而且輸出圖像的部分可以保留不變。而 cvGetQuadrangleSubPix 可以精確地從8位圖像中提取四邊形到浮點數緩存區中,具有比較小的系統開銷,而且總是全部改變輸出圖像的內容。
實踐:圖像旋轉變換(原尺寸)
首先用cvWarpAffine實驗將圖像逆時針旋轉degree角度。
[cpp]?view plaincopy
?? void?rotateImage(IplImage*?img,?IplImage?*img_rotate,int?degree)?? {?? ?????? ????CvPoint2D32f?center;???? ????center.x=float?(img->width/2.0+0.5);?? ????center.y=float?(img->height/2.0+0.5);?? ?????? ????float?m[6];?????????????? ????CvMat?M?=?cvMat(?2,?3,?CV_32F,?m?);?? ????cv2DRotationMatrix(?center,?degree,1,?&M);?? ?????? ????cvWarpAffine(img,img_rotate,?&M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0)?);?? }?? 逆時針旋轉30度結果:
這里我們將新的圖像還保留原來的圖像尺寸。這樣的效果顯然不太好,我們通過計算相應放大圖像尺寸。
實踐:圖像旋轉變換(保留原圖內容,放大尺寸)
需要計算新圖的尺寸,示意圖如下:
所以新圖size為(width*cos(a)+height*sin(a), height*cos(a)+width*sin(a))
[cpp]?view plaincopy
?? IplImage*?rotateImage1(IplImage*?img,int?degree){?? ????double?angle?=?degree??*?CV_PI?/?180.;??? ????double?a?=?sin(angle),?b?=?cos(angle);??? ????int?width?=?img->width;???? ????int?height?=?img->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*?img_rotate?=?cvCreateImage(cvSize(width_rotate,?height_rotate),?8,?3);??? ?????? ?????? ?????? ?????? ????cvWarpAffine(?img,img_rotate,?&map_matrix,?CV_INTER_LINEAR?|?CV_WARP_FILL_OUTLIERS,?cvScalarAll(0));???? ????return?img_rotate;?? }??
實踐:圖像旋轉變換(保留原圖內容,放大尺寸)-2
試一下用cvGetQuadrangleSubPix函數:
[cpp]?view plaincopy
?? IplImage*?rotateImage2(IplImage*?img,?int?degree)???? {???? ????double?angle?=?degree??*?CV_PI?/?180.;??? ????double?a?=?sin(angle),?b?=?cos(angle);??? ????int?width=img->width,?height=img->height;?? ?????? ????int?width_rotate=?int(height?*?fabs(a)?+?width?*?fabs(b));???? ????int?height_rotate=int(width?*?fabs(a)?+?height?*?fabs(b));???? ????IplImage*?img_rotate?=?cvCreateImage(cvSize(width_rotate,?height_rotate),?img->depth,?img->nChannels);???? ????cvZero(img_rotate);???? ?????? ????int?tempLength?=?sqrt((double)width?*?width?+?(double)height?*height)?+?10;???? ????int?tempX?=?(tempLength?+?1)?/?2?-?width?/?2;???? ????int?tempY?=?(tempLength?+?1)?/?2?-?height?/?2;???? ????IplImage*?temp?=?cvCreateImage(cvSize(tempLength,?tempLength),?img->depth,?img->nChannels);???? ????cvZero(temp);???? ?????? ????cvSetImageROI(temp,?cvRect(tempX,?tempY,?width,?height));???? ????cvCopy(img,?temp,?NULL);???? ????cvResetImageROI(temp);???? ?????? ?????? ?????? ????float?m[6];???? ????int?w?=?temp->width;???? ????int?h?=?temp->height;???? ????m[0]?=?b;???? ????m[1]?=?a;???? ????m[3]?=?-m[1];???? ????m[4]?=?m[0];???? ?????? ????m[2]?=?w?*?0.5f;???? ????m[5]?=?h?*?0.5f;???? ????CvMat?M?=?cvMat(2,?3,?CV_32F,?m);???? ????cvGetQuadrangleSubPix(temp,?img_rotate,?&M);???? ????cvReleaseImage(&temp);???? ????return?img_rotate;?? }???? 實踐:圖像放射變換(通過三點確定變換矩陣)
在OpenCV 2.3的參考手冊中《opencv_tutorials》介紹了另一種確定變換矩陣的方法,通過三個點變換的幾何關系映射實現變換。 變換示意圖如下:
即通過三個點就可以確定一個變換矩陣。(矩形變換后一定為平行四邊形) 以下是基于OpenCV 2.3的代碼(需至少2.0以上版本的支持)
[cpp]?view plaincopy
int?main(?)?? {?? ????Point2f?srcTri[3];?? ????Point2f?dstTri[3];?? ????Mat?rot_mat(?2,?3,?CV_32FC1?);?? ????Mat?warp_mat(?2,?3,?CV_32FC1?);?? ????Mat?src,?warp_dst,?warp_rotate_dst;?? ?????? ????src?=?imread(?"baboon.jpg",?1?);?? ????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()?);?? ?????? ????Point?center?=?Point(?warp_dst.cols/2,?warp_dst.rows/2?);?? ????double?angle?=?-50.0;?? ????double?scale?=?0.6;?? ????rot_mat?=?getRotationMatrix2D(?center,?angle,?scale?);?? ????warpAffine(?warp_dst,?warp_rotate_dst,?rot_mat,?warp_dst.size()?);?? ?????? ?????? ?????? ?????? ?????? ?????? ?? ????namedWindow(?"Source",?CV_WINDOW_AUTOSIZE?);?? ????imshow(?"Source",?src?);?? ????namedWindow(?"Wrap",?CV_WINDOW_AUTOSIZE?);?? ????imshow(?"Wrap",?warp_dst?);?? ????namedWindow("Wrap+Rotate",?CV_WINDOW_AUTOSIZE?);?? ????imshow(?"Wrap+Rotate",?warp_rotate_dst?);?? ????waitKey(0);?? ????return?0;?? }?? 變換結果:
轉載請注明出處:http://blog.csdn.net/xiaowei_cqu/article/details/7616044
實驗代碼下載:http://download.csdn.net/detail/xiaowei_cqu/4339856
總結
以上是生活随笔為你收集整理的OpenCV-图像几何变换:旋转,缩放,斜切 .的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。