如何使用Python OpenCV从图像中删除隐藏的标记?

13

我想挑战一下我的计算机视觉和图像处理技能,于是想从一个小项目开始。我遇到了一个项目,希望从图片中删除隐藏的标记。这里的“隐藏”指的是水印,在RGB空间中不易看到,但当你转换为HSV或其他空间时,标记就会变得可见。

以下是一个示例:

BGR空间:

enter image description here

HSV空间:

enter image description here

我尝试了不同的方法,但都没有实现可以去除图像中的水印的解决方案。我在这里发布这个问题,以获得解决这个问题的不同思路。

我尝试过的方法:

我已经尝试了各种方法,但都没有成功,分享代码可能并不能帮助到您。不必提供代码,伪代码、思路或任何线索都将受到赞赏。

  1. 我注意到隐藏的标记都是类似于RGB(90,94,105)的颜色。当我分别显示R、G和B通道时,我发现水印只在B通道中可见。我想如果在B通道中调整/删除标记,然后再合并图像,可能会得到更好的结果。

代码:

b,g,r = cv2.split(img)
b = b//2;
r = cv2.merge((r,g,b))
cv2.imshow("image",r)

问题:这并没有解决问题,虽然颜色变得更暗淡了,但是图像颜色也受到了影响。

  1. 我尝试调整B通道看看能否实现一些东西。

  2. 我还注意到,如果将图像转换为LUV空间,则标记可在V空间中可见。


你在说哪些“不同的方法”?这还不足以进行下去。 - rayryeng
让我更新问题以便更详细地阐述。同时,您能否分享一下对这个问题的想法? - Hissaan Ali
1
有趣的问题。我很快会看一下。目前我无法做到。 - rayryeng
请将您目前最佳解决方案的 [mre] 编辑到您的问题中。 - DisappointedByUnaccountableMod
1
顺便提一下,如果你检查RGB通道,数字只在蓝色通道上可见。我试图解决这个问题,但没有成功。 - Yunus Temurlenk
显示剩余5条评论
5个回答

5
这可能是一种可行的方法。其基本思想是,在HSV通道中存在在原始图像中不存在的边缘。以下是H、S和V通道并排显示的图像:

enter image description here

如果我们在原始图像和HSV图像中找到边缘并将它们相减,水印就应该出现了。然后可以将其用作掩模,在原始图像中使用OpenCV inpaint进行修复。
我只是在终端中使用ImageMagick,但同样可以使用OpenCVPILscikit-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

这个想法是将水印标记为黑色,然后在 OpenCV 中使用黑色区域(可能是形态学闭合的)作为掩模进行修复 - 参见上面的链接。

1
我也尝试过使用这种方法,但在寻找轮廓时的噪声会影响结果。在你的结果中也存在噪声。 - Yunus Temurlenk

2
我没有找到完全解决这个问题的答案。虽然我很感激大家的努力(谢谢),但我自己做了一些工作并想分享一下。这种方法会导致少量质量损失(略带蓝色模糊),但成功地去除了水印。这个解决方案非常简单,但分析图像需要时间。 如果有人能够扩展这种方法并提出更好的解决方案,我将非常高兴。 我观察到水印只在B空间(RGB之外)可见,在R和G空间中没有水印的痕迹。 B空间:

enter image description here

我还读到过,与R和G通道相比,蓝光对整体图像的贡献很小,所以我决定这样做。通过足够大的模糊来消除这些图案的痕迹。以下是B通道的处理方式:

enter image description here

最后,将图像与新的B通道、以前的R和以前的G通道合并。下面是RGB通道合并后的效果:

enter image description here

使用这种方法的优点是痕迹被消除了。
唯一的缺点是在黑色边缘处出现蓝紫色,整体图像略带蓝色。 我的代码:
import cv2
from matplotlib import pyplot as plt
import numpy as np
img = cv2.imread("img.png")
b, g, r = cv2.split(img) # split into B,G,R spaces 
b = cv2.GaussianBlur(b, None, 8)
plt.imshow(cv2.merge((r,g,b)), cmap='gray')

1
这里是Python/OpenCV处理的轻微变化和扩展。
主要区别在于我使用中值而不是模糊,并且在重新组合之前尝试提取黑线并将其强加到中值上。
输入:

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)

enter image description here

蓝色通道阈值(用于黑线):

enter image description here

新的蓝色通道:

enter image description here

结果:

enter image description here


许多错误的蓝线现在变成了黑色,但不是全部。增加阈值会得到更多的黑线,但是隐藏的标记将再次部分出现。

1
蓝色被去除了,但大部分白色区域被转换为浅棕色。 - Hissaan Ali

0
如果你已经成功地在任意通道中隔离出了水印,那么你应该能够将其阈值化并创建一个二进制掩模。然后,你可以使用修补技术来填充缺口,例如:
    clean_image = cv2.inpaint(marked_image, mask_of_marks, 3, cv2.INPAINT_TELEA)

2
OP没有将它们隔离出来。这就是问题的关键所在。 - rayryeng

0

在Python/OpenCV中,另一个微不足道的解决方案是将绿色通道替换为蓝色通道,因为大多数绿色通道的强度分布与蓝色通道相似。

输入:

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)

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

# write results to disk
cv2.imwrite("cartoon_hidden_marks_result2.png", img_new)

# display it
cv2.imshow("result", img_new)
cv2.waitKey(0)

结果

enter image description here

问题在于外套和绿树的颜色和质地略有不同。

可以尝试修改绿色通道图像的副本,使其均值和标准差与蓝色通道相同,以解决外套问题。对于绿树,它位于水印区域之外,因此可以使用inRange来掩盖绿树颜色,然后将蓝色通道图像的树替换为绿色通道的副本中的树。然后将修改后的绿色通道重新组合到蓝色通道的位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接