OpenCV : 仿射變換

幾何變換 : 仿射變換

仿射變換

[x~y~]=[a11a12a21a22][xy]+[a13a14]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\end{matrix}\right] = \left[\begin{matrix}a_{11} & a_{12}\\a_{21} & a_{22}\end{matrix} \right]\left[\begin{matrix}x \\ y\end{matrix}\right]+ \left[\begin{matrix}a_{13} \\ a_{14}\end{matrix}\right]

爲了計算方便(進行一些變換):齊次座標

[x~y~1]=[a11a12a13a21a22a23001][xy1]=A[xy1]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}a_{11} & a_{12} & a_{13}\\a_{21} & a_{22}& a_{23}\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]= A\left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]

平移

(x~,y~)=(x+tx,y+ty)(\tilde{x},\tilde{y}) = (x+t_x, y+t_y)
[x~y~1]=[10tx01ty001][xy1]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}1 & 0 & t_x\\0 & 1 & t_y\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]
[x~y~1]=[10tx01ty][xy1]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}1 & 0 & t_x\\0 & 1 & t_y\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]

放大和縮小

二維空間縮放:二維空間的座標(x,y)(x, y),以(0,0)(0, 0)爲中心在xx軸方向和yy軸方向上縮放.以縮放SS倍爲例:

  • (x~,y~)=(Sxx,Syy)(\tilde{x}, \tilde{y}) = (S_x*x, S_y*y)
  • Sx=SyS_x = S_y : 等比例縮放

[x~y~1]=[Sx000Sy0001][xy1]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}S_x & 0 & 0\\0 & S_y & 0\\ 0 & 0 & 1\end{matrix} \right]\left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]

二維空間:以任意座標x0,y0)x_0, y_0)爲中心進行縮放:(x~,y~)=(x0+Sx(xx0),y0+Sy(yy0))(\tilde{x}, \tilde{y}) = (x_0+S_x*(x-x_0), y_0+S_y*(y-y_0))

[x~y~1]=[10x001y0001][Sx000Sy0001][10x001y0001][xy1]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}1 & 0 & x_0\\0 & 1 & y_0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}S_x & 0 & 0\\0 & S_y & 0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}1 & 0 & -x_0\\0 & 1 & -y_0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]

順時針旋轉α\alpha

計算(x,y)(x~,y~)(x, y)\to(\tilde{x}, \tilde{y}), pp(x,y)(x, y)到原點的距離:
cosθ=xp,sinθ=ypcos\theta = \frac{x}{p}, sin\theta = \frac{y}{p}
cos(θ+α)cos(\theta + \alpha)
cos(θ+α)=cosθcosαsinθsinα=xpcosαypsinα=x~pcos(\theta + \alpha) = cos\theta cos\alpha - sin\theta sin\alpha = \frac{x}{p}cos\alpha - \frac{y}{p}sin\alpha = \frac{\tilde{x}}{p}
sin(θ+α)sin(\theta + \alpha)
sin(θ+α)=sinθcosα+cosθsinα=ypcosα+xpsinα=y~psin(\theta + \alpha) = sin\theta cos\alpha + cos\theta sin\alpha = \frac{y}{p}cos\alpha + \frac{x}{p}sin\alpha = \frac{\tilde{y}}{p}
x~,y~\tilde{x}, \tilde{y}

x~=xcosαysinα,y~=xsinα+ycosα\tilde{x} = xcos\alpha - ysin\alpha, \tilde{y} = xsin\alpha + ycos\alpha

矩陣形式

[x~y~1]=[cosαsinα0sinαcosα0001][xy1],A=[cosαsinα0sinαcosα0001]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}cos\alpha & -sin\alpha & 0\\sin\alpha & cos\alpha & 0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right], A = \left[\begin{matrix}cos\alpha & -sin\alpha & 0\\sin\alpha & cos\alpha & 0\\ 0 & 0 & 1\end{matrix}\right]

逆時針旋轉α\alpha

cos(θα)cos(\theta - \alpha)
cos(θα)=cosθcosα+sinθsinα=xpcosα+ypsinα=x~pcos(\theta - \alpha) = cos\theta cos\alpha + sin\theta sin\alpha = \frac{x}{p}cos\alpha + \frac{y}{p}sin\alpha = \frac{\tilde{x}}{p}
sin(θα)sin(\theta - \alpha)
sin(θα)=sinθcosαcosθsinα=ypcosαxpsinα=y~psin(\theta - \alpha) = sin\theta cos\alpha - cos\theta sin\alpha = \frac{y}{p}cos\alpha - \frac{x}{p}sin\alpha = \frac{\tilde{y}}{p}
x~,y~\tilde{x}, \tilde{y}

