生活随笔
收集整理的這篇文章主要介紹了
图像几何变换:旋转,缩放,斜切
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
幾何變換
幾何變換可以看成圖像中物體(或像素)空間位置改變,或者說是像素的移動(dòng)。
幾何運(yùn)算需要空間變換和灰度級(jí)差值兩個(gè)步驟的算法,像素通過變換映射到新的坐標(biāo)位置,新的位置可能是在幾個(gè)像素之間,即不一定為整數(shù)坐標(biāo)。這時(shí)就需要灰度級(jí)差值將映射的新坐標(biāo)匹配到輸出像素之間。最簡單的插值方法是最近鄰插值,就是令輸出像素的灰度值等于映射最近的位置像素,該方法可能會(huì)產(chǎn)生鋸齒。這種方法也叫零階插值,相應(yīng)比較復(fù)雜的還有一階和高階插值。
插值算法感覺只要了解就可以了,圖像處理中比較需要理解的還是空間變換。
空間變換
空間變換對(duì)應(yīng)矩陣的仿射變換。一個(gè)坐標(biāo)通過函數(shù)變換的新的坐標(biāo)位置:
所以在程序中我們可以使用一個(gè)2*3的數(shù)組結(jié)構(gòu)來存儲(chǔ)變換矩陣:
以最簡單的平移變換為例,平移(b1,b2)坐標(biāo)可以表示為:
因此,平移變換的變換矩陣及逆矩陣記為:
縮放變換:將圖像橫坐標(biāo)放大(或縮小)sx倍,縱坐標(biāo)放大(或縮小)sy倍,變換矩陣及逆矩陣為:
選擇變換:圖像繞原點(diǎn)逆時(shí)針旋轉(zhuǎn)a角,其變換矩陣及逆矩陣(順時(shí)針選擇)為:
OpenCV中的圖像變換函數(shù)
基本的放射變換函數(shù):
[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)????? );??
另外一個(gè)比較類似的函數(shù)是cvGetQuadrangleSubPix:
[cpp]?view plaincopy
void?cvGetQuadrangleSubPix(??? ???????const?CvArr*?src,???? ???????CvArr*?dst,????? ???????const?CvMat*?map_matrix??? );??
這個(gè)函數(shù)用以提取輸入圖像中的四邊形,并通過map_matrix變換存儲(chǔ)到dst中,與WarpAffine變換意義相同,
即對(duì)應(yīng)每個(gè)點(diǎn)的變換:
WarpAffine與 GetQuadrangleSubPix 不同的在于cvWarpAffine 要求輸入和輸出圖像具有同樣的數(shù)據(jù)類型,有更大的資源開銷(因此對(duì)小圖像不太合適)而且輸出圖像的部分可以保留不變。而 cvGetQuadrangleSubPix 可以精確地從8位圖像中提取四邊形到浮點(diǎn)數(shù)緩存區(qū)中,具有比較小的系統(tǒng)開銷,而且總是全部改變輸出圖像的內(nèi)容。
實(shí)踐:圖像旋轉(zhuǎn)變換(原尺寸)
首先用cvWarpAffine實(shí)驗(yàn)將圖像逆時(shí)針旋轉(zhuǎn)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)?);?? }?? 逆時(shí)針旋轉(zhuǎn)30度結(jié)果:
這里我們將新的圖像還保留原來的圖像尺寸。這樣的效果顯然不太好,我們通過計(jì)算相應(yīng)放大圖像尺寸。
實(shí)踐:圖像旋轉(zhuǎn)變換(保留原圖內(nèi)容,放大尺寸)
需要計(jì)算新圖的尺寸,示意圖如下:
所以新圖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;?? }??
實(shí)踐:圖像旋轉(zhuǎn)變換(保留原圖內(nèi)容,放大尺寸)-2
試一下用cvGetQuadrangleSubPix函數(shù):
[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;?? }???? 實(shí)踐:圖像放射變換(通過三點(diǎn)確定變換矩陣)
在OpenCV 2.3的參考手冊(cè)中《opencv_tutorials》介紹了另一種確定變換矩陣的方法,通過三個(gè)點(diǎn)變換的幾何關(guān)系映射實(shí)現(xiàn)變換。 變換示意圖如下:
即通過三個(gè)點(diǎn)就可以確定一個(gè)變換矩陣。(矩形變換后一定為平行四邊形) 以下是基于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;?? }?? 變換結(jié)果:
轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/xiaowei_cqu/article/details/7616044
實(shí)驗(yàn)代碼下載:http://download.csdn.net/detail/xiaowei_cqu/4339856
寫在最后的一點(diǎn)點(diǎn)閑話 之前一直用的2.1的版本,后來裝了2.3,只是聽說2.3很強(qiáng)大,但我剛開始學(xué),用的也基礎(chǔ),完全沒感覺出不同。直到今天忽然看到了2.3的手冊(cè),才發(fā)現(xiàn)從2.0開始函數(shù)和基本結(jié)構(gòu)都有了很大的改變,而我一直還是用的1.0風(fēng)格的函數(shù)(比如cvMat,cvLoadImage)。我的兩個(gè)學(xué)習(xí)工具《Learnning OpenCV》和《OpenCV中文參考手冊(cè)》都是基于1.0的,這也是我到今天才看到Mat,然后直接被驚艷到了。 別人總結(jié)出來的東西能幫助我們?cè)谝婚_始迅速入門,但要學(xué)深,學(xué)精,終歸還是要自己去努力挖的。
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的图像几何变换:旋转,缩放,斜切的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。