理论
设原始图像的任意点 P 0 ( x 0 , y 0 ) P_0(x_0, y_0) P0(x0,y0) 经顺时针旋转 β \beta β 角度后到新的位置 P ( x , y ) P(x,y) P(x,y),为表示方便,采用极坐标形式表示,原始点的角度为 α \alpha α。根据极坐标与直角坐标的关系,原始图像的点 P 0 ( x 0 , y 0 ) P_0(x_0, y_0) P0(x0,y0) 的极坐标为
{ x 0 = r c o s α y 0 = r s i n α \left\{ \begin{matrix} x_0 = r {\rm cos} \alpha \\ y_0 = r {\rm sin} \alpha \end{matrix} \right. {x0=rcosαy0=rsinα
旋转到新位置以后 P ( x , y ) P(x, y) P(x,y) 的极坐标为
{ x = r c o s ( α − β ) = r c o s α c o s β + r s i n α s i n β y = r s i n ( α − β ) = r s i n α c o s β − r c o s α s i n β \left\{ \begin{matrix} x = r {\rm cos} (\alpha - \beta) = r{\rm cos}\alpha {\rm cos} \beta + r{\rm sin}\alpha {\rm sin}\beta\\ y = r {\rm sin} (\alpha - \beta) = r{\rm sin}\alpha {\rm cos} \beta - r{\rm cos}\alpha {\rm sin}\beta \end{matrix} \right. {x=rcos(α−β)=rcosαcosβ+rsinαsinβy=rsin(α−β)=rsinαcosβ−rcosαsinβ
由于旋转后的点 P ( x , y ) P(x, y) P(x,y) 需要用 P 0 ( x 0 , y 0 ) P_0(x_0, y_0) P0(x0,y0) 表示,对上式进行简化,得
{ x = x 0 c o s β + y 0 s i n β y = − x 0 s i n β + y 0 c o s β \left\{ \begin{matrix} x = x_0 {\rm cos} \beta + y_0{\rm sin}\beta\\ y = -x_0 {\rm sin} \beta + y_0 {\rm cos}\beta \end{matrix} \right. {x=x0cosβ+y0sinβy=−x0sinβ+y0cosβ
用矩阵表示如下:
[ x y 1 ] = [ c o s β s i n β 0 − s i n β c o s β 0 0 0 1 ] [ x 0 y 0 1 ] \left[\begin{matrix} x \\ y \\ 1 \end{matrix}\right]= \left[\begin{matrix} {\rm cos} \beta & {\rm sin} \beta & 0\\ -{\rm sin} \beta & {\rm cos} \beta & 0\\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} x_0 \\ y_0 \\ 1 \end{matrix}\right] ⎣⎡xy1⎦⎤=⎣⎡cosβ−sinβ0sinβcosβ0001⎦⎤⎣⎡x0y01⎦⎤
记上式中变换矩阵为
R
=
[
c
o
s
β
s
i
n
β
0
−
s
i
n
β
c
o
s
β
0
0
0
1
]
R = \left[\begin{matrix} {\rm cos} \beta & {\rm sin} \beta & 0\\ -{\rm sin} \beta & {\rm cos} \beta & 0\\ 0 & 0 & 1 \end{matrix}\right]
R=⎣⎡cosβ−sinβ0sinβcosβ0001⎦⎤
为旋转矩阵。
上述变换是针对原点的,如果指定了旋转中心,可以先按上述方式进行旋转,再把旋转后的中心平移到旋转前的中心。具体地,设旋转前的中线坐标为
C
0
(
x
0
,
y
0
)
C_0(x_0, y_0)
C0(x0,y0),则旋转后的坐标为
C
(
x
,
y
)
C(x,y)
C(x,y),根据上面的关系,两个点的坐标关系即由上面矩阵变换确定。则旋转中心平移量为
C
C
0
⃗
=
C
0
−
C
\vec{CC_0}=C_0 - C
CC0=C0−C,代入
(
x
,
y
)
(x,y)
(x,y),可得
C
C
0
⃗
=
[
Δ
x
Δ
y
]
=
[
x
0
−
x
y
0
−
y
]
=
[
x
0
(
1
−
c
o
s
β
)
−
y
0
s
i
n
β
x
0
s
i
n
β
+
y
0
(
1
−
s
i
n
α
)
]
\vec{CC_0}= \left[ \begin{matrix} \Delta x\\ \Delta y \end{matrix} \right]= \left[ \begin{matrix} x_0 - x\\ y_0 - y \end{matrix} \right]=\left[ \begin{matrix} x_0(1-{\rm cos} \beta) - y_0{\rm sin}\beta\\ x_0 {\rm sin} \beta + y_0 (1 - {\rm sin}\alpha) \end{matrix} \right]
CC0=[ΔxΔy]=[x0−xy0−y]=[x0(1−cosβ)−y0sinβx0sinβ+y0(1−sinα)]
根据上一节,则平移对应的平移矩阵为
T = [ 1 0 Δ x 0 1 Δ y 0 0 1 ] T = \left[\begin{matrix} 1 & 0 & \Delta x\\ 0 & 1 & \Delta y\\ 0 & 0 & 1 \end{matrix}\right] T=⎣⎡100010ΔxΔy1⎦⎤
则旋转后再平移,对应矩阵为
M
=
T
R
=
[
1
0
Δ
x
0
1
Δ
y
0
0
1
]
[
c
o
s
β
s
i
n
β
0
−
s
i
n
β
c
o
s
β
0
0
0
1
]
=
[
c
o
s
β
s
i
n
β
Δ
x
−
s
i
n
β
c
o
s
β
Δ
y
0
0
1
]
=
[
c
o
s
β
s
i
n
β
x
0
(
1
−
c
o
s
β
)
−
y
0
s
i
n
β
−
s
i
n
β
c
o
s
β
x
0
s
i
n
β
+
y
0
(
1
−
s
i
n
α
)
0
0
1
]
M = TR = \left[\begin{matrix} 1 & 0 & \Delta x\\ 0 & 1 & \Delta y\\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} {\rm cos} \beta & {\rm sin} \beta & 0\\ -{\rm sin} \beta & {\rm cos} \beta & 0\\ 0 & 0 & 1 \end{matrix}\right] =\left[\begin{matrix} {\rm cos} \beta & {\rm sin} \beta & \Delta x\\ -{\rm sin} \beta & {\rm cos}\beta &\Delta y\\ 0 & 0 & 1 \end{matrix}\right] =\left[\begin{matrix} {\rm cos} \beta & {\rm sin} \beta & x_0(1-{\rm cos} \beta) - y_0{\rm sin}\beta \\ -{\rm sin} \beta & {\rm cos}\beta &x_0 {\rm sin} \beta + y_0 (1 - {\rm sin}\alpha)\\ 0 & 0 & 1 \end{matrix}\right]
M=TR=⎣⎡100010ΔxΔy1⎦⎤⎣⎡cosβ−sinβ0sinβcosβ0001⎦⎤=⎣⎡cosβ−sinβ0sinβcosβ0ΔxΔy1⎦⎤=⎣⎡cosβ−sinβ0sinβcosβ0x0(1−cosβ)−y0sinβx0sinβ+y0(1−sinα)1⎦⎤
对于 OPENCV 的
cv2.getRotationMatrix2D()
乘以缩放系数,并取了上述变换矩阵 M M M 的前两行(第三行恒为 [ 0 , 0 , 1 ] [0,0,1] [0,0,1]。
实现
代码
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def show(img):
if img.ndim == 2:
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
else:
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
img = cv.imread('pic/rabbit500x333.jpg')
# 以(80,100)为中心,顺时针旋转45度
rotateM = cv.getRotationMatrix2D((80, 100), 45, 1)
img_rotate = cv.warpAffine(img, rotateM, dsize=(500, 500))
show(img_rotate)
效果
说明:
- 未经许可,谢绝转载。
- 本教程为《数字图像处理Python OpenCV实战》的配套代码相关内容。
免费视频教程为0-6章(标题号≤6),可在此处点击观看。
所有课件及源代码可在此处下载:
链接:https://pan.baidu.com/s/198PySe_vebO3e06idHSQ6g
提取码:11o4
有问题可在QQ群(1079300899)指出,进群答案:数字图像处理。在本文评论指出可能导致回复很晚。