扫描线填充算法代码_21. 修补图像的利器:基于纹理填充技术的Inpainting

8983d0efccc401a95dc52624c9806d2b.png

本文同步发表在我的微信公众号“计算摄影学”,欢迎扫码关注

a24f0e60b58cd6a78ba1f2766a36fae6.png

【转载请注明来源和作者】

我相信你和我一样都会遇到一种情况,就是在旅游景区想拍个照留影,结果拍下了太多的路人甲路人乙,于是就总想找到一个p图软件,能够把这些不相干的背景人物p掉

但是直接p是不行的,只有填充被抹掉的像素,才能做到天衣无缝。

我们想要的实际上是这样的效果:

c2ab8e2366b71ac443a29c491677e720.gif

看过我之前的文章:19. 纹理合成再谈 - 一种非参数的方法的朋友一定会想,既然我们能合成纹理,甚至能像下图一样恢复纹理图像中的空洞区域,那是否能用同样的思想来达到我们抹去杂乱背景的目的呢?

1d163f41c7ab8d8a5218ff622e301754.gif

今天我就来给你介绍这样的技术,今天所参考的两份文献是:

1. A. Criminisi, P. Perez, K. Toyama. Region filling and object removal by exemplar-based inpainting. In 2004 IEEE Transactions on Image Processing 9 1200-1212.
2. Criminisi et al., “Object removal by exemplar-based inpainting,” CVPR 2003.

两份文献介绍的是同一种技术,即通过类似我们之前讲过的19. 纹理合成再谈 - 一种非参数的方法中的方法来恢复图像中的空洞区域,只不过作者将上述方法做了进一步扩展,使得它可以用于更广泛的自然图像,而不仅仅是纹理图像。

一、效果展示

我相信看到这里你已经很好奇这个算法的质量到底如何了,我们来看看论文中所展示的一些效果

去除大块的前景像素:

2ef5df624acd069f7d22dff38e1a3375.png

22f8790c148315a838f07a3e2715ea03.png

去除杂乱的信息

b8610d4febbd5d949e205fdb2d474533.png

db3f5bd87792cdbd92a6bce8e4f7ee05.png

填充缺失像素

这个技术甚至可以用于填充全景拼接时,由于图像的warp带来的空洞区域,你可以看到下面a图白色区域都是warp带来的空洞,而b图中则用此算法很好的进行了填充。

9c780a735d2b41e3c8712303a5192bd3.png

看起来真是一种神奇的算法,不是吗?现在让我们看看它到底是如何做到的

二、算法原理

看过我文章19. 纹理合成再谈 - 一种非参数的方法一定还记得起,Efros教授的纹理合成有两个关键点:

  1. 从待填充的像素中,用洋葱皮的顺序搜寻当前需要填充的像素,确保待填充的像素能够最大可能利用已知或已填充的像素信息。

05fc8dfcddf2fdf29c2524c83959f212.png

2. 对于待填充的像素,从已知图像像素中采样,获取源信息:

6a4daa879651ea3bcdf5ce8c0fd9ef7d.png

这里提到的方法首先被Efros教授运用到了纹理合成上,而今天这个算法的作者则向我们说明了这个方法不仅仅对填充纹理有效,对填充普通图像中的线性结构也是有效的。例如,在下面的图示中,

是指已知区域,
是指待填充的区域,
是已知区域和待填充区域的边界。首先作者认为我们要像洋葱皮顺序一样,填充的是已知区域的边界上的像素,也就是
上的像素,那么假设我们正在填充p点, p点的邻域是
,那么很显然,与
最相似的像素位于
。那么当我们用Efros的方法拷贝源像素或到点时,其实就把相应的边缘信息也拷贝到了目标区域,也因此d图上可以很明显看到源区域中黄色和蓝色形成的边缘信息扩展到了待填充区域。由此说明我们已经学过的填充纹理的方法是可以很好的保持图像中的线性边缘信息的。

6250455b48c18d6f21d27ab875ef4b44.png

理解了上面这点后,我们再来看看填充顺序的重要性。相比起Efros所提到的洋葱皮顺序,作者提到了一种梯度敏感的顺序,并认为对梯度敏感的填充顺序才能更好的填充目标区域,得到更好的效果,如下图所示:

1a3691d1bbd0d9f9db4f87ab242be529.png

下面这张图也很典型的说明了洋葱皮顺序会导致缺陷,而保持梯度的填充顺序能很好的回复图像中的空洞:

