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:
Given the following 3 images and using 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
If you want to use ICtCp
for example, you can simply change "Oklab"
for "ICtCp"
above.
It is also possible to get a detailed overview of the computations ran by the graph by using the verbose={"mode": "Long"}
argument:
colour.convert(image_1, "Output-Referred RGB", "Oklab", verbose={"mode": "Long"})
Google Colab Notebook: https://colab.research.google.com/drive/1aDyUa4hSeCn-Sj47nUOilRAghl0fpd_W?usp=sharing