一、效果展示

1.使用opencv进行图像修复,对一张简单缺损的图片进行修复的效果如下图所示:

修复前 修复后
修复前 修复后

2.对一个被模糊的网格线污染了的图片进行修复的效果如下图所示:

修复前 修复后
在这里插入图片描述 在这里插入图片描述

原始图片和完整代码在github项目中:
https://github.com/zhmc/inpaint_demo

二、使用的opencv函数inpaint基本介绍

C++中cv::inpaint函数声明如下:

void inpaint( const Mat& src, const Mat& inpaintMask,  
                         Mat& dst, double inpaintRange, int flags );
                         
第一个参数src是要修复的图像,Mat类型的,为8位单通道或者三通道图像的输入图像;
第二个参数inpaintMask为修复掩膜,为8位单通道图像,其中非零像素表示要修补的区域;
第三个参数dst为修复后的结果,它和src图像类型是一样的;
第四个参数inpaintRange是修复参考圆半径,double类型的,修复算法会使用需要修复点邻近的圆形区域,参照这个圆形区域内的像素点进行插值修复;
最后一个参数flags是修复算法类别,int型的,为修补方法的标识符,两种修补方法分别 cv::INPAINT_NS 或cv::INPAINT_TELEA

python中

dst	= cv2.inpaint(src, inpaintMask, inpaintRadius, flags[, dst]	)

参数含义和C++中一致;
修复后的图像作为返回值;
flags为cv2.INPAINT_NS或cv2.INPAINT_TELEA

三、简单缺损图片的修复过程

这是一张被白色印记毁损的图片,用于演示图像修复的最简单流程。
修复前首先,需要对图像进行灰度处理。

src_image = cv2.imread("data/1.jpg")
gray_image = cv2.cvtColor(src_image, cv2.COLOR_RGB2GRAY)

然后,进行二值化。

# 二值化
ret, binary = cv2.threshold(gray_image, 245, 255, cv2.THRESH_BINARY)

得到二值化图像如下图:
二值化图片观察图片发现,存在较多噪点,并不是需要提取的待修复区域。
使用形态学开操作,去除噪点。

# 进行开操作,去除噪音小点。
kernel_3X3 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
binary_after_open = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel_3X3)

得到过滤后的图片。
过滤后的图片这张图片就可以作为图像修复的掩膜。使用修复函数。

restored = cv2.inpaint(src_image, binary_after_open, 9, cv2.INPAINT_NS)

修复的图片这样就完成了一个缺损图片的修复。

四、复杂缺损图片的修复过程

但是上面完成修复的图片是一个很简单的场景,如果是真实世界一些复杂的缺损图片的修复就比较麻烦了。
如下图,这是一个被网格线毁损的图片,它是由于在相册里被某个网格图案粘合太长时间附上去的。
原图
1.转换灰度图

src_image = cv2.imread("data/2.jpg")
gray_image = cv2.cvtColor(src_image, cv2.COLOR_RGB2GRAY)

2.观察灰度图,发现网格线位于图像中的谷线。 使用Sobel滤波器,对X轴方向和Y轴方向做梯度提取。

# 对X轴方向和Y轴方向做Sobel梯度提取
sX = cv2.Sobel(gray_image, cv2.CV_64F, 1, 0, ksize=3, borderType=cv2.BORDER_REPLICATE)
sY = cv2.Sobel(gray_image, cv2.CV_64F, 0, 1, ksize=3, borderType=cv2.BORDER_REPLICATE)

# 去除负值。这是为了提取单边界,否则网格线两边的梯度绝对值都较大,形成双边缘。
sX[sX < 0] = 0
sY[sY < 0] = 0

3.对sobel梯度值进行exp(0.2), 0.2会稍微减弱峰值。然后进行竖直方向的积分投影。

eX = (sX ** .2).sum(axis=0)
eY = (sY ** .2).sum(axis=1)

Sobel梯度提取图和积分投影图:
Sobel梯度提取图和积分投影图4. 构建掩膜。观察图片,发现390是一个划分eX的阈值,480是一个划分eY的阈值

A2 = src_image.copy()
mask = np.zeros(A2.shape[:2], dtype=np.uint8)
mask[eY > 480, :] = 1
mask[:, eX > 390] = 1
A2[mask.astype(bool), :] = 255

将掩模图绘在原图上,查看效果
在这里插入图片描述5. 使用修复算法

restored = cv2.inpaint(src_image, mask, 1, cv2.INPAINT_NS)

最终修复效果如图所示:
修复后

原始图片和完整代码在github项目中:
https://github.com/zhmc/inpaint_demo

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