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:
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:
Ma question est simple. Que se passe-t-il ici?
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)
@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 .
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')
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')
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 ...