利用OpenCV实现图像修复

图像修复技术的应用

想想一下,我们有一张非常棒的相片,但是由于时间比较久远,没有电子版留底,而纸质版的又十分不便于保存。因此长采用扫描的方式获得电子版。但是非常不幸,扫描过程中落入了一根头发,或者是机器出现故 障,对相片造成了影响,这个时候就可以通过图像修复技术解决这个问题。

完整代码地址:https://github.com/YouthJourney/Computer-Vision-OpenCV/tree/master/image_restoration

OpenCV中图片修复技术

1、Inpaint_ns:基于Navier-Stokes的图像修复

该方法在2001年提出,其神奇之处竟然是基于流体力学理论提出的方法。根据其作者提出,我们需要解决的问题可以抽象成在一个鞋子图片上有一个黑色的区域,通过填充黑色区域,使得最佳的恢复鞋子的样子。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8fIELaxF-1603022025785)(en-resource://database/955:1)]

对于如何填补这个黑色区域,可以抽象成存在一条曲线,使得由A到B将黑色区域分开,并且保证在曲线的一 侧是蓝色,另一侧是白色。这个曲线应具有如下的约束:
1. 保持边缘特征
2. 在平滑区域中保持颜色信息

通过构建一个偏微分方程来更新具有上诉约束的区域内的图像强度,同时利用拉普拉斯算子估计图像平滑度信息,并沿着等照度传播。

由于这些方程与Navier-Stokes方程(流体力学中的方程,感兴趣的小伙伴可以自行百度)相关且类似,因此可以通过流体力学中的方法进行求解。

本人对流体力学了解的不是很仔细,有需要了解的小伙伴可以阅读该论文:
http://www.math.ucla.edu/~bertozzi/papers/cvpr01.pdf

2、Inpaint_Telea:基于快速行进方法的图像修复。

该方法中没有使用拉普拉斯算子作为平滑度的估计,而是使用像素的已知图像邻域上的加权平均值来描述。同时利用邻域像素和梯度恢复填充区域像素的颜色。当像素被修复后,通过快速行进方法更新边界。关于细节部分,可参考论文:https://pdfs.semanticscholar.org/622d/5f432e515da69f8f220fb92b17c8426d0427.pdf

下面以亚历山大·加德纳拍摄的林肯总统有裂痕的图片为例做图像修复:
在这里插入图片描述从左至右依次是输入图像、掩膜、INPAINT_TELEA的结果、INPAINT_NS的结果。

代码如下:

# -*- coding: UTF-8 -*-    
# Author: LGD
# FileName: pic_restoration
# DateTime: 2020/10/18 17:11
# SoftWare: PyCharm
import numpy as np
import cv2 as cv

# OpenCV Utility Class for Mouse Handling
from pip._vendor.certifi.__main__ import args


class Sketcher:
    def __init__(self, windowname, dests, colors_func):
        self.prev_pt = None
        self.windowname = windowname
        self.dests = dests
        self.colors_func = colors_func
        self.dirty = False
        self.show()
        cv.setMouseCallback(self.windowname, self.on_mouse)

    def show(self):
        cv.imshow(self.windowname, self.dests[0])
        cv.imshow(self.windowname + ": mask", self.dests[1])

    # onMouse function for Mouse Handling
    # 使用鼠标把掩膜画出来也就是第二幅图的白色线条
    def on_mouse(self, event, x, y, flags, param):
        pt = (x, y)
        if event == cv.EVENT_LBUTTONDOWN:
            self.prev_pt = pt
        elif event == cv.EVENT_LBUTTONUP:
            self.prev_pt = None

        if self.prev_pt and flags & cv.EVENT_FLAG_LBUTTON:
            for dst, color in zip(self.dests, self.colors_func()):
                cv.line(dst, self.prev_pt, pt, color, 5)
            self.dirty = True
            self.prev_pt = pt
            self.show()


def main():
    print("Usage: python inpaint <image_path>")
    print("Keys: ")
    print("t - inpaint using FMM")
    print("n - inpaint using NS technique")
    print("r - reset the inpainting mask")
    print("ESC - exit")

    # Read image in color mode
    # 读取输入图片
    img = cv.imread("Lincoln.jpg", cv.IMREAD_COLOR)

    # If image is not read properly, return error
    if img is None:
        print('Failed to load image file: {}'.format(args["image"]))
        return

    # Create a copy of original image
    img_mask = img.copy()
    # Create a black copy of original image
    # Acts as a mask
    inpaintMask = np.zeros(img.shape[:2], np.uint8)
    # print(inpaintMask)
    # Create sketch using OpenCV Utility Class: Sketcher
    sketch = Sketcher('image', [img_mask, inpaintMask], lambda: ((255, 255, 255), 255))

    while True:
        ch = cv.waitKey()
        if ch == 27:
            break
        if ch == ord('t'):
            # Use Algorithm proposed by Alexendra Telea: Fast Marching Method (2004)
            res = cv.inpaint(src=img_mask, inpaintMask=inpaintMask, inpaintRadius=3, flags=cv.INPAINT_TELEA)
            cv.imshow('Inpaint Output using FMM', res)
        if ch == ord('n'):
            # Use Algorithm proposed by Bertalmio, Marcelo, Andrea L. Bertozzi, and Guillermo Sapiro:
            # Navier-Stokes, Fluid Dynamics, and Image and Video Inpainting (2001)
            res = cv.inpaint(src=img_mask, inpaintMask=inpaintMask, inpaintRadius=3, flags=cv.INPAINT_NS)
            cv.imshow('Inpaint Output using NS Technique', res)
        if ch == ord('r'):
            img_mask[:] = img
            inpaintMask[:] = 0
            sketch.show()

    print('Completed')


if __name__ == '__main__':
    main()
    cv.destroyAllWindows()
  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hong_Youth

您的鼓励将是我创作的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值