304 votes

Comment convertir une image RVB en niveaux de gris en Python ?

J'essaie d'utiliser matplotlib pour lire une image RVB et la convertir en niveaux de gris.

Dans matlab, j'utilise ceci :

img = rgb2gray(imread('image.png'));

Dans le cadre de la matplotlib tutorial ils ne le couvrent pas. Ils se contentent de lire dans l'image

import matplotlib.image as mpimg
img = mpimg.imread('image.png')

puis ils découpent le tableau, mais ce n'est pas la même chose que de convertir RVB en niveaux de gris, d'après ce que j'ai compris.

lum_img = img[:,:,0]

J'ai du mal à croire que numpy ou matplotlib n'aient pas une fonction intégrée pour convertir de rgb en gray. N'est-ce pas une opération courante dans le traitement des images ?

J'ai écrit une fonction très simple qui fonctionne avec l'image importée à l'aide de imread en 5 minutes. C'est terriblement inefficace, mais c'est pourquoi j'espérais une mise en œuvre professionnelle intégrée.

Sebastian a amélioré mon fonctionnement, mais j'espère toujours trouver l'appareil intégré.

l'implémentation de matlab (NTSC/PAL) :

import numpy as np

def rgb2gray(rgb):

    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

    return gray

453voto

unutbu Points 222216

Pourquoi ne pas le faire avec Oreiller :

from PIL import Image
img = Image.open('image.png').convert('L')
img.save('greyscale.png')

Si un canal alpha (transparence) est présent dans l'image d'entrée et doit être préservé, utiliser le mode LA :

img = Image.open('image.png').convert('LA')

Utilisation de matplotlib et la formule

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

vous pourriez faire :

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

img = mpimg.imread('image.png')     
gray = rgb2gray(img)    
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()

99voto

yangjie Points 4219

Vous pouvez également utiliser scikit-image qui fournit des fonctions permettant de convertir une image en ndarray , comme rgb2gray .

from skimage import color
from skimage import io

img = color.rgb2gray(io.imread('image.png'))

Notes : Les poids utilisés dans cette conversion sont calibrés pour les phosphores contemporains des tubes cathodiques : Y = 0,2125 R + 0,7154 G + 0,0721 B

Vous pouvez également lire l'image en niveaux de gris :

from skimage import io
img = io.imread('image.png', as_gray=True)

88voto

Maximilian Peters Points 13600

La vitesse de trois des méthodes proposées a été testée avec 1000 images RGBA PNG (224 x 256 pixels) fonctionnant avec Python 3.5 sur Ubuntu 16.04 LTS (Xeon E5 2670 avec SSD).

Durée moyenne d'exécution

pil : 1,037 seconde

scipy: 1,040 seconde

sk : 2.120 secondes

PIL et SciPy ont donné des résultats identiques numpy (de 0 à 255). SkImage donne des tableaux de 0 à 1. De plus, les couleurs sont converties de manière légèrement différente, voir l'exemple de la page Ensemble de données CUB-200.

SkImage: SkImage

PIL : PIL

SciPy : SciPy

Original: Original

Diff : enter image description here

Code

  1. Performance

    run_times = dict(sk=list(), pil=list(), scipy=list())
    for t in range(100):
        start_time = time.time()
        for i in range(1000):
            z = random.choice(filenames_png)
            img = skimage.color.rgb2gray(skimage.io.imread(z))
        run_times['sk'].append(time.time() - start_time)
    
    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = np.array(Image.open(z).convert('L'))
    run_times['pil'].append(time.time() - start_time)
    
    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = scipy.ndimage.imread(z, mode='L')
    run_times['scipy'].append(time.time() - start_time)
    
    for k, v in run_times.items():
        print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))
  2. Sortie

    z = 'Cardinal_0007_3025810472.jpg'
    img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
    IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
    img2 = np.array(Image.open(z).convert('L'))
    IPython.display.display(PIL.Image.fromarray(img2))
    img3 = scipy.ndimage.imread(z, mode='L')
    IPython.display.display(PIL.Image.fromarray(img3))
  3. Comparaison

    img_diff = np.ndarray(shape=img1.shape, dtype='float32')
    img_diff.fill(128)
    img_diff += (img1 - img3)
    img_diff -= img_diff.min()
    img_diff *= (255/img_diff.max())
    IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
  4. Importations

    import skimage.color
    import skimage.io
    import random
    import time
    from PIL import Image
    import numpy as np
    import scipy.ndimage
    import IPython.display
  5. Versions

    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1

41voto

Vous pouvez toujours lire le fichier image en niveaux de gris dès le début en utilisant imread d'OpenCV :

img = cv2.imread('messi5.jpg', 0)

En outre, si vous souhaitez lire l'image en RVB, effectuer un traitement et ensuite la convertir en échelle de gris, vous pouvez utiliser cvtcolor d'OpenCV :

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

29voto

YPCrumble Points 526

La méthode la plus rapide et la plus courante consiste à utiliser Oreiller , installé par l'intermédiaire de pip install Pillow .

Le code est alors le suivant :

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X