How to remove hidden marks from images using python opencv?

This might be a possible approach. The underlying idea is that there are edges visible in the HSV channel that are not present in the original image. Here are the H, S and V channels side-by-side:

enter image description here

So if we find the edges in the original image and the edges in the HSV image and difference them, the watermarking should show up. That can then be used as a mask to do in-painting in the original image with OpenCV inpaint.

I am just using ImageMagick here in Terminal, but it could all be done equally with OpenCV, PIL or scikit-image:

# Detect edges visible in original image and auto-level
convert watermarked.png -colorspace gray -auto-level -canny 0x1+1%+3% -auto-level  RGB-edges.png

enter image description here

# Find visible edges in H, S and V colourspace, generate mean across all three and auto-level
convert watermarked.png -colorspace hsv -separate -canny 0x1+1%+3% -evaluate-sequence mean -auto-level HSV-edges.png

enter image description here

# Find changemask between the two sets of edges
convert RGB-edges.png HSV-edges.png -compose changemask -composite result.png

enter image description here

The idea is that the watermarking is now identified in black, so use the black areas (maybe morphologically closed) as a mask in OpenCV to inpaint - see link above.


Here is a slight variation and extension of your processing in Python/OpenCV.

The main difference is that I use the median rather than a blurring and that I try to extract the black lines and impose them on the median before recombining.

Input:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread("cartoon_hidden_marks.png")

# separate channels
b,g,r = cv2.split(img)

# median filter blue
median = cv2.medianBlur(b, 21)

# threshold blue image to extract black lines
thresh = cv2.threshold(b, 20, 255, cv2.THRESH_BINARY)[1]

# apply thresh to median
b_new = cv2.bitwise_and(median, thresh)

# combine b_new, g, b
img_new = cv2.merge([b_new,g,r])

# write results to disk
cv2.imwrite("cartoon_hidden_marks_median.jpg", median)
cv2.imwrite("cartoon_hidden_marks_thresh.jpg", thresh)
cv2.imwrite("cartoon_hidden_marks_new_blue.jpg", b_new)
cv2.imwrite("cartoon_hidden_marks_result.png", img_new)

# display it
cv2.imshow("median", median)
cv2.imshow("thresh", thresh)
cv2.imshow("b_new", b_new)
cv2.imshow("img_new", img_new)
cv2.waitKey(0)

Blue channel median:

enter image description here

Blue channel threshold (for black lines):

enter image description here

New blue channel:

enter image description here

Result:

enter image description here


Many of the erroneous blue lines are now black, but not all. Increasing the threshold would have gotten more black lines, but then the hidden marks would have appeared again in part.