生活随笔
收集整理的這篇文章主要介紹了
Opencv——几何空间变换(仿射变换和投影变换)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
幾何空間變換
- 【1】幾何變換(空間變換)簡述
- 【2】變換矩陣知識簡述
- 【3】圖像的仿射變換
- 1、平移變換
- 2、比例縮放
- 3、旋轉
- 4、對稱變換(不做展示)
- 1、關于X軸變換
- 2、關于Y軸變換
- 3、關于直線Y=X變換
- 4、關于直線Y=-X變換
- 5、錯切變換
- 6、復合變換
- 【4】圖像的投影變換
- 【5】應用
- 【6】Opencv自帶的變換函數:
- Opencv中仿射變換的函數:warpAffine()函數
- Opencv中計算二維旋轉變換矩陣: getRotationMatrix2D()函數
【1】幾何變換(空間變換)簡述
圖像的幾何變換,又稱空間變換,是圖形處理的一個方面,是各種圖形處理算法的基礎。它將一幅圖像中的坐標位置映射到另一幅圖像中的新坐標位置,其實質是改變像素的空間位置,估算新空間位置上的像素值。
幾何變換算法一般包括空間變換運算和插值算法。
【2】變換矩陣知識簡述
齊次坐標的概念
圖像一般是二維的,坐標形式為(x,y)。
這里我們將其擴展為3維形式的齊次坐標。形式如下:
第三個參數是尺度參數,控制尺度縮放。(1的時候表示尺度不變)
齊次坐標使用n+1維,來表示n維的坐標。它的優點如下所示:
●統一坐標的加法運算和乘法運算, 運算時提高效率。
●表示無窮遠的點。 當z=0的時候,表示無窮遠的點。
( x,y,z) ----->( x/z, y/z) ;齊次坐標和二維坐標的換算
如,(2,2,1),(4,4,2 )表示同樣的點。
幾何運算矩陣
最左邊是變換后的齊次坐標,中間的是原圖點的其次坐標,最右邊是變換矩陣,有9個參數,分為4個子矩陣,每個子矩陣具有特殊意義。
T1:比例、旋轉、對稱、錯切
T2:平移
T3:投影
T4:整體縮放(通常我們通過T1實現縮放,所以這里通常為1)
所謂的仿射變換其實就是通過T1、T2進行變換。
所謂的投影變換就是在仿射變換上多用到了T3。
這里我們忽略T4。
【3】圖像的仿射變換
為了能夠直觀地了解參數對于變換的各種影響,我編寫了一個程序,通過滑動條來控制參數,同時顯示參數改變后的圖像。
這里的參數我都是設的正的,你把滑動條從正最大移到0就相當于是逆操作了。
代碼如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#define WINDOW_NAME "【程序窗口】" using namespace cv
;
using namespace std
;
int g_nValueA
= 100;
int g_nValueB
= 0;
int g_nValueC
= 0;
int g_nValueD
= 100;
int g_nValueL
= 50;
int g_nValueM
= 50;
int g_nValueP
= 0;
int g_nValueQ
= 0;
int I_max
= 400;
int g_nValueS
= 100;
int theta
= 0;
int change_switch
= 0;
int center_x
= I_max
/ 2;
int center_y
= I_max
/ 2;
Mat g_srcImage
,g_dstImage
;void on_change(int, void*); int main()
{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE
), FOREGROUND_INTENSITY
| FOREGROUND_GREEN
); g_srcImage
= Mat
::zeros(I_max
, I_max
, CV_8UC1
);g_dstImage
= Mat
::zeros(I_max
, I_max
, CV_8UC1
);for (int i
= I_max
/2;i
< I_max
/2+50;i
++) {for (int j
= I_max
/ 2;j
< I_max
/ 2 + 50;j
++) {g_srcImage
.at
<uchar
>(i
, j
) = 255;}}namedWindow(WINDOW_NAME
, WINDOW_NORMAL
);imshow("原圖", g_srcImage
);createTrackbar("a", WINDOW_NAME
, &g_nValueA
,150, on_change
);createTrackbar("b", WINDOW_NAME
, &g_nValueB
, 150, on_change
);createTrackbar("c", WINDOW_NAME
, &g_nValueC
, 150, on_change
);createTrackbar("d", WINDOW_NAME
, &g_nValueD
, 150, on_change
);createTrackbar("l", WINDOW_NAME
, &g_nValueL
, 150, on_change
);createTrackbar("m", WINDOW_NAME
, &g_nValueM
, 150, on_change
);createTrackbar("p", WINDOW_NAME
, &g_nValueP
, 150, on_change
);createTrackbar("q", WINDOW_NAME
, &g_nValueQ
, 150, on_change
);createTrackbar("s", WINDOW_NAME
, &g_nValueS
, 150, on_change
);createTrackbar("角度", WINDOW_NAME
, &theta
, 360, on_change
);createTrackbar("switch", WINDOW_NAME
, &change_switch
, 1, on_change
);on_change(0,0); while (1){if (waitKey(10) == 27) break; }return 0;}
void on_change(int, void*)
{g_dstImage
= Mat
::zeros(I_max
, I_max
, CV_8UC1
);float a
= g_nValueA
* 0.01;float b
= g_nValueB
* 0.01;float c
= g_nValueC
* 0.01;float d
= g_nValueD
* 0.01;int l
= g_nValueL
;int m
= g_nValueM
;float p
= g_nValueP
* 0.0005;float q
= g_nValueQ
* 0.0005;float s
= g_nValueS
* 0.01;int x_change
, y_change
;if (change_switch
== 0){for (int x
= I_max
/ 2;x
< I_max
/ 2 + 50;x
++) {for (int y
= I_max
/ 2;y
< I_max
/ 2 + 50;y
++) {x_change
= (a
* x
+ c
* y
+ l
) / (p
* x
+ q
* y
+ 1);y_change
= (b
* x
+ d
* y
+ m
) / (p
* x
+ q
* y
+ 1);if (x_change
>= I_max
) x_change
= I_max
- 1;else if (x_change
<= 0) x_change
= 0;else{}if (y_change
>= I_max
) y_change
= I_max
- 1;else if (y_change
<= 0) y_change
= 0;else{}g_dstImage
.at
<uchar
>(x_change
, y_change
) = 255;}}}else{a
= cos(theta
);b
= sin(theta
);c
= -1 * sin(theta
);d
= cos(theta
);for (int x
= I_max
/ 2;x
< I_max
/ 2 + 50;x
++) {for (int y
= I_max
/ 2;y
< I_max
/ 2 + 50;y
++) {x_change
= (x
- center_x
) * cos(theta
) - (y
- center_y
) * sin(theta
) + center_x
;y_change
= (x
- center_x
) * sin(theta
) + (y
- center_y
) * cos(theta
)+ center_y
;if (x_change
>= I_max
) x_change
= I_max
- 1;else if (x_change
<= 0) x_change
= 0;else{}if (y_change
>= I_max
) y_change
= I_max
- 1;else if (y_change
<= 0) y_change
= 0;else{}g_dstImage
.at
<uchar
>(x_change
, y_change
) = 255;}}}imshow("效果圖", g_dstImage
);
}
原圖如下:
接下來看具體變換:
1、平移變換
效果展示:
2、比例縮放
效果展示:
3、旋轉
這里的旋轉是以原點為中心點的,當我們以(center_x,center_y)為中點,則需要修改公式為:
X’=(X-center_x)*cos(theta)-(Y-center_y)*sin(theta) + center_x;
Y’=(X-center_x)*sin(theta)+(Y-center_y)*cos(theta) +center_y ;
效果展示:
4、對稱變換(不做展示)
1、關于X軸變換
2、關于Y軸變換
3、關于直線Y=X變換
4、關于直線Y=-X變換
5、錯切變換
效果展示:
6、復合變換
【4】圖像的投影變換
點共線特性:原本是一條直線,變換后還是一條直線
效果展示:
【5】應用
由原理可知,變換的本質就是通過對應點組的坐標來求解方程。一個變換是否理想,在公式不做調整的情況下就要看對應點的選擇。
這里我們一般選擇圖像的特征點。這些知識會在以后展開講,哲理不做過多擴展。(像上面的二維碼變換,我們選取的特征點考慮那三個定位點,當然還要再找一個特征點。以后掌握了這方面知識再補充。)
【6】Opencv自帶的變換函數:
Opencv中仿射變換的函數:warpAffine()函數
公式依據:
C++: void warpAffine (InputArray src, OutputArray dst, InputArray M, Size
dsize, int flags=INTER_LINEAR,intborderMode=BORDER_CONSTANT, const
Scalar& borderValue=Scalar() )
第一個參數,InputArray 類型的src,輸入圖像,即源圖像,填Mat類的對
象即可。
第二個參數,OutputArray 類型的dst, 函數調用后的運算結果存在這里,
需和源圖片有一樣的尺寸和類型。
第三個參數,InputArray 類型的M,2x3 的變換矩陣。
第四個參數,Size 類型的dsize,表示輸出圖像的尺寸。
第五個參數,int 類型的flags, 插值方法的標識符。此參數有默認值
INTER_ LINEAR(線性插值),可選的插值方式如下圖所示。
第六個參數,int類型的borderMode,邊界像素模式,默認值為
BORDER CONSTANT。
第七個參數,const Scalar&類型的borderValue, 在恒定的邊界情況下取的
值,默認值為Scalar(), 即0。
Opencv中計算二維旋轉變換矩陣: getRotationMatrix2D()函數
C++: Mat getRotationMatrix2D (Point2fcenter, double angle, double scale)
第一個參數,Point2f 類型的center,表示源圖像的旋轉中心。
第二個參數,double類型的angle,旋轉角度。角度為正值表示向逆時針旋轉(坐標原點是左上角)。
第三個參數,double 類型的scale,縮放系數。
int main()
{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE
), FOREGROUND_INTENSITY
| FOREGROUND_GREEN
); Point2f srcTriangle
[3];Point2f dstTriangle
[3];Mat
rotMat(2, 3, CV_32FC1
); Mat
warpMat(2, 3, CV_32FC1
); Mat srcImage
, dstImage_warp
, dstImage_warp_roate
;srcImage
= imread("D:\\opencv_picture_test\\形態學操作\\黑白.jpg");if (srcImage
.empty()){cout
<< "圖像加載失敗!" << endl
;return -1;}elsecout
<< "圖像加載成功!" << endl
<< endl
;dstImage_warp
= Mat
::zeros(srcImage
.rows
, srcImage
.cols
, srcImage
.type()); srcTriangle
[0] = Point2f(0, 0); srcTriangle
[1] = Point2f(0, 0);srcTriangle
[2] = Point2f(0, 0);dstTriangle
[0] = Point2f(0, 0);dstTriangle
[1] = Point2f(0, 0);dstTriangle
[2] = Point2f(0, 0);warpMat
= getAffineTransform(srcTriangle
, dstTriangle
); warpAffine(srcImage
,dstImage_warp
,warpMat
,dstImage_warp
.size());Point center
= Point(dstImage_warp
.cols
/ 2, dstImage_warp
.rows
/ 2); double angle
= -30.0; double scale
=0.8;rotMat
= getRotationMatrix2D(center
, angle
,scale
);warpAffine(dstImage_warp
,dstImage_warp_roate
, rotMat
,dstImage_warp
.size());namedWindow("原圖像", WINDOW_NORMAL
); imshow("原圖像", srcImage
);namedWindow("縮放圖", WINDOW_NORMAL
); imshow("縮放圖", dstImage_warp
);namedWindow("縮放旋轉圖", WINDOW_NORMAL
); imshow("縮放旋轉圖", dstImage_warp_roate
);waitKey(0);return 0;
}
效果:
PPT是盜用的我們李竹老師的,嘿嘿。
總結
以上是生活随笔為你收集整理的Opencv——几何空间变换(仿射变换和投影变换)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。