图像扭曲与逆扭曲详解

  • 0. 前言
  • 1. 使用 scikit-image warp() 函数执行图像变换
    • 1.1 scikit-image warp() 函数原理
    • 1.2 利用 warp() 函数实现图像变换
  • 2. 漩涡变换详解
    • 2.1 漩涡变换原理
    • 2.2 使用 scikit-image warp() 实现漩涡变换
    • 2.3 使用 scipy.ndimage 实现漩涡变换
  • 3. 使用 scikit-image 实现弹性变形
    • 3.1 弹性变形原理
    • 3.2 实现弹性变形
  • 小结
  • 系列链接

0. 前言

我们已经知道,可以将图像变换分为线性变换与非线性变换两类,在《图像线性变换》一节中,我们介绍了如何在图像上应用欧几里得变换(例如,旋转、反射)和仿射转换。在本节中,我们将进一步学习如何利用 scikit-image 库执行图像变换,除了线性变换外,本节着重讲解了如何执行漩涡变换、弹性变换等非线性变换。

1. 使用 scikit-image warp() 函数执行图像变换

2D 线性几何变换是点转换,它们会被应用于图像中的每个像素,以得到变换后的输出图像。本节中,我们将介绍如何使用 scikit-image 库中的 warp() 函数来执行图像变换。

1.1 scikit-image warp() 函数原理

对于变换后的输出图像中的像素值 f(x′,y′)f(x',y')f(x′,y′) 可以使用以下方程式在输入图像对应位置 (u,v)(u, v)(u,v) 处获取,将得到的像素值赋值给输出图像即可得到结果:

f(x′,y′)=g(u,v)f(x',y')=g(u,v) f(x′,y′)=g(u,v)

其中,x′x'x′ 和 y′y'y′ 分别表示沿 xxx 和 yyy 轴的变换 x(u,v)=x′x(u,v)= x'x(u,v)=x′,y(u,v)=y’y(u,v)=y’y(u,v)=y’,我们也可以使用反扭曲来实现图像变换。使用 warp() 函数是更通用的图像变换方式,可用于实现线性(例如,使用矩阵乘法来实现的变换)和非线性图像变换。使用 warp() 函数执行图像变换,我们需要提供(反向)变换函数,而非变换矩阵。

1.2 利用 warp() 函数实现图像变换

根据 scikit-image 文档,我们得知 warp() 函数可以通过使用如下输入参数调用,利用该函数我们可以以更通用的方式实现图像变换(函数的输入参数如下):

skimage.transform.warp(image, inverse_map, map_args={}, output_shape= None, order=1, mode='constant', cval=0.0, clip=True, preserve_range=False)

warp() 函数根据给定的坐标变换函数 inverse_map 扭曲图像 image。接下来,我们实际应用 warp() 函数实现图像变换。

(1) 首先,导入所有所需的库,从 scikit-image 库的 transform 模块中导入 warp 函数:

from skimage.io import imread
from skimage.transform import warp
import matplotlib.pylab as plt

(2) 接下来,定义 translate() 函数,该函数用于在 warp() 函数中作为 inverse_map 参数实现像素坐标变换:

def translate(xy, t_x, t_y):xy[:, 0] -= t_yxy[:, 1] -= t_xreturn xy

(3) 读取输入图像,并将输入图像与变换函数一起传入 warp() 函数作为参数:

im = imread('1.png')
im = warp(im, translate, map_args={'t_x':-250, 't_y':200}) # 创建字典用于变换参数
plt.imshow(im)
plt.title('Translated image', size=20)
plt.show()

下图显示了程序执行后的输出,即将变换函数应用于输入图像后得到的输出图像:

2. 漩涡变换详解

在上一小节中,我们学习了如何执行图像的线性变换,在本节中,我们将学习如何实现图像的非线性变换——漩涡变换 (swirl transform)。

2.1 漩涡变换原理

我们假设输出图像中的坐标为 (x,y)(x,y)(x,y),漩涡变换的反向映射首先应计算其相对于中心 (x0,y0)(x_0,y_0)(x0​,y0​) 的极坐标:
θ=arctan(yx)ρ=(x−x0)2+(y−y0)2\theta=arctan(\frac y x) \\ ρ=\sqrt {(x-x_0)^2+(y-y_0)^2} θ=arctan(xy​)ρ=(x−x0​)2+(y−y0​)2​
然后,根据以下公式对其进行变换:
r=ln2⋅radious5θ′=ψ+s⋅e−ρr+θr=ln2\cdot \frac {radious} 5 \\ \theta'=ψ+s\cdot e^{-\frac ρ r+\theta} r=ln2⋅5radious​θ′=ψ+s⋅e−rρ​+θ
其中 ψψψ 表示旋转角度,sss 表示像素值强度。接下来,我们利用 warp() 函数实现漩涡变换。

