轉自:http://blog.csdn.net/w12345_ww/article/details/45332373 【OpenCV】圖像變換(五)-仿射變換和透視變換 标簽: 仿射變換透視單應性映射 2015-04-28 10:28 3443人閱讀 評論(0) 收藏 舉報

分類: opencv(27)
版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。
在上篇的博文中,我們重點讨論了基于霍夫變換的線段和圓檢測。其實在圖像的變換中,還有一部分是幾何操作,這些操作包括各種方式的拉伸,包括一緻性縮放和非一緻性縮放(即扭曲)。對于平面區域,有兩種方式的幾何轉換:一種是基于2×3矩陣進行的變換,叫仿射變換;另一種是基于3×3矩陣進行的變換,叫透視變換或者單應性映射。關于仿射變換和透射變換的矩陣變換,這篇博文不做重點讨論,因為圖像本質就是矩陣,對矩陣的變換就是對圖像像素的操作,很簡單的數學知識。
仿射變換可以形象的表示成以下形式。一個平面内的任意平行四邊形ABCD可以被仿射變換映射為另一個平行四邊形A’B’C’D’。通俗的解釋就是,可以将仿射變換想象成一幅圖像畫到一個膠版上,在膠版的角上推或拉,使其變形而得到不同類型的平行四邊形。相比較仿射變換,透射變換更具有靈活性,一個透射變換可以将矩形轉變成梯形。如下圖:
下面關于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()
)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
從上面的函數中,我們可以看到其中需要傳進去一個2×3變換矩陣,是以我們在調用cvWarpAffine()函數之前,要計算仿射映射矩陣,是以在OpenCV中有函數cvGetAffineTransform()來計算仿射映射矩陣。
CvMat* cvGetAffineTransform(
const CvPoint2D32f* pts_src,
const CvPoint2D32f* pts_dst,//src,dst三個二維點(x,y)的數組
CvMat* map_matrix//得到的仿射映射矩陣參數
)
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
下面給出這個仿射變換的完整程式示例:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
int main()
{
//數組聲明
CvPoint2D32f srcTri[], dstTri[];
//建立指針
CvMat* warp_mat = cvCreateMat(, , CV_32FC1);
CvMat* rot_mat = cvCreateMat(, , CV_32FC1);
//載入和顯示圖像
IplImage *src;
src = cvLoadImage("1.jpg", CV_LOAD_IMAGE_UNCHANGED);
cvNamedWindow("原圖", CV_WINDOW_AUTOSIZE);
cvShowImage("原圖", src);
IplImage *dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, );
dst=cvCloneImage(src);
dst->origin = src->origin;
cvZero(dst);
//計算變換矩陣
srcTri[].x = ;
srcTri[].y = ;
srcTri[].x = src->width - ;
srcTri[].y = ;
srcTri[].x = ;
srcTri[].y = src->height - ;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
cvGetAffineTransform(srcTri, dstTri, warp_mat);
//調用函數cvWarpAffine()
cvWarpAffine(src, dst, warp_mat);
cvNamedWindow("仿射圖1", CV_WINDOW_AUTOSIZE);
cvShowImage("仿射圖1", dst);
cvCopy(dst, src);
//用另外一種方法得到變換矩陣,并進行仿射變換
CvPoint2D32f center = cvPoint2D32f(src->height / , src->width / );
double angle = -;
double scale =- ;
cv2DRotationMatrix(center, angle, scale, rot_mat);
cvWarpAffine(src, dst, rot_mat);
cvNamedWindow("仿射圖2", CV_WINDOW_AUTOSIZE);
cvShowImage("仿射圖2", dst);
cvWaitKey();
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvDestroyWindow("原圖");
cvDestroyWindow("仿射圖1");
cvDestroyWindow("仿射圖2");
cvReleaseMat(&rot_mat);
cvReleaseMat(&warp_mat);
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
程式運作的結果為下圖:
透視變換的函數和得到透視映射矩陣的函數同仿射變換沒有太大差別,主要是仿射變換用到的是2×3矩陣,而透視變換用到的是3×3矩陣,關于函數的細節,在這裡我就不做細緻的介紹了,下面就直接給出程式示例:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
int main()
{
//數組聲明
CvPoint2D32f srcTri[], dstTri[];
//建立數組指針
CvMat *warp_mat = cvCreateMat(, , CV_32FC1);
IplImage *src, *dst;
//載入和顯示圖像
src = cvLoadImage("1.jpg", CV_LOAD_IMAGE_UNCHANGED);
cvNamedWindow("原圖", CV_WINDOW_AUTOSIZE);
cvShowImage("原圖", src);
dst = cvCloneImage(src);
dst->origin = src->origin;
cvZero(dst);
//構造變換矩陣
srcTri[].x = ;
srcTri[].y = ;
srcTri[].x = src->width - ;
srcTri[].y = ;
srcTri[].x = ;
srcTri[].y = src->height - ;
srcTri[].x = src->width - ;
srcTri[].y = src->height - ;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
dstTri[].x = src->width*;
dstTri[].y = src->height*;
//計算透視映射矩陣
cvGetPerspectiveTransform(srcTri, dstTri, warp_mat);
//調用函數cvWarpPerspective()
cvWarpPerspective(src, dst, warp_mat);
//顯示透視變換後的圖像
cvNamedWindow("透視變換", CV_WINDOW_AUTOSIZE);
cvShowImage("透視變換", dst);
cvWaitKey();
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvDestroyWindow("原圖");
cvDestroyWindow("透視變換");
cvReleaseMat(&warp_mat);
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
最後運作的結果如下: