前言
本篇讲的是图像的几何变换 的知识,其中具有一些代码实现。
一、图像几何变换
由于拍摄图像的角度、距离等原因,可能会需要对图像进行适当的几何变换。 几何变换又称为空间变换 ,是将一幅图像中的坐标位置映射到另外一幅图像中的新坐标位置。
二、解决几何变换问题的思路
一般要考虑原图像中的某个像素点 的坐标
(
x
0
,
y
0
)
(x_0,y_0)
(x0?,y0?)和此像素点映射到新图像中的新坐标
(
x
1
,
y
1
)
(x_1,y_1)
(x1?,y1?)之间的关系。可由下式描述:
x
1
=
f
1
(
x
0
,
y
0
)
x_1=f_1(x_0,y_0)
x1?=f1?(x0?,y0?);
y
1
=
f
2
(
x
0
,
y
0
)
y_1=f_2(x_0,y_0)
y1?=f2?(x0?,y0?)。
三、图像镜像
垂直镜像:图像的上半部分和下半部分以图像水平中轴线为中心轴进行对称变换。以下图为例:
水平镜像:图像的左半部分和右半部分以图像竖直中轴线为中心轴进行对称变换。以下图为例:
3.1、水平镜像的变换公式
(
x
0
,
y
0
)
(x_0,y_0)
(x0?,y0?)是原图像上的点,中心轴如图所示,水平镜像对应的新坐标点为:
x
1
=
x
0
x_1=x_0
x1?=x0?;
y
1
=
N
?
y
0
y_1=N-y_0
y1?=N?y0?;
水平镜像的变换矩阵:
代码示例如下:
read_image(Image, '图片路径')
mirror_image(Image, ImageMirror, 'column')
3.2、垂直镜像的变换公式
(
x
0
,
y
0
)
(x_0,y_0)
(x0?,y0?)是原图像上的点,中心轴如图所示,水平镜像对应的新坐标点为:
x
1
=
M
?
x
0
x_1=M-x_0
x1?=M?x0?;
y
1
=
y
0
y_1=y_0
y1?=y0?;
垂直镜像的变换矩阵:
代码示例如下:
read_image(Image, '图片路径')
mirror_image(Image, ImageMirror, 'row')
PS:要注意x轴和y轴分别是什么坐标轴,我的例子是x轴是纵轴、y轴是横轴,所以如果x、y轴有变化相应的公式以及变换矩阵也有变化。
四、图像转置
4.1、图像转置的公式
图像转置即行列互换,
(
x
0
,
y
0
)
(x_0,y_0)
(x0?,y0?)是原图像上的点,转置后对应的新坐标点为:
x
1
=
y
0
x_1=y_0
x1?=y0?;
y
1
=
x
0
y_1=x_0
y1?=x0?;注意:图像尺寸有可能改变。
4.2、图像转置的程序实现
代码示例如下:
read_image(Image, '图像路径')
mirror_image(Image, ImageMirror, 'diagonal')
五、图像平移
(
x
0
,
y
0
)
(x_0,y_0)
(x0?,y0?)是原图像上的点,图像水平平移量为
Δ
y
\varDelta y
Δy,垂直平移量为
Δ
x
\varDelta x
Δx,如图所示。 平移后的新坐标点为:
x
1
=
x
0
+
Δ
x
x_1=x_0+\varDelta x
x1?=x0?+Δx;
y
1
=
y
0
+
Δ
y
y_1=y_0+\varDelta y
y1?=y0?+Δy;
图像平移变换式的矩阵形式为:
以下为图像平移样例:
代码示例如下:
read_image(Image, '图像路径')
get_image_size(Image, Width, Height)
hom_mat2d_identity(HomMat2DIdentity)
hom_mat2d_translate(HomMat2DIdentity, 60, 60, HomMat2DTranslate)
affine_trans_image(Image, ImageAffinTrans, HomMat2DTranslate, 'weighted', 'false')
结果如下: 矩阵形式:
其中,关于最后一个函数的解释:
六、图像缩放
图像比例缩放变换:指将给定的图像在x轴方向按比例缩放r倍,在y轴方向上按比例缩放r倍,从而获得一幅新的图像。比例缩放前后两点
P
0
(
x
0
,
y
0
)
P_0(x_0,y_0)
P0?(x0?,y0?)、
P
(
x
,
y
)
P(x,y)
P(x,y)之间的关系可以表示为:
{
x
=
r
x
0
y
=
r
y
0
\begin{cases} {x=rx_0} \\ {y=ry_0}\end{cases}
{x=rx0?y=ry0??
矩阵形式:
[
x
y
1
]
=
[
r
0
0
0
r
0
0
0
1
]
[
x
0
y
0
1
]
\begin{bmatrix}{x}\\{y}\\{1}\end{bmatrix}=\begin{bmatrix}r & 0 & 0\\0 & r & 0\\0 & 0 & 1\end{bmatrix}\begin{bmatrix}{x_0}\\{y_0}\\{1}\end{bmatrix}
?
??xy1??
??=?
??r00?0r0?001??
???
??x0?y0?1??
?? 其中:
r
>
1
r>1
r>1,放大;
0
<
r
<
1
0<r<1
0<r<1,缩小
6.1、缩小
目的: 1、使缩小后的图像符合显示区域的大小要求; 2、生成原图像的缩略图。
图像的缩小操作,是在现有的信息里挑选所需要的有用信息。
如果图像按任意比例缩小,则需要计算所需选择的行列。
图像缩小实现算法:
图像缩小例题: 使用四舍五入策略
6.2、放大
图像的放大操作,需对尺寸放大后所多出来的空格填入适当的值,这是信息的估计问题,所以较图像的缩小要难一些。
图像放大一般分为按比例放大 和不按比例放大 两种:
- 按比例放大: 如果需要将原图像放大k倍,则将一个像素值填在新图像的
k
×
k
k\times k
k×k的子块中。
- 任意不按比例放大: 这种操作由于x方向和y方向的放大倍数不同一定带来图像的几何畸变。
- 图像放大倍数太大,会出现马赛克效应。
图像放大实现思路:
最简单的思想是如果需要将原图像放大为k倍,则将原图像中的每个像素值,填在新图像中对应的
k
×
k
k\times k
k×k大小的子块中。
图像放大实现方法:
设原图像大小为
M
×
N
M\times N
M×N,放大为
k
1
M
×
k
2
N
,
(
k
1
>
1
,
k
2
>
1
)
k_1M\times k_2N,(k_1>1,k_2>1)
k1?M×k2?N,(k1?>1,k2?>1)。算法步骤如下:
- 设旧图像是
F
(
i
,
j
)
,
i
=
1
,
2
,
.
.
.
,
M
,
j
=
1
,
2
,
.
.
.
,
N
F(i,j),i=1,2,...,M,j=1,2,...,N
F(i,j),i=1,2,...,M,j=1,2,...,N;新图像是
G
(
x
,
y
)
,
x
=
1
,
2
,
.
.
.
,
k
1
M
,
y
=
1
,
2
,
.
.
.
,
k
2
N
G(x,y),x=1,2,...,k_1M,y=1,2,...,k_2N
G(x,y),x=1,2,...,k1?M,y=1,2,...,k2?N。
-
G
(
x
,
y
)
=
F
(
c
1
?
x
,
c
2
?
y
)
,
c
1
=
1
k
1
,
c
2
=
1
k
2
G(x,y)=F(c_1\cdot x,c_2\cdot y),c_1=\frac {1}{k_1},c_2=\frac {1}{k_2}
G(x,y)=F(c1??x,c2??y),c1?=k1?1?,c2?=k2?1?
图像的成倍放大效果示例:
图像大比例放大时的马赛克效应:
6.3、灰度级插值方法
思考问题: 如果放大倍数太大,按照前面的方法处理会出现马赛克效应。如果这个问题交给你,有没有办法解决?或者想办法至少使之有所改善?
最邻近插值法(nearest neighbor interpolation)
- 最简单的插值方法是最邻近插值,即选择
离它所映射到的位置最近的输入像素的灰度值 为插值结果。 - 数学表示为:
f
(
x
)
=
f
(
x
k
)
f(x)=f(x_k)
f(x)=f(xk?)
-
1
2
(
x
k
?
1
+
x
k
)
<
x
<
1
2
(
x
k
+
x
k
+
1
)
\frac 1 2(x_{k-1}+x_k)<x<\frac 1 2(x_{k}+x_{k+1})
21?(xk?1?+xk?)<x<21?(xk?+xk+1?)
双线性插值(bilinear interpolation)
- 双线性插值法是对最邻近插值法的一种改进,即用线性内插方法,根据点的四个相邻点的灰度值,分别在x和y方向上进行两次线性插值,如下图:
基本算法思想: - 假设输出图像的宽度为W,高度为H;
- 输入图像的宽度为w,高度为h;
- 要将输入图像的尺度拉伸或压缩变换至输出图像的尺度;
- 按照线性插值的方法,将输入图像的宽度方向分为W等份,高度方向分为H等份,那么输出图像中任意一点
(
u
0
,
v
0
)
(u_0,v_0)
(u0?,v0?)的灰度值就应该由输入图像中四点
(
u
,
v
)
(u,v)
(u,v)、
(
u
+
1
,
v
)
(u+1,v)
(u+1,v)、
(
u
,
v
+
1
)
(u,v+1)
(u,v+1)和
(
u
+
1
,
v
+
1
)
(u+1,v+1)
(u+1,v+1)的灰度值来确定。
横坐标轴是y轴 按比例放大图像:
插值算法示例:
代码如下:
zoom_image_size(Image, ImageZoom, Width1, Height1, Interpolation)
七、图像的旋转变换
一般图像的旋转是以图像的中心为原点,旋转一定的角度,即将图像上的所有像素都旋转一个相同的角度。
图像的旋转变换也可用矩阵变换表示。设点
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)。如下图所示:
旋转前:
{
x
0
=
r
c
o
s
α
y
0
=
r
s
i
n
α
\begin{cases} {x_0=rcos\alpha} \\ {y_0=rsin\alpha}\end{cases}
{x0?=rcosαy0?=rsinα? 旋转后:
{
x
1
=
r
c
o
s
(
α
?
β
)
=
r
c
o
s
α
c
o
s
β
+
r
s
i
n
α
s
i
n
β
y
1
=
r
s
i
n
(
α
?
β
)
=
r
s
i
n
α
c
o
s
β
?
r
c
o
s
α
s
i
n
β
\begin{cases}{x_1=rcos(\alpha-\beta)=rcos\alpha cos\beta+rsin\alpha sin\beta}\\{y_1=rsin(\alpha-\beta)=rsin\alpha cos\beta-rcos\alpha sin\beta}\end{cases}
{x1?=rcos(α?β)=rcosαcosβ+rsinαsinβy1?=rsin(α?β)=rsinαcosβ?rcosαsinβ? 代入得:
{
x
1
=
x
0
c
o
s
β
+
y
0
s
i
n
β
y
1
=
?
x
0
s
i
n
β
+
y
0
c
o
s
β
\begin{cases}{x_1=x_0cos\beta+y_0sin\beta}\\{y_1=-x_0sin\beta+y_0cos\beta}\end{cases}
{x1?=x0?cosβ+y0?sinβy1?=?x0?sinβ+y0?cosβ? 矩阵形式为:
[
x
1
y
1
1
]
=
[
c
o
s
β
s
i
n
β
0
?
s
i
n
β
c
o
s
β
0
0
0
1
]
[
x
0
y
0
1
]
\begin{bmatrix}{x_1}\\{y_1}\\{1}\end{bmatrix}=\begin{bmatrix}cos\beta & sin\beta & 0\\-sin\beta & cos\beta & 0\\0 & 0 & 1\end{bmatrix}\begin{bmatrix}{x_0}\\{y_0}\\{1}\end{bmatrix}
?
??x1?y1?1??
??=?
??cosβ?sinβ0?sinβcosβ0?001??
???
??x0?y0?1??
??
代码如下:
rotate_image(Image, ImageRotate, Phi, Interpolation)
图像示例: 代码示例如下:
rotate_image(Image, ImageRotate, 45, 'constant')
hom_mat2d_identity(HomMat2DIdentity)
hom_mat2d_rotate(HomMat2DIdentity, 0.78, 200, 200, HomMat2DRotate)
affine_trans_image(Image, ImageAffinTrans, HomMat2DRotate, 'weighted', 'false')
结束!
|