什么是仿射变换
射变换是一种二维图像变换,可以通过旋转、缩放、平移和倾斜等操作改变图像的几何结构,同时保持图像中平行线的平行性。
主要是要涉及到仿射变换的M矩阵的推导,以及M矩阵的逆推导。
变换
关于点的变换,通常存在缩放、旋转、平移。将以上几种操作用矩阵表示的话可以表示成下以下:
旋转
旋转前后直线长度不变,设直线长度为
l
l
l,因此变换后有以下公式:
{
y
1
=
l
s
i
n
(
θ
+
β
)
x
1
=
l
c
o
s
(
θ
+
β
)
\begin{cases}y1=lsin(\theta+\beta) \\x1=lcos(\theta+\beta) \end{cases}
{y1=lsin(θ+β)x1=lcos(θ+β)
通过上式可得到:
{
y
1
=
y
cos
β
+
x
sin
β
x
1
=
x
cos
β
−
y
sin
β
\begin{cases}y1=y\cos\beta+x\sin\beta \\x1=x\cos\beta-y\sin\beta \end{cases}
{y1=ycosβ+xsinβx1=xcosβ−ysinβ
用矩阵表达:
[
x
1
y
1
]
=
[
cos
β
−
sin
β
sin
β
cos
β
]
[
x
y
]
\begin{bmatrix}x1 \\y1 \end{bmatrix}=\begin{bmatrix}\cos\beta & -\sin\beta \\\sin\beta & \cos\beta \end{bmatrix} \begin{bmatrix}x \\y \end{bmatrix}
[x1y1]=[cosβsinβ−sinβcosβ][xy]
但是由于opencv中图像的原点在左上角,x轴正方向在下,y轴正方向向右。因此旋转矩阵在图像上时是:
[
x
1
y
1
]
=
[
cos
β
sin
β
−
s
i
n
β
cos
β
]
[
x
y
]
\begin{bmatrix}x1 \\y1 \end{bmatrix}=\begin{bmatrix}\cos\beta & \sin\beta \\-sin\beta & \cos\beta \end{bmatrix} \begin{bmatrix}x \\y \end{bmatrix}
[x1y1]=[cosβ−sinβsinβcosβ][xy]
缩放
[ x 1 y 1 ] = [ s c a l e 0 0 s c a l e ] [ x y ] \begin{bmatrix}x1 \\y1 \end{bmatrix}=\begin{bmatrix}scale & 0 \\0 &scale\end{bmatrix} \begin{bmatrix}x \\y \end{bmatrix} [x1y1]=[scale00scale][xy]
旋转+缩放
[ x 1 y 1 ] = [ cos β × s c a l e sin β × s c a l e − s i n β × s c a l e cos β × s c a l e ] [ x y ] \begin{bmatrix}x1 \\y1 \end{bmatrix}=\begin{bmatrix}\cos\beta\times scale & \sin\beta\times scale \\-sin\beta\times scale & \cos\beta\times scale \end{bmatrix} \begin{bmatrix}x \\y \end{bmatrix} [x1y1]=[cosβ×scale−sinβ×scalesinβ×scalecosβ×scale][xy]
平移
[
x
1
y
1
]
=
[
1
0
0
1
]
[
x
y
]
+
[
o
x
o
y
]
\begin{bmatrix}x1 \\y1 \end{bmatrix}=\begin{bmatrix}1 & 0 \\0 &1\end{bmatrix} \begin{bmatrix}x \\y \end{bmatrix}+ \begin{bmatrix}ox\\oy \end{bmatrix}
[x1y1]=[1001][xy]+[oxoy]
由上式可以看出,平移是加法运算,如何合并成一个矩阵,答案是齐次矩阵。平移变换可用齐次坐标表示成以下格式:
[
x
1
y
1
1
]
=
[
1
0
o
x
0
1
o
y
0
0
1
]
[
x
y
1
]
\begin{bmatrix}x1 \\y1\\1 \end{bmatrix}=\begin{bmatrix}1 & 0 &ox \\0 & 1&oy \\0&0&1 \end{bmatrix}\begin{bmatrix}x \\y\\1 \end{bmatrix}
x1y11
=
100010oxoy1
xy1
旋转+平移+缩放
[
x
1
y
1
1
]
=
[
cos
β
×
s
c
a
l
e
sin
β
×
s
c
a
l
e
o
x
−
sin
β
×
s
c
a
l
e
cos
θ
×
s
c
a
l
e
o
y
0
0
1
]
[
x
y
1
]
\begin{bmatrix}x1 \\y1\\1 \end{bmatrix}=\begin{bmatrix}\cos\beta\times scale & \sin\beta\times scale &ox \\-\sin\beta\times scale & \cos\theta\times scale&oy \\0&0&1 \end{bmatrix}\begin{bmatrix}x \\y\\1 \end{bmatrix}
x1y11
=
cosβ×scale−sinβ×scale0sinβ×scalecosθ×scale0oxoy1
xy1
对于旋转矩阵而言,其逆矩阵就等于其转置,即
R
−
1
=
R
T
R^{-1}=R^{T}
R−1=RT,要想求反变换的话,只用求逆变换。
P
′
=
M
P
P^{'}=MP
P′=MP
P
=
M
−
1
P
′
P=M^{-1}P^{'}
P=M−1P′
对于目标检测来说,通常需要等比缩放且居中,通常可以拆解为以下三步:
s
c
a
l
e
=
m
i
n
(
d
s
t
.
w
i
d
t
h
o
r
i
g
i
n
.
w
i
d
t
h
,
d
s
t
.
h
e
i
g
h
t
o
r
i
g
i
n
.
h
e
i
g
h
t
)
scale=min(\frac{dst.width}{origin.width},\frac{dst.height}{origin.height})
scale=min(origin.widthdst.width,origin.heightdst.height)
M
=
M
=
[
s
c
a
l
e
0
−
s
c
a
l
e
∗
o
r
i
g
i
n
.
w
i
d
t
h
2
+
d
s
t
.
w
i
d
t
h
2
0
s
c
a
l
e
−
s
c
a
l
e
∗
o
r
i
g
i
n
.
h
e
i
g
h
t
2
+
d
s
t
.
h
e
i
g
h
t
2
]
M=M=\begin{bmatrix}scale & 0 &-\frac{scale*origin.width}{2}+\frac{dst.width}{2} \\0 & scale&-\frac{scale*origin.height}{2}+\frac{dst.height}{2} \end{bmatrix}
M=M=[scale00scale−2scale∗origin.width+2dst.width−2scale∗origin.height+2dst.height]
示例:主要用在yolov5的处理中
import numpy as np
import matplotlib.pyplot as plt
import cv2
def inv_align(M):
k=M[0,0]
b1=M[0,2]
b2=M[1,2]
return np.array(
[[1/k,0,-b1/k],
[0,-k/1,-b2/k]]
)
def align(image,dst_image):
orign_h,orign_w=image.shape[:2]
dst_h,dst_w=dst_image
k=min(dst_h/orign_h,dst_w/orign_w)
M=np.array([
[k,0,-k*orign_w*0.5+dst_w*0.5],
[0,k,-k*orign_h*0.5+dst_h*0.5]
])
return cv2.warpAffine(image,M,dst_image) ,inv_align(M)
if __name__=="__main__":
cat1=cv2.imread("cat1.png")
dst_image,M=align(cat1,(640,640))
cv2.imwrite("./dst_image.png",dst_image)
plt.imshow(dst_image[...,::-1])