首页 > 解决方案 > 从明亮的彩条下发现图像

问题描述

背景

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

在此处输入图像描述

问题

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

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

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

最后结果

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

标签: pythonimageopencvimage-processingrgb

解决方案


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

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

历史

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

脱粒

原版

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

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

从 std < thresh 清除

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

放大

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

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

# 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 中的灰度图像具有三个相同的通道,即它包含冗余信息。您的某些图像列被某些通道值按比例放大而损坏,但最小值在此过程中是不变的,除非所有通道都已损坏。因此,利用这个不变量可以让您恢复大部分数据。


推荐阅读