web-dev-qa-db-fra.com

Comment découper une image en canaux rouge, vert et bleu avec misc.imread

J'essaie de découper une image en RVB et j'ai un problème avec le traçage de ces images. J'obtiens toutes les images d'un certain dossier avec cette fonction:

def get_images(path, image_type):
image_list = []
for filename in glob.glob(path + '/*'+ image_type):
    im=misc.imread(filename, mode='RGB')
    image_list.append(im)
return image_list

Cette fonction crée un tableau 4d (30, 1536, 2048, 3) et je suis sûr que la première valeur représente le nombre d'images, les deuxième et troisième sont des dimensions et la troisième sont des valeurs RVB.

Après avoir obtenu toutes les images, je les ai stockées sous forme de tableau numpy

image_list = get_images('C:\HDR\images', '.jpg')
temp = np.array(image_list)

Après cela, j'ai essayé d'utiliser une simple découpe afin de prendre des couleurs spécifiques à partir de ces images:

red_images = temp[:,:,:,0]
green_images = temp[:,:,:,1]
blue_images = temp[:,:,:,2]

Lorsque j'imprime les valeurs, tout semble aller bien.

print(temp[11,125,311,:])
print(red_images[11,125,311])
print(green_images[11,125,311])
print(blue_images[11,125,311])

Et je reçois ce qui suit:

[105  97  76]
105
97
76

Jusqu'à présent, tout semble aller bien, mais le problème se pose lorsque j'essaie d'afficher l'image. J'ai utilisé matplotlib.pyplot.imshow pour l'afficher et j'obtiens l'image comme:

Image red channel

Ce qui est raisonnable, car je choisis le rouge:

 plt.imshow(temp[29,:,:,0])

Mais quand je le change en canal de couleur différent, comme ceci:

plt.imshow(temp[29,:,:,2])

Je reçois l'image comme ceci:

Image bug channel

Ma question est simple. Que se passe-t-il ici?

8
mrGreenBrown

Je pense que matplotlib traite simplement chaque canal (c'est-à-dire les intensités) comme une "carte thermique".

Passez une carte de couleur à la fonction imshow comme pour lui dire comment vous voulez qu'elle colorie votre image:

plt.imshow(image_slice, cmap=plt.cm.gray)

Éditer

@mrGreenBrown en réponse à votre commentaire, je suppose que le misc.imread la fonction que vous avez utilisée provient de scipy, c'est-à-dire scipy.misc.imread. Cette fonction n'est pas différente de celle de PIL. Voir scipy.misc.imread docs . Merci à @dai de l'avoir signalé.

Un seul canal de n'importe quelle image n'est que des intensités. Il n'a pas de couleur. Pour une image exprimée dans l'espace colorimétrique RVB, la couleur est obtenue en "mélangeant" des quantités (données par les intensités des canaux respectifs) de rouge, vert et bleu. Un seul canal ne peut pas exprimer la couleur .

Ce qui s'est passé, c'est que Matplotlib affiche par défaut les intensités sous forme de carte thermique, d'où la "couleur".

Lorsque vous enregistrez un seul canal en tant qu'image au format JPEG, la fonction duplique simplement le canal unique 3 fois afin que les canaux R, G et B contiennent tous les mêmes intensités. Il s'agit du comportement typique, sauf si vous l'enregistrez dans un format tel que PGM qui peut gérer l'image en niveaux de gris à canal unique. Lorsque vous essayez de visualiser cette image qui a le même canal dupliqué 3 fois, car les contributions du rouge, du vert et du bleu sont les mêmes à chaque pixel, l'image apparaît en gris.

Qui passe plt.cm.gray à l'argument cmap indique simplement à imshow de ne pas "coder par couleur" les intensités. Ainsi, des pixels plus lumineux (pixels approchant le blanc) signifient qu'il y a "plus" de cette "couleur" à ces endroits.

Si vous voulez de la couleur, vous devez faire des copies de l'image à 3 canaux et définir les autres canaux pour qu'ils aient des valeurs de 0.

Par exemple, pour afficher un canal rouge comme "rouge":

# Assuming I is numpy array with 3 channels in RGB order
I_red = image.copy()  # Duplicate image
I_red[:, :, 1] = 0    # Zero out contribution from green
I_red[:, :, 2] = 0    # Zero out contribution from blue

Une question connexe de stackoverflow ici .

13
lightalchemist

Donc, vous voulez montrer en différentes couleurs les différents canaux RVB d'une image ...

import matplotlib.pyplot as plt
from matplotlib.cbook import get_sample_data

image = plt.imread(get_sample_data('grace_hopper.jpg'))

titles = ['Grace Hopper', 'Red channel', 'Green channel', 'Blue channel']
cmaps = [None, plt.cm.Reds_r, plt.cm.Greens_r, plt.cm.Blues_r]

fig, axes = plt.subplots(1, 4, figsize=(13,3))
objs = Zip(axes, (image, *image.transpose(2,0,1)), titles, cmaps)

for ax, channel, title, cmap in objs:
    ax.imshow(channel, cmap=cmap)
    ax.set_title(title)
    ax.set_xticks(())
    ax.set_yticks(())

plt.savefig('RGB1.png')

enter image description here Notez que lorsque vous avez une pièce sombre avec un stylo rouge sur une table sombre, si vous allumez une lampe rouge, vous percevez le stylo comme presque blanc ...

Une autre possibilité consiste à créer une image différente pour chaque couleur, avec les valeurs de pixels pour les autres couleurs mises à zéro. Partant de là où nous sommes partis, nous définissons une fonction pour extraire un canal dans une image autrement noire

...
from numpy import array, zeros_like
def channel(image, color):
    if color not in (0, 1, 2): return image
    c = image[..., color]
    z = zeros_like(c)
    return array([(c, z, z), (z, c, z), (z, z, c)][color]).transpose(1,2,0)

et enfin l'utiliser ...

colors = range(-1, 3)
fig, axes = plt.subplots(1, 4, figsize=(13,3))
objs = Zip(axes, titles, colors)
for ax, title, color in objs:
    ax.imshow(channel(image, color))
    ax.set_title(title)
    ax.set_xticks(())
    ax.set_yticks(())

plt.savefig('RGB2.png')

enter image description here Je ne peux pas dire quelle est la version que j'aime mieux, peut-être que la 1ère me semble plus réaliste (peut-être qu'elle ressemble moins artificiel ) mais c'est assez subjectif ...

6
gboffi