日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV-图像几何变换:旋转,缩放,斜切 .

發布時間:2025/3/21 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV-图像几何变换:旋转,缩放,斜切 . 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

幾何變換

幾何變換可以看成圖像中物體(或像素)空間位置改變,或者說是像素的移動。

幾何運算需要空間變換和灰度級差值兩個步驟的算法,像素通過變換映射到新的坐標位置,新的位置可能是在幾個像素之間,即不一定為整數坐標。這時就需要灰度級差值將映射的新坐標匹配到輸出像素之間。最簡單的插值方法是最近鄰插值,就是令輸出像素的灰度值等于映射最近的位置像素,該方法可能會產生鋸齒。這種方法也叫零階插值,相應比較復雜的還有一階和高階插值。

插值算法感覺只要了解就可以了,圖像處理中比較需要理解的還是空間變換。

空間變換

空間變換對應矩陣的仿射變換。一個坐標通過函數變換的新的坐標位置:


所以在程序中我們可以使用一個2*3的數組結構來存儲變換矩陣:


以最簡單的平移變換為例,平移(b1,b2)坐標可以表示為:


因此,平移變換的變換矩陣及逆矩陣記為:


縮放變換:將圖像橫坐標放大(或縮小)sx倍,縱坐標放大(或縮小)sy倍,變換矩陣及逆矩陣為:


選擇變換:圖像繞原點逆時針旋轉a角,其變換矩陣及逆矩陣(順時針選擇)為:



OpenCV中的圖像變換函數

基本的放射變換函數:

[cpp]?view plaincopy
  • 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)???//用來填充邊界外的值??
  • );??
  • 另外一個比較類似的函數是cvGetQuadrangleSubPix:

    [cpp]?view plaincopy
  • void?cvGetQuadrangleSubPix(???
  • ???????const?CvArr*?src,??//輸入圖像???
  • ???????CvArr*?dst,???//?提取的四邊形??
  • ???????const?CvMat*?map_matrix?//2*3的變換矩陣??
  • );??
  • 這個函數用以提取輸入圖像中的四邊形,并通過map_matrix變換存儲到dst中,與WarpAffine變換意義相同,

    即對應每個點的變換:


    WarpAffine與 GetQuadrangleSubPix 不同的在于cvWarpAffine 要求輸入和輸出圖像具有同樣的數據類型,有更大的資源開銷(因此對小圖像不太合適)而且輸出圖像的部分可以保留不變。而 cvGetQuadrangleSubPix 可以精確地從8位圖像中提取四邊形到浮點數緩存區中,具有比較小的系統開銷,而且總是全部改變輸出圖像的內容。


    實踐:圖像旋轉變換(原尺寸)

    首先用cvWarpAffine實驗將圖像逆時針旋轉degree角度。 [cpp]?view plaincopy
  • //逆時針旋轉圖像degree角度(原尺寸)??
  • 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));????
  • ????//旋轉數組map??
  • ????//?[?m0??m1??m2?]?===>??[?A11??A12???b1?]??
  • ????//?[?m3??m4??m5?]?===>??[?A21??A22???b2?]??
  • ????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);???
  • ????//對圖像做仿射變換??
  • ????//CV_WARP_FILL_OUTLIERS?-?填充所有輸出圖像的象素。??
  • ????//如果部分象素落在輸入圖像的邊界外,那么它們的值設定為?fillval.??
  • ????//CV_WARP_INVERSE_MAP?-?指定?map_matrix?是輸出圖像到輸入圖像的反變換,??
  • ????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);????
  • ????//將原圖復制到臨時圖像tmp中心??
  • ????cvSetImageROI(temp,?cvRect(tempX,?tempY,?width,?height));????
  • ????cvCopy(img,?temp,?NULL);????
  • ????cvResetImageROI(temp);????
  • ????//旋轉數組map??
  • ????//?[?m0??m1??m2?]?===>??[?A11??A12???b1?]??
  • ????//?[?m3??m4??m5?]?===>??[?A21??A22???b2?]??
  • ????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()?);??
  • ????//?用3個點確定A仿射變換??
  • ????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()?);??
  • ????OpenCV?1.0的形式??
  • ????//IplImage?*?img=cvLoadImage("baboon.jpg");??
  • ????//IplImage?*img_rotate=cvCloneImage(img);??
  • ????//CvMat?M?=warp_mat;??
  • ????//cvWarpAffine(img,img_rotate,?&M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0)?);??
  • ????//cvShowImage("Wrap2",img_rotate);??
  • ??
  • ????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-图像几何变换:旋转,缩放,斜切 .的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。