基础

你们可能家里都会有一些老照片已经有黑点啊,划痕啊等。你有想过修复它们么?我们不能简单的在绘图工具里把他们擦除了就完了。因为这样只是把黑色的东西变成白色的而已,实际上没用。在这种情况下,会用到一种技术叫图像修复。基本的思想很简单:用周围的像素替换坏掉的像素,这样看上去就和周围一样了。比如下面这张:

很多算法被设计来干这个,OpenCV提供了两个,可以用同一个函数来访问: cv2.inpaint()

第一个算法是基于论文"An Image Inpainting Technique Based on the Fast Marching Method"。是基于快速匹配方法的。假设图像里的一个区域要修复。算法从这个区域的边界开始,逐渐地进入区域,把边界内的所有东西填充上。它取要修复的部分周围的一个像素周围的一小片邻居。这个像素被周围已知的像素的标准加权和替换掉。选择权重是很重要的。要修复的点周围像素的权重较高。和正常边界近的,还有在边界轮廓上的像素的权重较高。当像素被修复以后,它会通过快速匹配方法(FMM)移动到最近的像素。FMM保证那些已知像素周围的像素首先被修复,所以这个就像人工启发式的操作一样。这个算法使用标志cv2.INPAINT_TELEA开启。

第二个算法基于论文"Navier-Stokes, Fluid Dynamics, and Image and Video Inpainting".这个算法基于流体动力学和偏微分方程。基本原则是启发式。它首从已知区域先沿着边缘到未知区域访问(由于边缘应该是连续的)。在匹配边要修复区域边界的梯度向量时持续画等值线(把相同亮度的点用线连起来,类似于轮廓线)。这时候用到流体动力学。之后会填充颜色以减小最小方差。这个算法用标志cv2.INPAINT_NS启用。

编码

我们需要创建和输入图像相同大小的掩图,需要修复的区域对应的像素要非0.剩下的就简单了。我的图像被一些黑色划痕给破坏了(实际上是我自己加的)。我用绘图工具对应的标记出来。import numpy as np

import cv2
img = cv2.imread('messi_2.jpg')
mask = cv2.imread('mask2.png',0)
dst = cv2.inpaint(img,mask,3,cv2.INPAINT_TELEA)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

看下面的结果。第一个图片是输入图像,第二个是掩图,第三个是用第一种算法的结果,最后一张是第二种算法的结果。

END