【完整项目】基于Python+Tkinter+FFD(free-form deformations)的2D彩色图像实时网格自由变形软件的设计与实现


一、效果展示

校正比萨斜塔:

请添加图片描述

人脸变形:

请添加图片描述

图像拼接结果中,重叠区域的对齐warp细节修正:

请添加图片描述


二、前言介绍

这是一个基于Python+Tkinter+FFD(free-form deformations)的2D彩色图像实时网格自由变形软件,它可以将任意彩色RGB图像划分为若干网格,用户可以使用鼠标点击网格顶点,按住并拖拽移动,释放鼠标后,图像会根据网格的变形而实时变形。

网格的自由变形技术(FFD,mesh warp/grid warp)在图像配准领域广泛使用,包括图像的旋转校正、图像人脸变形(image morphing)等。而在图像拼接领域,网格变形也几乎涵盖了所有的传统方法,在图像翘曲步骤使用。所以,了解网格变形技术对于图像拼接技术的学习也是大有裨益。

做这个软件或者写这篇文章的动机:

  1. 目前没有公开类似的软件,也没有好的文章来讲网格变形。
  2. 有图像变形的需求。
  3. 看到文章Deep Rotation Correction Without Angle Prior里nie等人开发了这样的软件制作数据集(文章第四部分),手痒就做一个类似的,也算复现文章的一部分。
    在这里插入图片描述
    为了进一步提高数据集的质量,我们开发了一个基于网格的程序,对旋转结果进行手动微调。基于网格的程序来手动微调旋转结果。He等人的旋转方法[7]。它允许用户用鼠标拖动拖动网格顶点,以交互方式修改网格变形。

文章链接:【图像拼接】论文精读:Deep Rotation Correction without Angle Prior(DRC)

  1. 学习网格变形原理,对加深图像拼接中网格变形的原理有帮助。(虽然FFD和图像拼接中的图像warp不太一样)
  2. 网格变形简单,但是让图像跟随网格的变化而变化比较难。(怎么实现网格到图像的映射呢?我看这也是大多数人比较发愁的地方)
  3. 学习软件开发,练练tkinter

软件的基础功能:

  1. 2D图像实时网格变形,包括灰度图、彩色RGB图像
  2. 保存变形后的图像

软件的特色功能:

  1. 颜色复原:一般FFD都是变形灰度图,只有形状变化,没有颜色和亮度变化;而本软件可以在颜色和亮度变化后,通过算法将颜色和亮度恢复到和原输入图像一致。(前面效果展示中只有变形步骤,没有颜色恢复步骤,颜色复原的效果见第四部分【快速开始】中的第6步)。
  2. 支持任意大小的网格,并保证实时处理速度。网格越密,图像微调的越精细。
  3. 可以应用到各种需要图像变形的场景,比如上面展示的图像内容校正、捏脸、全景图/鱼眼图的扭曲消除、各种细节微调、甚至可以通过拉伸将全景图矩形化。
  4. 使用极简风格编写,只用了numpy,pillow,torch三个库,没有用opencv等打包后文件比较大的库。

三、软件使用说明

3.1 环境配置

下载源码后,用pycharm打开该项目,setting中设置好所需的python环境。建议新建一个虚拟环境进行配置。

安装依赖:torch可能比较慢,建议使用清华镜像

pip install -r requirements.txt 或
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/

requirments.txt中的库以及库版本:
在这里插入图片描述
numpy用于存储网格结构和图像输入,PIL用于将图像显示在tkinter上,torch用于将网格变化映射到图像时计算损失,即将图像以张量的形式输入及操作。

3.2 文件结构

项目文件结构如下:
在这里插入图片描述

  • main.py:主函数运行tkinter的GUI窗口
  • mesh_warp.py:网格变形相关算法,包括B样条、插值算法等
  • tk_utils.py:tkinter的相关操作,包括组件逻辑等

3.3 准备工作

在本地任意位置准备好待处理的图像,支持jpg和png格式。

