【问题标题】:Detect almost grayscale image with Python用 Python 检测几乎灰度图像
【发布时间】:2023-02-20 10:47:37
【问题描述】:

Inspired by this question and this answer (which isn't very solid) I realized that I often find myself converting to grayscale a color image that is almost grayscale (usually a color scan from a grayscale original). So I wrote a function meant to measure a kind of distance of a color image from grayscale:

import numpy as np
from PIL import Image, ImageChops, ImageOps, ImageStat

def distance_from_grey(img): # img must be a Pillow Image object in RGB mode
    img_diff=ImageChops.difference(img, ImageOps.grayscale(img).convert('RGB'))
    return np.array(img_diff.getdata()).mean()

img = Image.open('test.jpg')
print(distance_from_grey(img))

The number obtained is the average difference among all pixels of RGB values and their grayscale value, which will be zero for a perfect grayscale image.

What I'm asking to imaging experts is:

  • is this approach valid or there are better ones?
  • at which distance an image can be safely converted to grayscale without checking it visually?
  • I am not an expert. Intuitively, I would say you need to square the differences before adding them up, and then taking the square root again: Error = 1/N * sqrt(Sum error_i^2). In that case, if some pixels deviate a lot and others don't at all, this is considered worse than if every pixel deviates a little bit.
  • You could use a perceptually uniform colourspace, e.g. JzAzBz, ICtCp, OkLab, convert to Lightness, Chroma, Hue (LCH) representation and check whether the Chroma is close to zero.
  • @KelSolaar Very interesting, I'm studying your comment, I'm sure many would be grateful if you showed how to do in an answer.
  • Not sure exactly what cases you need to discriminate between, but you could consider the saturation in HSV colourspace as an indication of greyness stackoverflow.com/a/74874586/2836621

标签: python colors python-imaging-library grayscale


【解决方案1】:

给定以下 3 张图像并使用 Colour

import numpy as np
import colour

image_1 = colour.read_image("mcdonald_lake.png")
# "mcdonald_lake.png" is single channel, we convert it to 3
image_1 = colour.utilities.tstack([image_1, image_1, image_1])
image_2 = colour.read_image("niagara_falls.png")
image_3 = colour.read_image("colouring_pencils.png")

# Converting from assumed "sRGB" encoded, i.e. "Output-Referred" to "Oklab" using Colour's Automatic Colour Conversion Graph.
image_1_OkLab = colour.convert(image_1, "Output-Referred RGB", "Oklab")
image_2_OkLab = colour.convert(image_2, "Output-Referred RGB", "Oklab")
image_3_OkLab = colour.convert(image_3, "Output-Referred RGB", "Oklab")

# Converting from "Lightness" and "a", "b" opponent colour dimensions
# to "Lightness", "Chroma" and "Hue".
image_1_OkLab_JCh = colour.models.Jab_to_JCh(image_1_OkLab)
image_2_OkLab_JCh = colour.models.Jab_to_JCh(image_2_OkLab)
image_3_OkLab_JCh = colour.models.Jab_to_JCh(image_3_OkLab)

print(np.mean(image_1_OkLab_JCh[..., 1]))
print(np.mean(image_2_OkLab_JCh[..., 1]))
print(np.mean(image_3_OkLab_JCh[..., 1]))
6.14471772026e-05
0.0292843706963
0.0798391223111

例如,如果您想使用ICtCp,您只需将上面的"Oklab"更改为"ICtCp"即可。

还可以使用 verbose={"mode": "Long"} 参数详细了解图表运行的计算:

colour.convert(image_1, "Output-Referred RGB", "Oklab", verbose={"mode": "Long"})

谷歌 Colab 笔记本:https://colab.research.google.com/drive/1aDyUa4hSeCn-Sj47nUOilRAghl0fpd_W?usp=sharing

【讨论】:

  • 谢谢,这就是我一直在寻找的质量答案,效果很好,输出值不同几乎是灰色的从彩色图像中提取大约 4 倍,而使用我的方法,该因子约为 2.5,所以这是一个很好的改进,我相信结果会更可靠。
  • 最近几天在colour包安装中有什么变化吗conda install -c conda-forge colour-science?安排另一个环境我得到一个错误,说 networkx 模块丢失,我必须手动安装它。
  • 我们这边什么都没有!
【解决方案2】:

该答案假定您的灰度函数是幂等的,如果这不成立,请完全忽略该答案。

这种方法有效吗

取决于你的输入看起来如何以及你期望做什么,考虑某些边缘情况:你的图像由两部分组成,左半部分是灰度,右半部分是彩色,应该发生什么?

更好的?

取决于你的定义更好的,我建议尝试使用其他功能代替mean,例如最大值或中值。

【讨论】:

  • 我的主要目的是自动检测图像何时是灰度原件(如黑白照片或绘图)的彩色扫描,因此我可以将其转换为灰度而不用目视检查。
猜你喜欢
  • 2020-10-11
  • 2021-02-07
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 2019-02-20
  • 2020-03-07
  • 1970-01-01
相关资源
最近更新 更多