如何使用 python opencv 从图像中删除隐藏标记?

How to remove hidden marks from images using python opencv?

我想做一个小项目来挑战我的计算机视觉和图像处理技能。我遇到了一个项目,我想从图像中删除隐藏的标记。这里的隐藏是指水印在rgbspace中不容易看到,但是当你转换成hsv或其他一些space时,水印就变得可见了。

这是一个例子:

BGR SPACE:

HSV SPACE:

我尝试了不同的方法,但能够实施一个解决方案,从图像中删除这些水印。我在这里发布这个问题是为了获得解决这个问题的不同想法。

我试过的:

我尝试了多种方法,但 none 方法有效,共享代码可能无济于事。没有必要为此提供代码,伪代码、想法或任何线索将不胜感激。

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

代码:

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

问题:这并没有解决问题,它确实使颜色变暗了一点,但图像颜色也受到了干扰。

  1. 我试了一下B频道,看看能不能有所作为。

  2. 我还注意到,如果我们将图像转换为 LUV space,那么标记在 V space.

    中可见

如果您设法隔离了任何频道中的水印,您应该能够对其设置阈值并创建一个二进制掩码。然后你可以使用修复来填补空白,比如:

    clean_image = cv2.inpaint(marked_image, mask_of_marks, 3, cv2.INPAINT_TELEA)

这可能是一种可行的方法。基本思想是 HSV 通道中存在原始图像中不存在的可见边缘。这是 H、S 和 V 通道 side-by-side:

因此,如果我们找到原始图像中的边缘和 HSV 图像中的边缘并将它们相差,水印应该会显示出来。然后可以将其用作掩码,使用 OpenCV inpaint.

在原始图像中执行 in-painting

我只是在终端中使用 ImageMagick,但使用 OpenCVPIL 也可以同样完成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

# 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

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

想法是水印现在被识别为黑色,所以在 OpenCV 中使用黑色区域(可能在形态上闭合)作为遮罩来修复 - 参见 link 以上。

我没有找到任何完全解决问题的答案。不过,我感谢大家的努力(谢谢)。 我自己做了一些事情,想分享一下。它导致很少的质量损失(有点蓝色模糊)但成功地去除了水印。解决方案很简单,但是需要时间来分析图像。

如果有人可以扩展这种方法并提出更好的方法,我将非常高兴

我观察到水印只在Bspace(非RGB)可见,R和Gspace没有水印痕迹。

B space:

与 R 和 G 通道相比,蓝光对整体图像的贡献很小,因此我决定这样做。

对 B 通道进行足够大的模糊处理,以消除这些模式的痕迹。下面是 B 通道之后的显示方式:

最后,将图像与新的B通道、之前的R通道和之前的G通道合并。以下是 RGB 通道之后的显示方式:

使用approach的好处是痕迹没有了

唯一不足的是黑边出现偏蓝偏紫的现象,画面整体偏蓝

我的代码:

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')

这里是您在 Python/OpenCV 中处理的细微变化和扩展。

主要区别在于我使用中位数而不是模糊,并且我尝试提取黑线并在重新组合之前将它们强加到中位数。

输入:

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)

蓝色通道中位数:

蓝色通道阈值(黑色线条):

新的蓝色频道:

结果:


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

Python/OpenCV 中的另一个简单解决方案是简单地将绿色通道替换为蓝色通道,因为大部分绿色通道的强度分布与蓝色通道的强度分布大致相同。

输入:

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)

结果:

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

人们可能会尝试修改绿色通道图像的副本,使其具有平均值,并 standard-deviation 作为蓝色通道来解决外套问题。对于绿树,它位于水印区域之外,因此可以使用 inRange 来掩盖绿树的颜色,然后在绿色通道的副本中替换蓝色通道图像的树。然后重新组合修改后的绿色通道代替蓝色通道。