Challenge¶
One of these three images is not a grayscale image.
Tomatoes 1
Tomatoes 2
Tomatoes 3
Download each image and do some investigative work in Python to figure out which one is the grayscale imposter.
Bonus
When I originally put this problem together, I tried using JPEG files instead of PNGs. But every time I saved the imposter image, it reverted back to being a non-imposter.
What was my mistake?
Solution¶
Tomatoes 2 is the imposter!
Grayscale images are usually represented by a 2-Dimensional array like this
[[0.1, 0.0, 0.9]
[0.0, 0.3, 0.0]
[0.1, 0.0, 0.5]]
However, when you load a PNG file into Python with XXX
or YYY
and convert it to an array, you'll get back a 3-Dimensional array with Red, Green, and Blue color channels included.
[[[0.1, 0.1, 0.1], [0.0, 0.0, 0.0], [0.9, 0.9, 0.9]]
[[0.0, 0.0, 0.0], [0.3, 0.3, 0.3], [0.0, 0.0, 0.0]]
[[0.1, 0.1, 0.1], [0.0, 0.0, 0.0], [0.5, 0.5, 0.5]]],
In such cases, gray pixels have an equal amount of each color channel. So, for a grayscale image, R == G == B for every pixel.
With this in mind, we can do some basic NumPy array logic to find the imposter.
import numpy as np
from PIL import Image
def is_grayscale(filepath):
"""Given the path to an image file, check if it's a grayscal image"""
# Load the image file
img = Image.open(filepath)
# Convert to array
arr = np.array(img)
# Check if R == G == B for every pixel
rg = np.all(arr[:, :, 0] == arr[:, :, 1])
rb = np.all(arr[:, :, 0] == arr[:, :, 2])
return bool(rg & rb)
is_grayscale("CV-tomatoes1.png") # true
is_grayscale("CV-tomatoes2.png") # false
is_grayscale("CV-tomatoes3.png") # true
Bonus Solution
JPEG uses lossy compression whereas PNG uses lossless compression.
When I saved my JPEG file, the compression algorithm decided that my slightly not-gray pixel was unimportant enough to be discarded.
In general, this is why people often recommend using PNG when you care about preserving quality and JPEG when you care about minimizing file size.