2.2 使用 scikit-image warp() 实现漩涡变换

(1) 首先,导入所需库,并定义 swirl() 函数,该函数根据上述数学公式实现像素漩涡变换:

from skimage.io import imread
from skimage.transform import warp
import matplotlib.pylab as plt
import numpy as npdef swirl(xy, x0, y0, R):r = np.sqrt((xy[:,1]-x0)**2 + (xy[:,0]-y0)**2)a = np.pi*r / Rxy[:, 1] = (xy[:, 1]-x0)*np.cos(a) + (xy[:, 0]-y0)*np.sin(a) + x0xy[:, 0] = -(xy[:, 1]-x0)*np.sin(a) + (xy[:, 0]-y0)*np.cos(a) + y0return xy

(2) 读取输入图像,然后将图像与 swirl() 函数输入参数调用 warp() 函数,以将非线性变换应用于输入图像:

im = imread('1.png')
print(im.shape)
im1 = warp(im, swirl, map_args={'x0':250, 'y0':350, 'R':600})
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(im1), plt.axis('off'), plt.title('Output image', size=10)
plt.show()

函数 swirl() 接受参数 xyx0y0r,并根据 warp() 函数的 map_args 参数进行设定。
执行以上代码,可以得到以下结果图像:


需要注意的是,x0y0R 参数传递给 swirl() 函数,通过修改这些参数值,可以观察到不同参数对输出图像的影响。

2.3 使用 scipy.ndimage 实现漩涡变换

在上一小节中,我们学习了如何使用 scikit-image warp() 实现漩涡变换;在本小节中,我们将继续学习如何使用 scipy.ndimagegeometric_transform() 函数实现非线性漩涡变换。

(1) 首先,导入所需库,并定义实现漩涡变换所需的函数 apply_swirl()

from scipy import ndimage as ndi
from skimage.io import imread
from skimage.color import rgb2gray
import matplotlib.pylab as plt, numpy as npdef apply_swirl(xy, x0, y0, R):                                                                        r = np.sqrt((xy[1]-x0)**2 + (xy[0]-y0)**2)a = np.pi*r / Rreturn ((xy[1]-x0)*np.cos(a) + (xy[0]-y0)*np.sin(a) + x0, -(xy[1]-x0)*np.sin(a) + (xy[0]-y0)*np.cos(a) + y0)

函数 apply_swirl() 接受参数 xyx0y0r,并根据 geometric_transform() 函数的 extra_arguments 参数进行设定。

(2) 接下来,读取输入图像,并将其转换为灰度图像,从 scipy.ndimage 模块中调用 geometric_transform() 函数,然后将 apply_swirl() 函数作为参数传递给 geometric_transform() 函数,用于执行漩涡变换。

im = rgb2gray(imread('1.png'))
print(im.shape)
im1 = ndi.geometric_transform(im, apply_swirl, extra_arguments=(300, 200, 620))

(3) 最后,绘制原始图像和变换后的图像:

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

3. 使用 scikit-image 实现弹性变形

3.1 弹性变形原理

对图像应用位移场( displacement fields )可以产生图像畸变,通过位移场可以计算每个像素原始位置的新目标位置。位置 (x,y)(x,y)(x,y) 处的新目标位置根据原位置得出,例如,如果 ΔX(x,y)=1ΔX(x,y)=1ΔX(x,y)=1、Δy(x,y)=0Δy(x,y)=0Δy(x,y)=0 这意味着每个像素的新位置都向右移动 1。我们可以通过以下步骤创建图像弹性变形:

  • 首先,生成随机位移场,即 Δy(x,y)=rand(−1,+1)Δy(x,y)= rand(-1,+1)Δy(x,y)=rand(−1,+1)、Δx(x,y)=rand(−1,+1)Δx(x,y)= rand(-1,+1)Δx(x,y)=rand(−1,+1),其中 rand(−1,+1)rand(-1,+1)rand(−1,+1) 用于生成一个在 -11 之间的随机数
  • 然后用标准偏差为 σσσ 的高斯函数(以像素为单位)与 ΔxΔxΔx、ΔyΔyΔy 执行卷积
  • 如果 σσσ 很大,因为随机值的平均值为 0,则将导致结果值非常小,如果我们将位移场进行归一化,则位移场将接近具有随机方向的常数;如果 σσσ 很小,则位移场在归一化后近似于完全随机的场。如果 σσσ 值大小合适,位移场则类似弹性变形,其中 σσσ 为弹性系数
  • 然后将位移场乘以控制变形强度的缩放因子 ααα

