图像变换
图像处理过程中经常存在着大小,位置,角度不同的图像,如果想统一的用一个标准处理,就需要图像变换将其变到需要的状态。常用的图像变换有平移、旋转、缩放、透视等。本章节主要讨论的就是这几种常用的变换方法。
一、基本变换
1.平移
平移意思是将物体从A点沿某个方向移动至B点,不改变物体的大小形状。如果在坐标系下,可以表示为沿着
x
,
y
x,y
x,y方向分别移动
△
x
,
△
y
\triangle x,\triangle y
△x,△y。用一个公式可以表示为:
x
′
=
x
+
△
x
y
′
=
y
+
△
y
x'=x+\triangle x \\ y'=y+\triangle y
x′=x+△xy′=y+△y
其中
x
′
,
y
′
x',y'
x′,y′表示移动后位置,
x
,
y
x,y
x,y表示移动前位置,
△
x
,
△
y
\triangle x,\triangle y
△x,△y表示移动距离。
2.旋转
旋转是物体绕着某个中心点旋转某个角度的变换,如果用直角坐标系表示。旋转变换可以表示为:
x
′
=
x
∗
c
o
s
(
θ
)
−
y
∗
s
i
n
(
θ
)
y
′
=
x
∗
s
i
n
(
θ
)
+
y
∗
c
o
s
(
θ
)
x'=x*cos(\theta)-y*sin(\theta) \\ y'=x*sin(\theta)+y*cos(\theta)
x′=x∗cos(θ)−y∗sin(θ)y′=x∗sin(θ)+y∗cos(θ)
其中
x
′
,
y
′
x',y'
x′,y′表示旋转后位置,
x
,
y
x,y
x,y表示旋转前位置,
θ
\theta
θ表示旋转角度。
3.缩放
假设某点位置坐标在二维图像上沿
x
x
x轴放大
S
x
S_x
Sx倍,沿
y
y
y轴放大
S
y
S_y
Sy倍,那么变换后该店位置坐标为:
x
′
=
S
x
∗
x
y
′
=
S
y
∗
y
x'=S_x*x \\ y'=S_y*y
x′=Sx∗xy′=Sy∗y
其中
x
′
,
y
′
x',y'
x′,y′表示放大后位置,
x
,
y
x,y
x,y表示放大前位置,
S
x
,
S
y
S_x,S_y
Sx,Sy分别表示
x
x
x方向和
y
y
y方向放大系数。
二、认识提升
如果将上述几种变换做一些比较和扩展,那么变换的规律可以更深入的了解,对于熟练掌握和应用有很大好处。
首先前两个变换平移和旋转都不改变物体本身大小,改变的仅仅是位置,这类变换也被称为刚体变换,含义就是被变换的物体像刚体一样没有形变。从数学角度看,就是变换前后两点间的距离依旧保持不变。该变换是个线性变换,设刚体变换为
M
M
M,则变换可以表示为:
[
x
′
y
′
]
=
M
∗
[
x
y
]
+
[
△
x
△
y
]
\begin {bmatrix} x' \\ y'\end {bmatrix}=M*\begin {bmatrix} x \\ y\end {bmatrix}+\begin {bmatrix} \triangle x \\ \triangle y\end {bmatrix}
[x′y′]=M∗[xy]+[△x△y]
那么变换前后保持距离不变,对于二维变换就是
d
e
t
(
M
)
=
∣
M
∣
=
±
1
det(M)=|M|=\pm1
det(M)=∣M∣=±1(思考一下为什么?),对于2维变换来说:
M
=
[
a
b
c
d
]
(1)
M= \begin{bmatrix} a&b\\ c&d \end{bmatrix} \tag{1}
M=[acbd](1)
det
(
M
)
=
∣
a
b
c
d
∣
=
±
1
(2)
\det(M)= \begin{vmatrix} a&b\\ c&d \end{vmatrix}=\pm1 \tag{2}
det(M)=∣∣∣∣acbd∣∣∣∣=±1(2)
我们先取
d
e
t
(
M
)
=
1
det(M)=1
det(M)=1这个分支看看,都是什么组成的,首先变换前后距离不变,假设点的位置向量是
P
⃗
=
(
x
,
y
)
\vec{P}=(x,y)
P=(x,y),那么按照距离的内积表示:
变换前:
d
=
<
P
⃗
,
P
⃗
>
=
(
x
,
y
)
(
x
,
y
)
T
d=<\vec{P},\vec{P}>=(x,y) (x,y)^{T}
d=<P,P>=(x,y)(x,y)T
变换后:
d
′
=
<
P
′
⃗
,
P
′
⃗
>
=
(
x
′
,
y
′
)
(
x
′
,
y
′
)
T
d'=<\vec{P'},\vec{P'}>=(x',y') (x',y')^{T}
d′=<P′,P′>=(x′,y′)(x′,y′)T
这样就是:
d
=
d
′
⟹
(
x
′
,
y
′
)
(
x
′
,
y
′
)
T
=
(
x
,
y
)
(
x
,
y
)
T
d=d'\Longrightarrow(x',y') (x',y')^{T}=(x,y) (x,y)^{T}
d=d′⟹(x′,y′)(x′,y′)T=(x,y)(x,y)T
有
(
M
∗
(
x
,
y
)
T
)
T
∗
(
M
∗
(
x
,
y
)
T
)
=
(
x
,
y
)
M
T
M
(
x
,
y
)
T
=
(
x
,
y
)
∗
(
x
,
y
)
T
(M*(x,y)^T)^T*(M*(x,y)^T)=(x,y)M^TM(x,y)^T=(x,y)*(x,y)^T
(M∗(x,y)T)T∗(M∗(x,y)T)=(x,y)MTM(x,y)T=(x,y)∗(x,y)T,所以
M
T
M
=
I
M^TM=I
MTM=I
矩阵展开得到三个方程组成的方程组:
{
a
2
+
c
2
=
1
a
b
+
c
d
=
0
b
2
+
d
2
=
1
\begin{cases} a^2+c^2=1\\ ab+cd=0\\ b^2+d^2=1\\ \end{cases}
⎩⎪⎨⎪⎧a2+c2=1ab+cd=0b2+d2=1
同时加入
det
(
M
)
=
1
\det(M)=1
det(M)=1这个条件,具体将行列式展开就有:
(
a
∗
d
−
b
∗
c
)
=
1
(a*d-b*c)=1
(a∗d−b∗c)=1,我们得到4个参数,4个方程,但解不唯一,取一组常用解就是:
a
=
c
o
s
(
θ
)
,
b
=
−
s
i
n
(
θ
)
,
c
=
s
i
n
(
θ
)
,
d
=
c
o
s
(
θ
)
a=cos(\theta),b=-sin(\theta),c=sin(\theta),d=cos(\theta)
a=cos(θ),b=−sin(θ),c=sin(θ),d=cos(θ)
这是一个旋转矩阵
M
=
[
c
o
s
(
θ
)
−
s
i
n
(
θ
)
s
i
n
(
θ
)
c
o
s
(
θ
)
]
M=\begin{bmatrix} cos(\theta)&-sin(\theta)\\ sin(\theta)&cos(\theta) \end{bmatrix}
M=[cos(θ)sin(θ)−sin(θ)cos(θ)]
当
θ
=
0
\theta=0
θ=0时,
M
=
[
1
0
0
1
]
M=\begin{bmatrix} 1&0\\ 0&1 \end{bmatrix}
M=[1001]是一个恒等变换。
如果时
det
(
M
)
=
−
1
\det(M)=-1
det(M)=−1,这些方程的解组成的矩阵就是一个镜像旋转变换。这里篇幅所限,以后单独讨论。
所有这些都是正交变换。
在任意正交变换下不变的几何性质有:距离(长度)、角度、面积、对称性。
缩放变换不属于正交变换,它归类为仿射变换的一种,包括正交变换也属于仿射变换。仿射变换的性质:共线、平行、相交、线上点的顺序、中心对称等。回到缩放变换来,缩放变换的变换矩阵可以表示成:
[
x
′
y
′
]
=
[
S
x
0
0
S
y
]
[
x
y
]
\begin {bmatrix} x' \\ y'\end {bmatrix}=\begin{bmatrix} S_x&0\\ 0&S_y \end{bmatrix}\begin {bmatrix} x \\ y\end {bmatrix}
[x′y′]=[Sx00Sy][xy]
上述平移、旋转、缩放等变换矩阵不满足齐次性,运算起来不方便,为此将欧式空间映射到仿射空间中变换,使得变换矩阵构成群元,这样具有封闭性,这个思维转变比较重要。
这样上述变换对应成
平移变换:
T
=
[
1
0
△
x
0
1
△
y
0
0
1
]
T=\begin{bmatrix} 1&0&\triangle x\\0&1&\triangle y\\0&0&1\end{bmatrix}
T=⎣⎡100010△x△y1⎦⎤
旋转变换:
T
=
[
c
o
s
(
θ
)
−
s
i
n
(
θ
)
0
s
i
n
(
θ
)
c
o
s
(
θ
)
0
0
0
1
]
T=\begin{bmatrix} cos(\theta)&-sin(\theta)& 0\\sin(\theta)&cos(\theta)&0\\0&0&1\end{bmatrix}
T=⎣⎡cos(θ)sin(θ)0−sin(θ)cos(θ)0001⎦⎤
缩放变换:
T
=
[
S
x
0
0
0
S
y
0
0
0
1
]
T=\begin{bmatrix} S_x&0& 0\\0&S_y&0\\0&0&1\end{bmatrix}
T=⎣⎡Sx000Sy0001⎦⎤
有了这种形式:平移、旋转、缩放矩阵乘法可以连乘,可以混合乘,很方便。
举例:平移变换:
T
1
,
T
2
T_1,T_2
T1,T2分别为:
T
1
=
[
1
0
△
x
1
0
1
△
y
1
0
0
1
]
T_1=\begin{bmatrix} 1&0&\triangle x_1\\0&1&\triangle y_1\\0&0&1\end{bmatrix}
T1=⎣⎡100010△x1△y11⎦⎤,
T
2
=
[
1
0
△
x
2
0
1
△
y
2
0
0
1
]
T_2=\begin{bmatrix} 1&0&\triangle x_2\\0&1&\triangle y_2\\0&0&1\end{bmatrix}
T2=⎣⎡100010△x2△y21⎦⎤
合成后还是一个平移变换(没有变坏掉 ^_^):
T
=
T
1
∗
T
2
=
[
1
0
△
x
1
+
△
x
2
0
1
△
y
1
+
△
y
2
0
0
1
]
T=T_1*T_2=\begin{bmatrix} 1&0&\triangle x_1+\triangle x_2\\0&1&\triangle y_1+\triangle y_2\\0&0&1\end{bmatrix}
T=T1∗T2=⎣⎡100010△x1+△x2△y1+△y21⎦⎤
旋转矩阵
T
1
,
T
2
T_1,T_2
T1,T2分别为:
T
1
=
[
c
o
s
(
θ
1
)
−
s
i
n
(
θ
1
)
0
s
i
n
(
θ
1
)
c
o
s
(
θ
1
)
0
0
0
1
]
T_1=\begin{bmatrix} cos(\theta_1)&-sin(\theta_1)&0\\sin(\theta_1)&cos(\theta_1)&0\\0&0&1\end{bmatrix}
T1=⎣⎡cos(θ1)sin(θ1)0−sin(θ1)cos(θ1)0001⎦⎤,
T
2
=
[
c
o
s
(
θ
2
)
−
s
i
n
(
θ
2
)
0
s
i
n
(
θ
2
)
c
o
s
(
θ
2
)
0
0
0
1
]
T_2=\begin{bmatrix} cos(\theta_2)&-sin(\theta_2)&0\\sin(\theta_2)&cos(\theta_2)&0\\0&0&1\end{bmatrix}
T2=⎣⎡cos(θ2)sin(θ2)0−sin(θ2)cos(θ2)0001⎦⎤
合成后还是旋转矩阵:
T
=
T
1
∗
T
2
=
[
c
o
s
(
θ
1
+
θ
2
)
−
s
i
n
(
θ
1
+
θ
2
)
0
s
i
n
(
θ
1
+
θ
2
)
c
o
s
(
θ
1
+
θ
2
)
0
0
0
1
]
T=T_1*T_2=\begin{bmatrix} cos(\theta_1+\theta_2)&-sin(\theta_1+\theta_2)&0\\sin(\theta_1+\theta_2)&cos(\theta_1+\theta_2)&0\\0&0&1\end{bmatrix}
T=T1∗T2=⎣⎡cos(θ1+θ2)sin(θ1+θ2)0−sin(θ1+θ2)cos(θ1+θ2)0001⎦⎤
缩放矩阵也是类似的,这里就不写了。
思考一下旋转和平移合成是什么结果?大家可以试试!
我们整理再扩展一下变换:
正交变换包含平移、旋转、镜像等变换;
相似变换=位似变换与正交变换的合成;
缩放变换包含相似变换、伸缩变换;
由伸缩变换延伸出错切变换;
相似变换、位似变换、伸缩变换、错切变换的共同性质是把共线三点映射成共线三点,且都为可逆变换,这个共同性质抽象出了仿射变换。
所以仿射变换包含正交变换、斜切变换、缩放变换、压缩、错切等变换。
而射影变换是更一般的线性变换,是射影平面到自身的映射,也就是射影平面上共线三点映射到射影平面共线三点的映射。(注意和仿射变换区别)
射影变换也叫透视变换、投影变换
变换矩阵表示为
M
=
[
A
t
c
t
1
]
M=\begin{bmatrix} A&t\\ c^t&1 \end{bmatrix}
M=[Actt1],可以看出射影变换的自由度为
n
2
−
1
n^2-1
n2−1
上述变换统一到变换群的框架中,从群的角度分类几何变换可以更清晰的理解其中的意义。
射影变换经常用于视觉校正中,方便观察和处理。这里过多不介绍了,以后再专门讲解。
三、应用
有了上述理论,将它用于实际中,更有意义,下面使用的是halcon软件演示的效果,不了解halcon的可以自行百度一下,halcon使用起来比较方便,容易上手。以后补充Opencv版的变换。
halcon中算子使用方法
- 创建一个空的仿射变换矩阵
hom_mat2d_identity (HomMat2DIdentity) - 设置平移矩阵
hom_mat2d_translate (HomMat2DIdentity, T x T_x Tx, T y T_y Ty,HomMat2DTranslate) - 设置旋转矩阵 以
(
P
x
,
P
y
)
(P_x,P_y)
(Px,Py)为参考点进行旋转
hom_mat2d_rotate (HomMat2DTranslate, θ \theta θ, P x P_x Px, P y P_y Py, HomMat2DRotate) - 设置缩放矩阵 以
(
P
x
,
P
y
)
(P_x,P_y)
(Px,Py)为参考点进行缩放
hom_mat2d_scale (HomMat2DRotate, S x S_x Sx, S y S_y Sy, P x P_x Px, P y P_y Py, HomMat2DScale) - 求出投影变换算子
hom_vector_to_proj_hom_mat2d( Px, Py, Pw, Qx, Qy, Qw, Method,HomMat2DScale) - 投影变换
projective_trans_image (Image_display, Image_rectified, HomMat2D, ‘bilinear’, ‘false’, ‘false’)
1.平移变换
*读取图像
read_image (Image, 'C:/Users/DELL/Desktop/1.jpg')
*创建单元矩阵
hom_mat2d_identity (HomMat2DIdentity)
*创建平移矩阵移动150,200
hom_mat2d_translate (HomMat2DIdentity, 150, 200, HomMat2DTranslate)
*对图像做平移变换
affine_trans_image (Image, ImageRotate, HomMat2DTranslate, 'constant', 'false')
效果如下:


2.旋转变换
*读取图像
read_image (Image, '2.jpg')
*创建单元矩阵
hom_mat2d_identity (HomMat2DIdentity)
*在单元矩阵上修改成旋转矩阵
hom_mat2d_rotate (HomMat2DIdentity, rad(30), 360, 500, HomMat2DRotate)
*应用矩阵做旋转变换
affine_trans_image (Image, ImageRotate, HomMat2DRotate, 'constant', 'false')
效果如下:


3.射影变换:
*关闭当前显示窗口,清空屏幕
dev_close_window ()
*读取图像
read_image (Image, 'image.jpg')
*将图像转为灰度图像,单通道
rgb1_to_gray (Image, GrayImage)
*获取图像的尺寸---宽imageWidth和高imageHeight
get_image_size(Image,imageWidth, imageHeight)
*新建窗口,适应图像尺寸,方便显示
dev_open_window (0, 0, imageWidth, imageHeight, 'black', WindowHandle1)
*显示图像,用于观察
dev_display (GrayImage)
*初始化角点坐标,相当于初始化数组,存放变换的角点
XCoordCorners := []
YCoordCorners := []
***************下面时图像处理,提取出变换的点*******************
*阈值处理,提取较暗的区域
threshold(GrayImage,DarkRegion,0, 80)
*分离不相连的区域
connection (DarkRegion, ConnectedRegions)
*选择面积最大的暗色区域,即屏幕区域
select_shape_std (ConnectedRegions, displayRegion, 'max_area', 70)
*裁剪屏幕区域
reduce_domain (GrayImage, displayRegion, displayImage)
*创建边缘轮廓
gen_contour_region_xld (displayRegion, Contours, 'border')
*将轮廓分割为边
segment_contours_xld (Contours, ContoursSplit, 'lines', 5, 4, 2)
*获取边的数量
count_obj (ContoursSplit, Number)
*存储每条边的起点位置
for index:=1 to Number by 1
select_obj(ContoursSplit, ObjectCurrent, index)
*拟合每条边
fit_line_contour_xld (ObjectCurrent, 'tukey', -1, 0, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)
*存储每条边的顶点x坐标
tuple_concat (XCoordCorners, RowBegin, XCoordCorners)
*存储每条边的顶点y坐标
tuple_concat (YCoordCorners, ColBegin, YCoordCorners)
endfor
**************************************************************************
*****现在XCoordCorners和YCoordCorners是提取出的角点,分别保存x和y坐标,共四个点。
*****建立要变换到的目标的坐标
XOff:= 100
YOff:= 100*imageHeight/imageWidth
*****用提取的4个点和创建目标点构建仿射变换矩阵
hom_vector_to_proj_hom_mat2d (XCoordCorners, YCoordCorners, [1,1,1,1], [YOff,YOff,imageHeight-YOff,imageHeight-YOff], [XOff,imageWidth-XOff,imageWidth-XOff,XOff], [1,1,1,1], 'normalized_dlt', HomMat2D)
*对图像做投影变换
projective_trans_image (Image, Image_rectified, HomMat2D, 'bilinear', 'false', 'false')
* 显示校正结果
dev_display (Image_rectified)
效果如下:

