Bootstrap

cv2.getRotationMatrix2D的旋转矩阵的正确形式

在查找cv2.getRotationMatrix2D的这个函数时,看到很多博客给都是如下的式子,自己推导了一下发现好像是错了,现在给出推导过程,如果有错欢迎评论指出

以下图为例,首先图像坐标以左上为原点,图像中的点\(v(x,y)\)逆时针转到\(v^{'}(x^{'},y^{'})\),可以得到

​​​​​​​\(x^{'}=Rcos(\alpha -\theta )=Rcos\alpha cos\theta +Rsin\alpha sin\theta =xcos\theta +ysin\theta\)

\(y^{'}=Rsin(\alpha -\theta )=Rsin\alpha cos\theta -Rcos\alpha sin\theta =ycos\theta -xsin\theta\)

即 ​​​​​​​\(\begin{bmatrix} x^{'}\\ y^{'} \end{bmatrix}=\begin{bmatrix} cos\theta &sin\theta \\ -sin\theta &cos\theta \end{bmatrix}\begin{bmatrix} x\\ y \end{bmatrix}\)

这是图片以左上角原点的结果,实际应用中我们可以指定旋转中心,通常是图片的中心,这种情况下的做法是:

  1. 首先将旋转中心平移到原点
  2. 按上述描述的绕原点进行旋转
  3. 再将旋转中心平移回原来的位置

在计算机图形学中,为了统一将平移、旋转、缩放等用矩阵表示,需要引入齐次坐标。(假设使用​​​​​​​\(2\times 2\)的矩阵,是没有办法描述平移操作的,只有引入​​​​​​​\(3\times 3\)矩阵形式,才能统一描述二维中的平移、旋转、缩放操作。同理必须使用​​​​​​​\(4\times 4\)的矩阵才能统一描述三维的变换)

假设旋转中心为\((tx,ty)\),将旋转中心平移到原点后,任意一点\((x,y)\)变成\((x^{'},y^{'})\)

\(x^{'}=x-tx\)

\(y^{'}=y-ty\)

由于引入了齐次坐标,在描述二维坐标的时候,使用​​​​​​​\((x,y,w)\)的方式(一般​​​​​​​\(w=1\)),于是上述变换可以写成如下矩阵变换的形式

\(\begin{bmatrix} x^{'}\\ y^{'}\\ 1 \end{bmatrix}=\begin{bmatrix} 1 &0 &-tx \\ 0&1 & -ty\\ 0& 0 &1 \end{bmatrix}\begin{bmatrix} x\\ y\\ 1 \end{bmatrix}\)

将旋转中心平移回原位置同理,于是整个变换过程可以表示成如下所示的矩阵

\(\begin{bmatrix} x^{'}\\ y^{'}\\ 1 \end{bmatrix}=M\begin{bmatrix} x\\ y\\ 1 \end{bmatrix}\)

​​​​​​​\(M=\begin{bmatrix} 1 &0 &tx \\ 0 &1 &ty \\ 0&0 &1 \end{bmatrix}\begin{bmatrix} cos\theta &sin\theta &0 \\ -sin\theta &cos\theta &0 \\ 0&0 &1 \end{bmatrix}\begin{bmatrix} 1 &0 &-tx \\ 0& 1 &-ty \\ 0&0 & 1 \end{bmatrix}=\begin{bmatrix} cos\theta &sin\theta &(1-cos\theta)*tx-sin\theta*ty \\ -sin\theta&cos\theta & sin\theta*tx+(1-cos\theta)*ty\\ 0&0 &1 \end{bmatrix}\)

注意这里是左乘,因此算得时候要从右往左乘

到这里整个推导就完了,可以与第一个矩阵进行比较,其中

\(\alpha =cos\theta ,\beta =sin\theta,center_{x}=tx,center_{y}=ty\)

验证如下,其中cv2.getRotationMatrix2D第一个参数为旋转中心坐标,这里取(1,1),第二个为旋转角度取45,第三个为缩放比例,可以将这两个参数带入上面两个表达式算下并与结果对比,会发现文章最开始的那个式子是错的

import cv2
mat_rotation = cv2.getRotationMatrix2D((1, 1), 45, 1)
print(mat_rotation)

[[ 0.70710678  0.70710678 -0.41421356]
 [-0.70710678  0.70710678  1.        ]]

还可以参考PIL的rotate实现,会发现和上面的式子一样https://github.com/python-pillow/Pillow/blob/8dc5f692dbd9a418d8c441f0e2aa09a3f5c03508/src/PIL/Image.py#L1974

参考

旋转变换(一)旋转矩阵 - 莫水千流 - 博客园

Opencv:图像旋转,cv2.getRotationMatrix2D 和 cv2.warpAffine 函数_宁静致远*的博客-CSDN博客_opencv4旋转图像函数

;