x~=xcosα+ysinα,y~=xsinα+ycosα\tilde{x} = xcos\alpha + ysin\alpha, \tilde{y} = -xsin\alpha + ycos\alpha

矩陣形式

[x~y~1]=[cosαsinα0sinαcosα0001][xy1],A=[cosαsinα0sinαcosα0001]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}cos\alpha & sin\alpha & 0\\-sin\alpha & cos\alpha & 0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right], A = \left[\begin{matrix}cos\alpha & sin\alpha & 0\\-sin\alpha & cos\alpha & 0\\ 0 & 0 & 1\end{matrix}\right]

從任意位置旋轉α\alpha矩陣形式

[x~y~1]=[10x001y0001][cosαsinα0sinαcosα0001][10x001y0001][xy1]=A[xy1]\left[\begin{matrix}\tilde{x} \\ \tilde{y}\\ 1\end{matrix}\right] = \left[\begin{matrix}1 & 0 & x_0\\0 & 1 & y_0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}cos\alpha & sin\alpha & 0\\-sin\alpha & cos\alpha & 0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}1 & 0 & -x_0\\0 & 1 & -y_0\\ 0 & 0 & 1\end{matrix}\right] \left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]= A\left[\begin{matrix}x \\ y \\ 1\end{matrix}\right]

計算放射矩陣

  • getAffineTransform(src, dst)
    1. Point2f[]:保存放射前後的座標,數據類型CV_64F
    2. Mat_:保存放射前後的座標,數據類型CV_32F
  • getRotationMatrix2D(center, angle, scale)
    1. center : 原座標
    2. angle : 角度
    3. scale : 縮放倍數
  • resize(Mat src, Mat dst, Size dsize, double fx=0, double fy=0, int interpolation)
    1. src : 輸入圖像矩陣
    2. dst : 輸出圖像矩陣
    3. dsize : (寬,高)輸出圖像大小
    4. fx, fy : 水平垂直方向的縮放比例
    5. interpolation : INTE_NEAREST, INTE_LINEAR(默認)
  • warpAffine(Mat src, Mat dst, Mat s, Size dsize)
    1. s : 放射變換矩陣
  • rotate(Mat src, Mat dst, int rotateCode)
    1. src : 輸入矩陣
    2. dst : 輸出矩陣
    3. rotateCode : ROTATE_90_CLOCKWISE : 順時針旋轉90度,ROTATE_180 : 順時針旋轉180度,ROTATE_90_COUNTERCLOCKWISE : 順時針旋轉270度
#include<iostream>
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Point2f src[] = { Point2f(0, 0), Point2f(20,0),Point2f(0,20) };
	Point2f dst[] = { Point2f(0,0),Point2f(20,0),Point2f(0,20) };
	Mat A = getAffineTransform(src, dst);
	cout << A << endl;
	return 0;
}
#include<iostream>
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src = (Mat_<float>(3, 2) << 0, 0, 20, 0, 0, 20);
	Mat dst = (Mat_<float>(3, 2) << 0, 0, 10, 0, 0, 10);
	Mat A = getAffineTransform(src, dst);
	cout << A << endl;
	return 0;
}

插值算法

把圖像看作是一個二維的圖像函數fIf_I
z=fI(x,y)=I(x,y),0<=x<W,0<=y<H,xN,yNz = f_I(x, y) = I(x,y), 0 <= x < W, 0< = y <H, x \in N, y \in N

  • NN : 整數集合
  • I(x,y)I(x, y) : 矩陣IIxxyy列的值
  • fIf_I : 圖像函數
  • fI(x,y)f_I(x, y) : 圖像座標(x,y)(x, y)處的值

(x,y)(x~,y~)(x, y) \to (\tilde{x}, \tilde{y})的空間變換關係如下:
[x~y~1]=A[xy1],A=[a11a12a13a21a22a23001]\left[\begin{matrix}\tilde{x}\\ \tilde{y}\\ 1\end{matrix}\right] = A\left[\begin{matrix}x\\ y\\ 1\end{matrix}\right], A =\left[\begin{matrix}a_{11}&a_{12}&a_{13}\\a_{21}&a_{22}&a_{23}\\0&0&1\end{matrix}\right]

