I am trying to slice an image into RGB and I have a problem with plotting these images. I obtain all images from a certain folder with this function:
def get_im
I think matplotlib is just treating each channel (i.e., intensities) as a "heat map".
Pass a color map to the imshow function like so to tell it how you want it to color your image:
plt.imshow(image_slice, cmap=plt.cm.gray)
@mrGreenBrown in response to your comment, I'm assuming that the misc.imread
function you used is from scipy, i.e., scipy.misc.imread
. That function is no different from that of PIL
. See scipy.misc.imread docs. Thanks to @dai for pointing this out.
A single channel of any image is just intensities. It does not have color. For an image expressed in RGB color space, color is obtained by "mixing" amounts (given by the respective channel's intensities) of red, green, and blue. A single channel cannot express color.
What happened was Matplotlib by default displays the intensities as a heatmap, hence the "color".
When you save a single channel as an image in a format say JPEG, the function merely duplicates the single channel 3 times so that the R, G, and B channels all contain the same intensities. This is the typical behavior unless you save it in a format such as PGM which can handle single channel grayscale image. When you try to visualize this image which has the same channel duplicated 3 times, because the contributions from red, green, and blue are the same at each pixel, the image appears as grey.
Passing plt.cm.gray
to the cmap
argument simply tells imshow
not to "color-code" the intensities. So, brighter pixels (pixels approaching white) means there is "more" of that "color" at those locations.
If you want color, you have to make copies of the 3 channel image and set the other channels to have values of 0
.
For e.g., to display a red channel as "red":
# 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
A related question from stackoverflow here.
So, you want to show in different colors the different RGB channels of an 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')
Note that when you have a dark room with a red pen on a dark table, if you turn on a red lamp you percept the pen as almost white...
Another possibility is to create a different image for each color, with the pixel values for the other colors turned to zero. Starting from where we left we define a function to extract a channel into an otherwise black image
...
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)
and finally use it...
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')
I can't tell which is the version that I like better, perhaps the 1st one is looking more realistic to me (maybe it looks less artificial) but it's quite subjective...