3.2 实现弹性变形

(1) 首先导入所需的库,然后自定义函数实现弹性变形函数 elastic_transform()

import numpy as np
import matplotlib.pylab as plt
from skimage.color import rgb2gray
from scipy.ndimage import gaussian_filter, map_coordinatesdef elastic_transform(image, alpha, sigma):random_state = np.random.RandomState(None)h, w = image.shapedx = gaussian_filter((random_state.rand(*image.shape) * 2 - 1), sigma, mode="constant", cval=0) * alphady = gaussian_filter((random_state.rand(*image.shape) * 2 - 1), sigma, mode="constant", cval=0) * alphax, y = np.meshgrid(np.arange(w), np.arange(h))indices = np.reshape(y+dy, (-1, 1)), np.reshape(x+dx, (-1, 1))distored_image = map_coordinates(image, indices, order=1, mode='reflect')return distored_image.reshape(image.shape)

函数 map_coordinates() 通过插值将输入阵列映射到新的坐标,坐标的数组用于为输出中的每个点找到输入中的相应坐标,这些坐标处的输入值由调用函数时所用的插值参数 order 确定。

(2) 使用 matplotlibimread() 函数读取输入图像,并使用 skimage.colorrgb2gray() 函数将其转换为灰度图像:

img = rgb2gray(plt.imread('2.png'))

(3) 调用 elastic_transform() 函数将弹性变形应用于图像:

img1 = elastic_transform(img, 100, 4)

(4) 绘制原始输入和应用弹性形变后的输出图像:

plt.figure(figsize=(20,10))
plt.subplot(121)
plt.imshow(img, cmap='gray')
plt.axis('off'), plt.title('Original', size=10)
plt.subplot(122)
plt.imshow(img1, cmap='gray')
plt.axis('off'), plt.title('Deformed', size=10)
plt.tight_layout()

小结

在本节中,我们学习了如何使用 scikit-image 库中的通用图像变换函数 warp(),该函数不仅可以实现常见的图像线性变换,而且能够实现包括漩涡变换、弹性变换等在内的非线性变换。在实际应用 warp() 函数之前,我们还学习了不同非线性变换的基本数学原理,以分辨其与线性变换之间的差别。

系列链接

Python图像处理【1】图像与视频处理基础
Python图像处理【2】探索Python图像处理库
Python图像处理【3】Python图像处理库应用
Python图像处理【4】图像线性变换
Python图像处理【6】通过哈希查找重复和类似的图像