圖像矩陣的放大fO(2x,2y)=fI(x,y)f_O(2x, 2y) = f_I(x, y):假設:(4,4)(2,2)(4,4) \longleftarrow (2,2),即fO(4,4)=fI(2,2)f_O(4,4) = f_I(2,2),同理fO(3,3)=fI(1,5,1.5)f_O(3,3)=f_I(1,5, 1.5),但是fIf_I(1.5,1.5)(1.5,1.5)處沒有函數值,因爲fIf_I只在第一象限的整數座標處有函數值,但是(1.5,1.5)(1.5, 1.5)周圍四個臨近的座標有函數值(1,1),(2,1),(1,2),(2,2)(1,1),(2,1),(1,2),(2,2),可以根據這四個位置的函數值估算fI(1.5,1.5)f_I(1.5, 1.5)的值.

最鄰近插值(輸出圖像會出現鋸齒狀)

最鄰近插值同上,也是找到目標座標四個相鄰的座標,從中找到一個距離目標最近的一個,假設爲(x^,y^)(\hat{x},\hat{y})
fI(x,y)=fI(x^,y^)f_I(x, y) = f_I(\hat{x}, \hat{y})

線性插值

已知座標(x0,y0),(x1,y1)(x_0,y_0),(x_1, y_1),要計算得到兩點所在直線上xxyy的值:

  1. xx已知求yy?
    yy0xx0=y1y0x1x0\frac{y-y_0}{x-x_0} = \frac{y_1 - y_0}{x_1 - x_0}
    y=y1y0x1x0(xx0)+y0y = \frac{y_1 - y_0}{x_1 - x_0}(x-x_0)+y_0
    已知yy計算xx同上
雙線性插值

顧名思義,雙線性插值就是線性插值的double,p1,p2,p3,p4p_1,p_2,p_3,p_4均已知,求OO
在這裏插入圖片描述

  1. 先計算aa, bb
    ya=yp2yp1xp2xp1(xaxp1)+yp1(1)y_a = \frac{y_{p_2}-y_{p_1}}{x_{p_2}-x_{p_1}}(x_a-x_{p_1})+y_{p_1} \tag{1}
    yb=yp4yp3xp4xp3(xbxp3)+yp3(2)y_b = \frac{y_{p_4}-y_{p_3}}{x_{p_4}-x_{p_3}}(x_b-x_{p_3})+y_{p_3} \tag{2}

  2. a,ba, b 已知求OO
    yO=yaybxaxb(xOxb)+yb(3)y_O = \frac{y_a -y_b}{x_a - x_b}(x_O - x_b) + y_b \tag{3}

圖像的縮放

#include<iostream>
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat I = imread("./People/wave.jpg", 1);
	if (!I.data)
		return -1;
	// 放大放射矩陣
	Mat s = (Mat_<float>(2, 3) << 2, 0, 0, 0, 2, 0);
	Mat dst1;
	// 利用放射矩陣縮放
	warpAffine(I, dst1, s, Size(I.cols * 2, I.rows * 2));
	Mat dst2;
	// resize 放大矩陣2倍
	resize(I, dst2, Size(I.cols * 2, I.rows * 2), 2, 2);
	Mat dst3;
	resize(I, dst3, Size(I.cols * 10, I.rows * 10), 10, 10);
	imshow("original img", I);
	imshow("warpAffine", dst1);
	imshow("resize x 2", dst2);
	imshow("resize x 10", dst3);
	waitKey(0);
}

圖像的旋轉

#include<iostream>
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat I = imread("./People/wave.jpg", 1);
	if (!I.data)
		return -1;
	Mat Ix10;
	resize(I, Ix10, Size(I.cols * 10, I.rows * 10), 10, 10);
	Mat I_90, I_180, I_270;
    // 順時針旋轉90, 180, 270
	rotate(Ix10, I_90, ROTATE_90_CLOCKWISE);
	rotate(Ix10, I_180, ROTATE_180);
	rotate(Ix10, I_270, ROTATE_90_CLOCKWISE);
	imshow("順時針旋轉90", I_90);
	imshow("順時針旋轉180", I_180);
	imshow("順時針旋轉270", I_270);
	waitKey(0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章