7e28da6bc73d1602a934646fc02dfec9.png

那什么是保持梯度的填充顺序呢?

来看看这幅图,首先作者认为应该优先填充已知区域和待填充区域的边界上的像素,即下图中红色线

上的像素, 对每个这样的像素,我们要计算其“优先级”,根据优先级来确定先填充哪一个。

eece67cfc8c1696c4ee92cd791df0cf4.png

优先级的计算公式如下:

cb1fb9583f49b0647316e53eeea6c383.png

其中C(p)是p点的置信项,D(p)是p点的数据项,它们的定义如下:

cc9066ac37057e0b07df7cf083b7530e.png

先说C(p)的计算:

  1. 分母|
    |代表邻域窗口的大小,例如9x9的窗口大小就是81.
  2. 分子是指把
    中的已填充的像素的置信度累加起来

因此C(p)其实是通过p的邻域的已填充像素的置信度推导出了p点的置信度。当初始化时,所有已知像素的置信度为1,待填充像素的置信度为0,你可以看到当我们逐渐填充像素时,越是靠近待填充像素内部的点,其置信度越低——这是非常符合我们的直觉的。

再来看看D(p),这里面α是一个归一化参数,对一般的灰度图像,α=255. np是指在p点的法向量,而▽

则是指p点的梯度。在实际的实现过程中,▽
实际上是取中所有像素梯度的幅度最大者,而
则是通过p点在边界线上的两边的像素所连成的直线的正交单位向量,如果你使用OpenCV的话,findContour函数可以帮到你。

这里面我还想借用作者的示意图来给大家说下置信项和数据项对填充顺序的影响。下图中,红色轮廓内部是待填充的像素,其他是已知像素。当我们只采用置信度来判断优先级时,可以看到算法会优先填充绿色像素,并且红色像素的优先级最低。于是待填充区域会越来越趋于圆形,突出的尖端会被压制。 而如果只采用数据项,则算法倾向于把已知像素中的结构信息,例如图中的边缘信息,扩散到未知区域中。于是它会逐步填充绿色像素。

如果同时考虑置信项C(p)和数据项D(p),我们就能得到很好的平衡,得到一种很自然的保持结构的填充顺序。

9df0e35d0dcb26d89a283c29dd702700.png

一旦我们计算出所有像素的优先级,那么就选出优先级最高的像素

进行填充。填充的关键是寻找源像素块,可以表达为公式(2)。其中
是我们选出的优先级最高的像素,是指已知区域,所以就是指在已知区域里面寻找d最小的像素块
,然后把其中的信息拷贝到里面的待填充像素上。

15c22b41af237b260f4df49918e59223.png

于此同时,我们还需要填充这些点的置信度,作者的方法很直接,就是用直接拷贝

的置信度到其邻域待填充像素上。

所以,作者的方法可以用如下的伪代码来总结:

67c76c0d5ec16a720a0d502817b864c0.png

三、总结

介绍的算法Region filling and object removal by exemplar-based inpainting是在我们介绍过的19. 纹理合成再谈 - 一种非参数的方法基础上的进一步改进,使之可以应用到自然图像上,能够填充被遮挡的直线型结构。其主要的改进点是同时使用置信度和数据项来衡量填充的优先级顺序,然后在已知像素中搜索与待匹配块相符合的区块来进行块填充,并让置信度从空洞的外层逐渐向内漫延降低。

Inpainting的技术出现已经很久,现在有了很多优秀的方法。但在本篇论文发表当时,也是非常重量级的算法,效果很好。

希望这篇文章能够给你带来启发,别忘了给我点赞哦^_^

番外:

Nvidia推出了在线Inpainting应用,第一幅动图就来自于该应用的页面,你也可以自己试试,这应该是一个基于深度学习的算法,对某些图像效果也挺不错的:

https://www.nvidia.com/research/inpainting/

四、参考资料

本文的大部分信息来自于作者上面提到的两篇论文:

1. A. Criminisi, P. Perez, K. Toyama. Region filling and object removal by exemplar-based inpainting. In 2004 IEEE Transactions on Image Processing 9 1200-1212.
2. Criminisi et al., “Object removal by exemplar-based inpainting,” CVPR 2003.

本文还有少量信息来自于:

CMU 2017 Fall Computational Photography Course 15-463, Lecture 9

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值