Python图像处理【5】图像扭曲与逆扭曲详解相关推荐

  1. 4.3 Python图像处理之图像恢复-无约束滤波器(逆滤波)、有约束滤波器(维纳滤波器)

    4.3 Python图像处理之图像恢复-无约束滤波器(逆滤波).有约束滤波器(维纳滤波器) 文章目录 4.3 Python图像处理之图像恢复-无约束滤波器(逆滤波).有约束滤波器(维纳滤波器) 1 算 ...

  2. 9.2.1 Python图像处理之图像数学形态学-二值形态学应用之噪声消除

    9.2.1 Python图像处理之图像数学形态学-二值形态学应用之噪声消除 文章目录 9.2.1 Python图像处理之图像数学形态学-二值形态学应用之噪声消除 1 算法原理 2 代码 3 效果 1 ...

  3. 8.1 Python图像处理之图像典型分割-SUSAN边缘检测

    8.1 Python图像处理之图像典型分割-SUSAN边缘检测 文章目录 8.1 Python图像处理之图像典型分割-SUSAN边缘检测 1 算法原理 2 代码 3 效果 1 算法原理 SUSAN 的 ...

  4. 9.4 Python图像处理之图像数学形态学-基于灰度形态学的应用(形态梯度、形态平滑、高帽变换、低帽变换)

    9.4 Python图像处理之图像数学形态学-基于灰度形态学的应用(形态梯度.形态平滑.高帽变换.低帽变换) 文章目录 9.4 Python图像处理之图像数学形态学-基于灰度形态学的应用(形态梯度.形 ...

  5. 9.3 Python图像处理之图像数学形态学-灰度形态学

    9.3 Python图像处理之图像数学形态学-灰度形态学 文章目录 9.3 Python图像处理之图像数学形态学-灰度形态学 1 算法原理 2 代码 3 效果 1 算法原理 灰度图像与二值图像的区别在 ...

  6. 9.2.3 Python图像处理之图像数学形态学-二值形态学应用-区域填充

    9.2.3 Python图像处理之图像数学形态学-二值形态学应用-区域填充 文章目录 9.2.3 Python图像处理之图像数学形态学-二值形态学应用-区域填充 1 算法原理 2 代码 3 效果 1 ...

  7. 9.2.2 Python图像处理之图像数学形态学-二值形态学应用-目标检测

    9.2.2 Python图像处理之图像数学形态学-二值形态学应用-目标检测(击中与击不中) 文章目录 9.2.2 Python图像处理之图像数学形态学-二值形态学应用-目标检测(击中与击不中) 1 算 ...

  8. 9.1 Python图像处理之图像数学形态学-二值形态学(腐蚀、膨胀、开启、闭合)

    9.1 Python图像处理之图像数学形态学-二值形态学(腐蚀.膨胀.开启.闭合) 文章目录 9.1 Python图像处理之图像数学形态学-二值形态学(腐蚀.膨胀.开启.闭合) 1 算法原理 1.1 ...

  9. 8.3 Python图像处理之图像典型分割-分水岭分割

    8.3 Python图像处理之图像典型分割-分水岭分割 文章目录 8.3 Python图像处理之图像典型分割-分水岭分割 1 算法原理 2 代码 3 效果 1 算法原理 分水岭概念是以对图像进行三维可 ...

  10. 8.2 Python图像处理之图像典型分割-主动轮廓

    8.2 Python图像处理之图像典型分割-主动轮廓 文章目录 8.2 Python图像处理之图像典型分割-主动轮廓 1 算法原理 2 代码 3 效果 1 算法原理 主动轮廓模型,将图像分割问题转换为 ...

最新文章

  1. 423. 从英文中重建数字
  2. STM32之独立看门狗例程
  3. 有赞“小程序订阅消息”功能上线 支持商家主动推送「活动通知」
  4. 关于 ssh-keygen 的一点疑问
  5. 系统学习数字图像处理之图像分割
  6. WIN10 windows mobile设备中心连接不上
  7. win10查看计算机管理员,肿么查看win10微软账户是否为管理员账户
  8. 硬盘损坏如何恢oracle,硬盘损坏后恢复数据的几种方法
  9. A Comparative Analysis of Deep Learning Approaches for Network Intrusion Detection Systems (N-IDSs)
  10. 卡洛斯·斯利姆·埃卢
  11. 蚂蚁开放联盟链合约开发入门
  12. Win10 配置Java JDK 16 环境变量
  13. 微软外包人才之道:一流外包团队如何打造
  14. iphone ios 视频拍摄旋转
  15. Xmind 无法保存文件
  16. 登录用户互挤 实现的思路
  17. jxl可以操作excel2007吗?可以
  18. Linux盘符漂移问题
  19. 用python+selenium做个翻译助手
  20. 诺基亚301支持java评测_诺基亚301怎么样 诺基亚301测评【图解】

热门文章

  1. Either类java_基于Java8的Either类
  2. Python中的六种基本数据类型
  3. 传奇服务器攻城文件,仿盛大传奇沙巴克攻防战与比奇怪物攻城说明
  4. 什么是不确定性推理?不确定推理中需要解决的基本问题有哪些?
  5. Tableau柱状图
  6. java猜数字小游戏:任意输入数字,判断与系统随机产生数字是否相等。
  7. 皇图中原青豫大战打到服务器维护,【九州皇图】青、豫国砸再现激情
  8. vim-plug插件安装
  9. 国外变电站3d可视化技术发展_从裸眼3D技术看LED显示的发展趋势
  10. 2022年 HSC-1th中MISC的汝闻,人言否