web-dev-qa-db-fra.com

Comment vérifier si une image jpeg est en couleur ou en niveaux de gris en utilisant uniquement Python stdlib

Je dois écrire un scénario de test en python pour vérifier si une image jpg est en couleur ou en niveaux de gris. Quelqu'un peut-il me faire savoir s'il existe un moyen de le faire sans installer des bibliothèques supplémentaires comme opencv?

14
kadina

Réponse en expansion @gat:

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

En gros, vérifiez chaque pixel pour voir s’il est en niveaux de gris (R == G == B)

9
joaoricardo000

Peut être fait comme suit:

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'
10
superMind

Pour un traitement plus rapide, il est préférable d'éviter les boucles sur chaque pixel, en utilisant ImageChops (mais aussi pour être sûr que l'image est vraiment en niveaux de gris, nous devons comparer les couleurs sur chaque pixel et ne pas utiliser la somme):

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
5
Karl K

Une amélioration des performances pour des résultats rapides: comme beaucoup d'images ont une bordure noire ou blanche, vous pouvez vous attendre à une fin plus rapide en échantillonnant quelques points i, j aléatoires de im et les tester? Vous pouvez également utiliser l’arithmétique modulo pour parcourir les lignes de l’image. D'abord, nous échantillonnons (sans remplacement), disons 100 points aléatoires i, j; dans le cas peu probable où cela ne serait pas concluant, nous le numériserions linéairement.

Utilisation d’un itérateur personnalisé iterpixels (im). Je n'ai pas installé PIL, je ne peux donc pas le tester, voici le résumé:

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())

(Ma remarque originale est également vérifiée. Commencez par vérifier l'en-tête JPEG, offset 6: nombre de composants (1 = niveaux de gris, 3 = RVB). S'il s'agit de 1 = niveaux de gris, vous connaissez déjà la réponse sans avoir à inspecter les pixels individuels.)

4
smci

Pourquoi n'utiliserions-nous pas le module ImageStat?

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 nous donne la somme de tous les pixels de la vue liste = [R, V, B], par exemple [568283302.0, 565746890.0, 559724236.0]. Pour une image en niveaux de gris, tous les éléments de la liste sont égaux.

1
GriMel