从明亮的彩条下发现图像

Discover an image from under bright color bars

背景

给定一张覆盖有亮色条的黑白图像,目标是识别它。原始图像仍然可见,但不够清晰,无法识别。

问题

给定一个 RGB 格式的像素,我需要确定它是彩色的还是黑白的。我应该将它与一系列值进行比较吗?

识别后我想将像素反转为原始像素black & white。在不覆盖原始像素的情况下应该进行哪些计算?

我曾尝试将可能指示彩色像素的值归零,但这种技术覆盖了彩色条后面的原始图像。

最终结果

反转后原图应该足够可见了。
提前致谢。

“给定一个像素 (252, 173, 28),作为 RGB 格式,我需要确定它是彩色的还是黑白的。” - 黑色将靠近 (0,0,0),白色 (255,255,255) 看向 RGB Color Space。 您可以使用 FFT 方法去除某种频率,正如您在 this post.

中看到的那样

转换为灰度似乎是一个合理的开始:

import cv2

# Load image as greyscale and save
im = cv2.imread('rainbow.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imwrite('result.png',im)

关于您的示例图像的第一件事是色带非常特定于 RGB;叠加的颜色是纯红色、绿色、蓝色、品红色、黄色、青色和白色。这似乎表明修改图像的方式是将通道的一些随机 selection 发送到 255(或者以其他方式将它们放大一些常数或乘数)。 None 图像中的亮点变暗,这表明这些值只是更改为更高的值。由于图像是压缩的 jpeg,这些值也有点模糊。

为了更仔细地观察这种行为,我们可以看一下图像中每个颜色通道的值在图像的特定列上的分布。例如,图像的第一列具有以下像素颜色分布:

从这张图中可以非常明显地看出,红色通道上的值分布与绿色和蓝色通道完全不同,并且所有值都接近红色通道的最大值。这提出了一种检测策略,即在每一列上取每个通道的中值或平均值,并将其阈值设为 select“坏”通道。例如,任何通道的平均值超过 230 或每列的值都是“坏”通道。 运行 通过这个过程给出以下频道为坏;您可以看到它非常接近图像中的实际色带:

您还可以使用统计技术,例如阈值标准偏差而不是实际值(或使用值、标准偏差、偏度、峰度等的某种组合)以获得一些稳健性。

我们可以用其余通道的平均值或中值来估算坏通道中的值:

但是,当您执行此操作时,您可以看到整个过程中有一些明亮的单列条带,这些条带对应于错误通道识别有点失败的列。失败的发生部分是因为图像是 jpeg,部分是因为一些颜色混合在一起(即颜色变化不一定发生在像素的边缘),很难 select 正确的阈值,等等。这些问题在放大的图片上更容易看到:

但是,我们可以做一些比上述所有事情更简单的事情。特别是,对于每一列,我们知道坏通道总是最亮的通道。由于图像最终是灰度的,我们只需要每个像素一个通道。这意味着我们可以简单地为每一列选择最暗的通道,我们永远不会得到坏的列(除非所有三个通道都坏,在这种情况下信息被破坏)。

所以这个过程只是select每列颜色通道的最小值,这比上述方法更容易用代码表达。而且我们也不必调整任何阈值。

# take the average value over each column
mean_columns = np.mean(img, axis=0)  

# find the channels which have the minimum average value
channel_select = np.argmin(mean_columns, axis=1)

# reshape the result just to be passed into take_along_axis
channel_select = np.expand_dims(channel_select, axis=(0, 2))

# take the selected channels, squeeze just removes an unnecessary axis
gray = np.take_along_axis(img, channel_select, axis=2).squeeze()

这是该操作的结果:

一种简洁的查看方式是 RGB 灰度图像具有三个相同的通道,即它包含冗余信息。您的某些图像列因某些通道的值按比例放大而损坏,但最小值在此过程中是不变的,除非 所有 通道都已损坏。所以利用这个不变量可以让你恢复大部分数据。

您可能会考虑 OpenCV 中的除法归一化


    1. 将输入转换为灰度
    1. 应用高斯模糊
    1. 申请分部

import cv2

if __name__ == '__main__':
    # Step 1: Convert input to the grayscale
    img = cv2.imread("kztMK.png")
    gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Step 2: Apply Gaussian Blur
    blr = cv2.GaussianBlur(gry, (95, 95), 0)

    # Step 3: Apply Division
    div = cv2.divide(gry, blr, scale=125)

结果: