Fabio Spoto
Fabio Spoto

Reputation: 11

Inpainting looks blurry

I want to remove a watermark from a image and result looks blurry on the watermarks. I need help to fix this.

Original Image Original Image

Mask Mask

Result Result

I have used the inpaint function from opencv. My code looks like this.

import cv2 
import matplotlib.pyplot as plt 
import numpy as np
import time 

start = time.time()

IMAGE = "images/img.jpg"
MASK = "images/mask.png"

image = cv2.imread(IMAGE)
mask = cv2.imread(MASK, 0)

img = cv2.inpaint(image, mask, 0, cv2.INPAINT_NS)

cv2.imwrite("output.jpg", img)

print(time.time()-start)

Upvotes: 0

Views: 550

Answers (1)

stateMachine
stateMachine

Reputation: 5815

There are some artifacts that the in-painting algorithm produces; it's difficult to completely get rid of them. This is my take trying to minimize the artifacts. It basically involves converting the BGR image to LAB, splitting the L channel, in-painting only this channel, merging the components and then converting back to BGR:

import cv2

# Set image path
directoryPath = "D://opencvImages//"

# Load image:
inputImage = cv2.imread(directoryPath + "GzRoc.jpg")
showImage("Input Image", inputImage)

# To LAB:
labImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2LAB)
# Split LAB Image:
L, A, B = cv2.split(labImage)

# Load mask:
maskImage = cv2.imread(directoryPath + "H5DpA.png")
showImage("Input Mask", maskImage)

# Mask to grayscale:
maskImage = cv2.cvtColor(maskImage, cv2.COLOR_BGR2GRAY)

It appears that your mask is a little bit bigger than your input image. Let’s resize it because the in-painting algorithm needs exactly the same sizes for both images:

# Resize mask:
imageHeight, imageWidth = inputImage.shape[:2]
newSize = (imageWidth, imageHeight)
maskImage = cv2.resize(maskImage, newSize, interpolation=cv2.INTER_LINEAR)

# Threshold mask:
_, binaryMask = cv2.threshold(maskImage, 0, 255, cv2.THRESH_OTSU)

Let’s apply a little bit of morphology. Looks like a basic dilation helps mitigating the artifacts:

# Prepare in-paint mask:
kernelSize = (3, 3)
morphoKernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernelSize)
inpaintMask = cv2.morphologyEx(binaryMask, cv2.MORPH_DILATE, morphoKernel, iterations=1)

Now, let’s in-paint the L channel, merge it with the rest of the original components and convert back to BGR:

# In-paint the L channel:
inpaintedL = cv2.inpaint(L, inpaintMask, 0, cv2.INPAINT_NS)

# Merge LAB:
labImage = cv2.merge([inpaintedL, A, B])

# LAB to BGR:
outImage = cv2.cvtColor(labImage, cv2.COLOR_LAB2BGR)

cv2.imshow("OutImage", outImage)
cv2.waitKey(0)

This is the result:

Observation: Save your images using a lossless format such as png, your original image is jpeg and you can see some compression artifacts already before performing any processing.

Upvotes: 2

Related Questions