四、快速开始

  1. 运行main.py打开软件界面:
    请添加图片描述
  2. 输入网格大小,然后点击【确定网格大小】。以15*15为例:
    在这里插入图片描述
  3. 点击菜单栏【文件】,然后选择自己要处理的图像(或快捷键A)
    在这里插入图片描述
  4. 选择好的图像如下所示,如果窗口大小显示不全可以拖拽改变窗口大小:
    在这里插入图片描述
  5. 鼠标点击网格顶点,拖拽移动,释放鼠标,图像产生对应的形变,颜色和亮度会发生变化
    在这里插入图片描述
  6. 形变完成后,点击【恢复图像颜色】,会弹出提示框,等待较长时间后,会弹窗提示颜色恢复完毕。(注:颜色恢复的时长与你的形变量和图像质量有关,如果形变较多,图像质量较高,请耐心等待
    在这里插入图片描述
    在这里插入图片描述
  7. 图像恢复原色后,可以点击【文件】,然后【保存图像】;或按快捷键S,可以将图像保存到本地的任意位置。
    在这里插入图片描述
  8. 菜单栏的【帮助】中有详细的【使用说明】
    在这里插入图片描述
  9. 菜单栏的【帮助】中的【关于】有软件的相关说明
    在这里插入图片描述

五、主要思路

整体过程描述:将图像放入网格阵中,通过控制网格的变形来定义一个空间变换函数,使各点映射到变形后的空间中,与图像的插值算法结合,从而实现图像变形。

算法思路

空间变换函数使用三次B样条,具体原理见下面文献:

D. Rueckert, L. I. Sonoda, C. Hayes, D. L. G. Hill, M. O. Leach, and D. J. Hawkes, “Nonrigid
registration using free-form deformations: application to breast mr images,” IEEE Transactions
on Medical Imaging, vol. 18, no. 8, pp. 712–721, 1999.

三次B样条的基函数:
在这里插入图片描述
重点:将网格变形映射到图像上

一般的方法是利用网格的变换结果对图像中的像素点进行插值运算,场景的有双线性插值等,就是图像resize用的那个插值算法。但是,图像resize并不涉及图像的warp。换句话说,图像resize的变换是线性的,而图像warp的变化是非线性的。那么,如果我想让图像变形后的插值尽量与原变化一致,就需要对每个像素点计算变形的贡献,即添加权重。没有形变的像素位置的权重为0,有形变的像素通过核函数施加权重,最后得到图像每个像素的加权和。

然而,当图像很大,质量很高时,上述方法的计算复杂度将是非常高的,计算缓慢,无法实现我们想达到的实时效果。

于是,我们受到深度学习中损失函数的启发,将目标图求逆得到反向图,将反向图与原图之间的差别视为loss,然后最小化这个loss,最后再变换回来,则得到损失最小的形变图像。(是不是很像图像拼接中网格变形的那些能量函数,定义很多个能量项,然后最小二乘找最优解就是最优的warp。这里我们也是这种思想,只不过我们的损失是简单的二次平方差。

为了计算上述损失,那么图像的输入numpy流转为tensor流,求解后转为PIL流,用于显示到界面中。

上述原理对应mesh_warp.py中的函数,大家可以根据代码理解上述原理。

numpy流:输入图像,输入网格
tensor流:网格和图像转为tensor输入
pillow流:tkinter的GUI界面显示

先迭代2次,实现实时形变,最后迭代40次,用于恢复图像原色。

注:不是只有训练模型才会用到torch,也会有只用到计算loss,只用反向传播的情况。

网格变形和实时操作思路

用tkinter的canvas显示网格和图像,网格由顶点和线组成。层级关系由上到下依次为:顶点、线、图像。

初始化网格后,要能得到网格顶点的相关信息,包括网格顶点坐标,网格顶点的序号;与网格顶点相交的线的信息,线的id等。用户用鼠标点击网格顶点后,要能知道用户点击的是哪个网格顶点,从而知道与其相交的线,进而移动它们。

初始化网格时,每个顶点对应右、下两条相邻的网格边。除了最后一列和最后一行,每个网格顶点及其右、下临边作为一个整体按先列后行初始化;最后一列是从上到下初始化,最后一行是从左到右初始化。

只移动与顶点相交的线:
在这里插入图片描述
上述思路见tk_utils.py,代码注释详细。

六、总结与反思

  1. 恢复原图颜色和亮度实际上还是有一些不同的,但是已经足够接近了。起码可以变形彩色的RGB图像了,能满足一部分需求。
  2. 实现过程中,一定要设计好变量流,比如网格mesh是如何变换的,怎么存储顶点和线的坐标,怎么得到它们的索引;图像从输入开始是如何变化的。本例中图像就有numpy,PIL,tensor三种形式。
  3. 可以用cuda加速颜色复原过程,感兴趣的朋友可以试试。

七、代码链接

项目源码链接:基于Python+Tkinter+FFD(free-form deformations)的2D彩色图像实时网格自由变形软件

八、其他完整项目

【完整项目】基于Python+Tkinter+OpenCV+Yolo+手写OCR的双模式答题卡识别软件的设计与实现

最近更新

  1. TCP协议是安全的吗?

    2023-12-26 10:02:01       17 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-26 10:02:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-26 10:02:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-26 10:02:01       18 阅读

热门阅读

  1. Docker资源

    2023-12-26 10:02:01       30 阅读
  2. 制作spring boot docker镜像Dockerfile文件编写

    2023-12-26 10:02:01       34 阅读
  3. StarRocks-3.1.6升级

    2023-12-26 10:02:01       26 阅读
  4. PAT.1101.QuickSort

    2023-12-26 10:02:01       30 阅读
  5. 每日一水:leetcode1576.替换所有的问号

    2023-12-26 10:02:01       38 阅读
  6. Nestjs使用log4j打印日志

    2023-12-26 10:02:01       38 阅读
  7. 附录E SQL入门之SQL保留字

    2023-12-26 10:02:01       40 阅读
  8. Python 查杀进程的方法封装

    2023-12-26 10:02:01       45 阅读
  9. C#的故事

    2023-12-26 10:02:01       27 阅读