目标
在本章中
- 我们将学习如何通过一种名为 "内绘 "的方法去除老照片中的细小噪点和笔触等。
- 我们将了解 OpenCV 中的内绘制功能。
基础知识
大多数人家里都会有一些老照片,上面有一些黑点、笔画等。您是否想过将其复原?我们不能简单地用油漆工具擦除它们,因为这样做只会用白色结构代替黑色结构,毫无用处。在这种情况下,需要使用一种叫做 "图像内绘 "的技术。基本原理很简单: 用相邻的像素替换那些坏的标记,使其看起来与相邻的像素一样。请看下图(摘自维基百科):
为此设计了几种算法,OpenCV 提供了其中两种。这两种算法可以通过相同的函数 cv.inpaint() 访问。
第一种算法基于 Alexandru Telea 在 2004 年发表的论文 "An Image Inpainting Technique Based on the Fast Marching Method " 。该算法基于快速行进法。在图像中考虑一个要涂抹的区域。算法从这一区域的边界开始,先逐渐填充边界内的所有内容。它在要涂抹的像素周围选取一个小的邻域。该像素由邻域中所有已知像素的归一化加权和代替。权重的选择非常重要。那些靠近点的像素、靠近边界法线的像素和位于边界轮廓线上的像素会得到更多权重。一旦一个像素被内绘,它就会使用快速行进法移动到下一个最近的像素。快速行进法确保先涂抹已知像素附近的像素,因此它就像手动启发式操作一样。使用 cv.INPAINT_TELEA 标志可以启用该算法。
第二种算法基于 Bertalmio、Marcelo、Andrea L. Bertozzi 和 Guillermo Sapiro 于 2001 年发表的论文 "Navier-Stokes, Fluid Dynamics, and Image and Video Inpainting " 。该算法以流体力学为基础,利用偏微分方程。其基本原理是 “heurisitic”。它首先沿着从已知区域到未知区域的边缘行进(因为边缘是连续的)。在匹配内绘区域边界的梯度矢量时,它会继续等距线(连接相同强度点的线,就像等高线连接相同海拔高度的点)。为此,我们使用了流体力学中的一些方法。一旦获得了梯度矢量,就会填充颜色以减少该区域的最小方差。使用 cv.INPAINT_NS 标志可启用该算法。
代码
我们需要创建一个与输入图像大小相同的遮罩,其中非零像素对应于要进行涂色的区域。其他一切都很简单。我的图像被一些黑色笔画(手动添加)降级。我使用画图工具创建了相应的笔画。
import numpy as np
import cv2 as cv
img = cv.imread('messi_2.jpg')
mask = cv.imread('mask2.png',0)
dst = cv.inpaint(img,mask,3,cv.INPAINT_TELEA)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()
请看下面的结果。第一张图片显示的是降级输入。第二张图片是掩码。第三张图片是第一种算法的结果,最后一张图片是第二种算法的结果。
其他资源
- Bertalmio, Marcelo, Andrea L. Bertozzi, and Guillermo Sapiro. “纳维-斯托克斯、流体动力学以及图像和视频内画”。计算机视觉与模式识别》,2001 年。CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on, vol. 1, pp. IEEE, 2001.
- Telea, Alexandru. “基于快速行进法的图像内绘技术” 图形工具期刊 9.1 (2004): 23-34.
练习
- OpenCV 自带一个关于内绘的交互式示例,samples/python/inpaint.py,试试吧。
- 几个月前,我观看了一段关于内容感知填充(Content-Aware Fill)的视频,这是 Adobe Photoshop 中使用的一种高级内画技术。经过进一步搜索,我发现 GIMP 中也有同样的技术,只是名称不同,叫做 “Resynthesizer”(需要单独安装插件)。我相信你会喜欢这项技术的。