从明亮的彩条下发现图像
背景
给定一个覆盖有亮色条的黑白图像,目标是识别它。原始图像仍然可见,但它不够清晰,无法识别。
题
给定一个像素作为RGB格式,我需要确定它是彩色的还是黑白的。我应该将它与一系列值进行比较吗?
确定后,我想将像素反转为原始像素black & white。在不覆盖原始像素的情况下应该进行哪些计算?
我试图将可能表示彩色像素的值归零,但这种技术覆盖了彩条后面的原始图像。
最后结果
反转后,原始图像应该足够可见。
提前致谢。
回答
关于您的示例图像的第一件事是色带非常特定于 RGB;叠加的颜色是纯红色、绿色、蓝色、品红色、黄色、青色和白色。这似乎表明修改图像的方式是将通道的一些随机选择发送到 255(或以其他方式将它们按某个常数或乘数放大)。图像中的任何亮点都没有变暗,这表明这些值仅更改为更高的值。由于图像是压缩的 jpeg,这些值也有点模糊。
为了更仔细地观察这种行为,我们可以查看图像中每个颜色通道中值在图像特定列上的分布。例如,图像的第一列像素的颜色分布如下:
从该图中可以非常明显地看出,红色通道上的值分布与绿色和蓝色通道完全不同,并且所有值都接近红色通道的最大值。这提出了一种检测策略,即在每列上取每个通道的中值或平均值,并将其设置为阈值以选择“坏”通道。例如,任何通道的平均值超过 230 或每列的值都是“坏”通道。通过这个过程,以下渠道是不好的;您可以看到它与图像中的实际色带非常接近:
您还可以使用统计技术,例如阈值标准偏差而不是实际值(或使用某些值、标准偏差、偏度、峰度等的组合)以获得一些稳健性。
我们可以用其余通道的平均值或中值来估算坏通道中的值:
但是,您可以在执行此操作时看到一些明亮的单列条带,它们对应于错误通道识别失败的列。失败部分是因为图像是 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 中的灰度图像具有三个相同的通道,即它包含冗余信息。您的某些图像列因某些通道的值被放大而损坏,但在此过程中最小值是不变的,除非所有通道都已损坏。因此,利用这个不变量可以恢复大部分数据。