使用 SciPy 实现仿射变换

246 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

前言

仿射变换将每个像素 f(x,y)f(x,y) 从输入图像变换到输出图像中的位置 (x,y)=T(x,y)(x',y')= T(x,y)。如果变换的像素坐标位于输出图像中的两个像素之间,通常通过反射(扭曲,warping)解决。在本节中,我们将使用 Scipy 库的 ndimage 模块函数实现图像上的仿射变换。

仿射变换原理

对于输出图像中位置 (x,y)(x',y') 处的每个像素,利用以下公式从输入图像中相应位置处获取像素值:

(x,y)=T1(x,y)(x,y)=T^{-1}(x',y')

如果输入图像中的像素位于两像素之间,则使用来自相邻像素的插值(例如,使用双线性插值)像素值进行计算。下图显示了向扭曲和反扭曲的概念:

绘图3.png

反向映射过程如下:

  • 创建输出图像
  • 对于输出图像中的每个像素,找到输入图像中的对应像素
  • 赋予输出像素对应的像素值

下图给出了每个仿射变换操作的矩阵( M):

绘图4.png

我们将通过将仿射转换矩阵传递给affine_transfom()函数函数来实现图像转换,affine_transfom()函数的输入参数如下:

scipy.ndimage.affine_transform(input, matrix, offset=0.0, output_shape= None, output=None, order=3, mode='constant', cval=0.0, prefilter=True)

应用仿射变换。输出图像中的位置 o 处的像素值由输入图像中的位置为 np.dot(matrix, o) + offset 处的像素值确定,其中矩阵和偏移量分别是传递给 affine_transform() 函数的 matriixoffset 参数。

 

使用 scipy.ndimage 实现仿射变换

接下来,我们使用 Scipy 库的 ndimage 模块实现仿射变换。

(1) 首先,导入所需的所有 Python 库:

from skimage.io import imread
from scipy.ndimage import affine_transform
import numpy as np
import matplotlib.pylab as plt

(2) 读取图像并通过传递 3×3 变换矩阵和偏移量使用函数 affine_transform() 来执行变换。 在这里,我们沿 x 轴和 y 轴(使用 @ 运算符乘上相应的变换矩阵)将图像沿正(逆时针)方向旋转 45 度:

im = imread("1.png")
rot_mat = np.array([[np.cos(np.pi/4),np.sin(np.pi/4), 0],[-np.sin(np.pi/4),np.cos(np.pi/4), 0], [0,0,1]])
shr_mat = np.array([[1, 0.45, 0], [0, 0.75, 0], [0, 0, 1]])
transformed = affine_transform(im, rot_mat@shr_mat, offset=[-im.shape[0]/4+25, im.shape[1]/2-50, 0], output_shape=im.shape)

(3) 绘制输入和输出图像,运行代码生成的输出图像:

plt.figure(figsize=(20,10))
plt.subplot(121), plt.imshow(im), plt.axis('off'), plt.title('Input image', size=10)
plt.subplot(122), plt.imshow(transformed), plt.axis('off'), plt.title('Output image', size=10)
plt.show()

Figure_3.png