How to check if jpeg image is color or gray using only Python stdlib

I need to write a test case in python to check if a jpg image has color or shades of gray. Can someone please tell me if there is a way to do this without installing additional libraries like opencv?

+7
python image-processing
source share
6 answers

@ Gat answer extension:

import Image def is_grey_scale(img_path="lena.jpg"): im = Image.open(img_path).convert('RGB') w,h = im.size for i in range(w): for j in range(h): r,g,b = im.getpixel((i,j)) if r != g != b: return False return True 

Basically check each pixel to see if it is grayscale (R == G == B)

+5
source share

You can do the following:

 from scipy.misc import imread, imsave, imresize image = imread(f_name) if(len(image.shape)<3): print 'gray' elif len(image.shape)==3: print 'Color(RGB)' else: print 'others' 
+5
source share

Improving performance for faster results: since many images have a black or white border, do you expect faster completion by selecting a few random i, j points from im and testing them? Or use modulo arithmetic to move lines of the image. First, we trace (without replacement) 100 random i, j-points; in the unlikely event this is not final, then we scan it linearly.

Using the iterpixels custom iterator (im). I do not have PIL, so I can not check this, here is the diagram:

 import Image def isColor(r,g,b): # use tuple-unpacking to unpack pixel -> r,g,b return (r != g != b) class Image_(Image): def __init__(pathname): self.im = Image.open(pathname) self.w, self.h = self.im.size def iterpixels(nrand=100, randseed=None): if randseed: random.seed(randseed) # For deterministic behavior in test # First, generate a few random pixels from entire image for randpix in random.choice(im, n_rand) yield randpix # Now traverse entire image (yes we will unwantedly revisit the nrand points once) #for pixel in im.getpixel(...): # you could traverse rows linearly, or modulo (say) (im.height * 2./3) -1 # yield pixel def is_grey_scale(img_path="lena.jpg"): im = Image_.(img_path) return (any(isColor(*pixel)) for pixel in im.iterpixels()) 

(Also, my original point is, first you check the JPEG header, offset 6: number of components (1 = grayscale, 3 = RGB). If it's 1 = grayscale, you already know the answer without having to check individual pixels.)

+3
source share

For faster processing, it is better to avoid loops on each pixel using ImageChops (but also to make sure the image is really gray, we need to compare the colors on each pixel and not just use the sum):

 from PIL import Image,ImageChops def is_greyscale(im): """ Check if image is monochrome (1 channel or 3 identical channels) """ if im.mode not in ("L", "RGB"): raise ValueError("Unsuported image mode") if im.mode == "RGB": rgb = im.split() if ImageChops.difference(rgb[0],rgb[1]).getextrema()[1]!=0: return False if ImageChops.difference(rgb[0],rgb[2]).getextrema()[1]!=0: return False return True 
+2
source share

Why don't we use the ImageStat module?

 from PIL import Image, ImageStat def is_grayscale(path="image.jpg") im = Image.open(path).convert("RGB") stat = ImageStat.Stat(im) if sum(stat.sum)/3 == stat.sum[0]: return True else: return False 

stat.sum gives us the sum of all the pixels in the form of a list = [R, G, B], for example [568283302.0, 565746890.0, 559724236.0]. For grayscale images, all list items are equal.

0
source share

As you are probably right, OpenCV may be redundant for this task, but you need to use the Python Image Library (PIL) for this. The following should work for you:

 import Image im = Image.open("lena.jpg") 

EDIT As Mark and JRicardo000 noted, you can iterate over each pixel. You can also use the im.split () function here.

-one
source share

All Articles