Image repair in Python, OpenCV — cv2.inpaint

Image Inpainting Image modification

This blog post will explain how to remove small noises, strokes, etc. from old photos using cv2.inpaint(), an image repair technique in OpenCV. And provides an interactive program, using OpenCV’s fast moving and fluid mechanics repair algorithm to repair their own pictures.

Most people have some old aging photos at home with black dots, strokes, etc. How to recover?


Erase in the Drawing Tool: Will simply replace the black structure with a useless white structure, which is not ideal. Image repair techniques in OpenCV – The basic idea is simple: replace these bad markers with adjacent pixels to make them look like neighbors.

  • Cv2. INPAINT_TELEA (Fast Marching Method)

  • Cv2.INPAINT_NS (Fluid Dynamics Method)

  • What OpenCV doesn’t implement: Content-Aware Fill, an advanced repair technique used in Adobe Photoshop.

Cv2.inpaint () Benefits: More natural repair effect; Disadvantages: the original image and mask map need to be provided when repairing (only the polluted pixel area has values consistent with the original image);

1. The rendering

The official original graph VS mask graph VS fast moving algorithm repair effect VS fluid mechanics repair effect is as follows: Next, implement your own image fixes with interactive examples;

Original graph VS Mask graph VS fast moving algorithm repair effect diagram is as follows:The original image can be moved randomly with the left mouse button to draw points and lines, and the right mouse button to move and draw rectangles to randomly add some polluted areas; According to the original image, a mask image is generated. The mask image has the same size as the original image, and only the polluted area is white pixels. You can see that the repair effect is still very good ~Original graph VS Mask graph VS fluid mechanics algorithm repair effect diagram is as follows:The original image can be moved randomly with the left mouse button to draw points and lines, and the right mouse button to move and draw rectangles to randomly add some polluted areas; A mask map is a map of the same size as the original, and only the contaminated areas are white pixels. You can see that the repair effect is still very good ~ There is not much difference between the fast moving algorithm and the fluid mechanics algorithm.

Principle 2.

  • Cv2.inpaint_telea (Fast Marching Method), which assigns more weight to pixels located near points, near boundary normals, and on the boundary contour. Once a pixel has been repaired, it moves to the next nearest pixel using the fast marching method.

  • Cv2.INPAINT_NS (Fluid Dynamics Method Fluid Mechanics algorithm) uses some methods of Fluid mechanics, and the basic principle is heuristic. First move from the known region to the unknown region along the edge (because the edge is continuous). It continues the contour lines (lines that connect points of the same strength, just as contour lines connect points of the same elevation) while matching the gradient vectors at the boundaries of the repaired area.

  • What OpenCV doesn’t implement: Content-Aware Fill, an advanced repair technique used in Adobe Photoshop.

3. The source code

# Interactive case of image repair -- repair damaged image area by water flow filling algorithm;
# Use two fixes
# cv2.inpaint_telea (Fast Marching Method), which assigns more weight to pixels located near points, near boundary normals, and on the boundary contour. Once a pixel has been repaired, it moves to the next nearest pixel using the fast marching method.
# cv2.INPAINT_NS Fluid mechanics algorithm, using some methods of fluid mechanics, the basic principle is heuristic, first move from known region to unknown region along edge (because edge is continuous). It continues the contour lines (lines that connect points of the same strength, just as contour lines connect points of the same elevation) while matching the gradient vectors at the boundaries of the repaired area.

# USAGE 
# python inpaint.py D:/deepLearning/py-demo/20210808/images/ml.jpg

# Hold down the left mouse button to add dots and lines, and hold down the right mouse button to add rectangular boxes to make contaminated images that need to be repaired
# Press the space bar to perform the repair function
# Press R to reset the mask to be repaired
Press esc to exit
import cv2
import numpy as np


class Sketcher:
    def __init__(self, windowname, dests, colors_func) :
        self.prev_pt = None  # line starting point
        self.drag_start = None  # start of rectangle
        self.drag_rect = None  Coordinates of the rectangle (upper left corner, lower right corner
        self.windowname = windowname
        self.dests = dests
        self.colors_func = colors_func
        self.dirty = False
        self.drawing = False
        self.mode = False
        self.show()
        cv2.setMouseCallback(self.windowname, self.on_mouse)

    def show(self) :
        cv2.imshow(self.windowname, self.dests[0])

    def on_mouse(self, event, x, y, flags, param) :
        pt = (x, y)
        if event == cv2.EVENT_LBUTTONDOWN:
            self.prev_pt = pt
            self.drawing = True
        elif event == cv2.EVENT_RBUTTONDOWN:
            Set pt to the first initialization, leaving the previous point as the starting point of the rectangle
            if self.drag_start == None:
                self.drag_start = pt

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

        if self.drag_start and flags & cv2.EVENT_FLAG_RBUTTON:
            xo, yo = self.drag_start
            x0, y0 = np.minimum([xo, yo], [x, y])
            x1, y1 = np.maximum([xo, yo], [x, y])
            self.drag_rect = None
            if x1 - x0 > 0 and y1 - y0 > 0:
                self.drag_rect = (x0, y0, x1, y1)
                for dst, color in zip(self.dests, self.colors_func()):
                    cv2.rectangle(dst, (x0, y0), (x1, y1), color, -1)
                self.dirty = True
                self.drag_start = None
                self.drag_rect = None
                self.show()
            else:
                self.drag_start = pt

    @property
    def dragging(self) :
        return self.drag_rect is not None


def main() :
    import sys
    try:
        fn = sys.argv[1]
    except:
        fn = 'images/ml_.jpg'

    img = cv2.imread(fn)
    if img is None:
        print('Failed to load image file:', fn)
        sys.exit(1)

    img_mark = img.copy()
    mark = np.zeros(img.shape[:2], np.uint8)
    sketch = Sketcher('img', [img_mark, mark], lambda: ((255.255.255), 255))

    while True:
        ch = cv2.waitKey()
        if ch == 27:
            break
        if ch == ord(' '):
            cv2.imshow('mask', mark)
            fmmres = cv2.inpaint(img_mark, mark, 3, cv2.INPAINT_TELEA)
            nsres = cv2.inpaint(img_mark, mark, 3, cv2.INPAINT_NS)
            cv2.imshow('inpaint fmm res', fmmres)
            cv2.imshow('inpaint ns res', nsres)
        if ch == ord('r'):
            img_mark[:] = img
            mark[:] = 0
            sketch.show()

    print('Done')


if __name__ == '__main__':
    main()
    cv2.destroyAllWindows()
Copy the code

reference

  • Docs.opencv.org/3.0-beta/do…