I have to write a test case in python to check whether a jpg image is in color or grayscale. Can anyone please let me know if there is any way to do it with out installing e
Why wouldn't we use 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 a sum of all pixels in list view = [R, G, B] for example [568283302.0, 565746890.0, 559724236.0]. For grayscale image all elements of list are equal.
As you are probably correct, OpenCV may be an overkill for this task but it should be okay to use Python Image Library (PIL) for this. The following should work for you:
import Image
im = Image.open("lena.jpg")
EDIT As pointed out by Mark and JRicardo000, you may iterate over each pixel. You could also make use of the im.split() function here.
In case of a grayscale image, all channels in a certain pixel are equal (if you only have one channel then you don't have a problem) . So basicly if you list all the pixels with their 3 channels values, you suppose to see that each pixel has all 3 channels equal.
Image.getcolors()
returns an unsorted list of (count, pixel) values.
im = Image.open('path_to_image.whatever')
color_count = im.getcolors()
If len(color_count)
exceeds 256, this method returns None - meaning that you had more than 256 color-options in your pixel list, hence it is a colored image (in case of grayscale you can only have 256 colors (0,0,0) to (255,255,255)).
So after that you only need :
if color_count:
# your image is grayscale
else:
# your images is colored
Notice this will work only when using the default parameter value of getcolors()
.
Documentation: https://pillow.readthedocs.io/en/3.0.x/reference/Image.html#PIL.Image.Image.getcolors
There is more pythonic way using numpy functionality and opencv:
import cv2
def isgray(imgpath):
img = cv2.imread(imgpath)
if len(img.shape) < 3: return True
if img.shape[2] == 1: return True
b,g,r = img[:,:,0], img[:,:,1], img[:,:,2]
if (b==g).all() and (b==r).all(): return True
return False
A performance-enhance for fast results: since many images have black or white border, you'd expect faster termination by sampling a few random i,j-points from im and test them? Or use modulo arithmetic to traverse the image rows. First we sample(-without-replacement) say 100 random i,j-points; in the unlikely event that isn't conclusive, then we scan it linearly.
Using a custom iterator iterpixels(im). I don't have PIL installed so I can't test this, here's the outline:
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 remark stands, first you check the JPEG header, offset 6: number of components (1 = grayscale, 3 = RGB). If it's 1=grayscale, you know the answer already without needing to inspect individual pixels.)
Expanding @gat answer:
import Image
def is_grey_scale(img_path):
img = Image.open(img_path).convert('RGB')
w,h = img.size
for i in range(w):
for j in range(h):
r,g,b = img.getpixel((i,j))
if r != g != b: return False
return True
Basically, check every pixel to see if it is grayscale (R == G == B)