Colour intensity is changing when stacking numpy image arrays - python

I am loading an image from here, which is saved as .nii.gz. The image opens fine (with a dimension of (497x497)), and when displayed using matplotlib, it shows with correct intensities, as shown below:
When we are trying to make it a 3 channel image, by stacking the numpy array, and after plotting it, the intensity changes, as shown below:
Any idea how to resolve this? The minimal code to reproduce the problem in google colaboratory is present here:
import cv2
import glob
import numpy as np
import nibabel as nib
import skimage.io as io
from nibabel import nifti1
import matplotlib.pyplot as plt
! wget "https://github.com/Jimut123/simply_junk/blob/main/image.nii.gz?raw=true" -O image.nii.gz
image_file_name = "image.nii.gz"
print(image_file_name)
epi_img = nib.load(image_file_name)
epi_img_data = epi_img.get_fdata()
epi_img_data = epi_img_data/epi_img_data.max()
# epi_img_data = epi_img_data[..., np.newaxis]
plt.imshow(epi_img_data)
plt.show()
total_mask = np.stack((epi_img_data,)*3, axis=-1)
plt.imshow(total_mask,cmap='gray')
plt.show()
Like for example this is a 3-channel image (RGB):
But this looks exactly like it's grayscale version. For the above image, when stacking numpy arrays, I cannot make the image look similar to the grayscale one.

If you scale it as Cristolph and Johan described, the 3-channel plot becomes identical:
epi_img_data -= epi_img_data.min()
epi_img_data /= epi_img_data.max()
total_mask = np.stack((epi_img_data,)*3, axis=-1)
plt.imshow(total_mask)

Related

PIL show Image only RGB Values (Image from PlanetScope Planet Product)

I have this image (which was taken from Planet Lab's PlanetScope product (not sure if that matters)). The image file is a .tif file and has 4 channels: R, G, B, and NIR. Link to original image here: https://drive.google.com/open?id=1g9tZar41tU3E_y5oev1Gy77hGiKB1q7L
I'm just trying to do something basic where I am trying to load the image into Pillow using Python and using Matplotlib to show the image. But, I think what's happening is that the fourth channel is being assumed to be an alpha channel so the images look a bit weird. I want to only visualize the R, G, B components. How do I do this?
I currently have something like this:
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
img = Image.open(image_file)
plt.imshow(img)
# Subsetting the array
img_arr = np.array(img)
# Plotting only the first 3 channels
plt.imshow(img_arr[:, :, 0:3])
# After asking PIL to drop NIR Channel
img_rgb = Image.open(image_files).convert('RGB')
plt.imshow(img_rgb)
In both cases, the images look like it's not really plotting RGB
EDIT: I did img = Image.open(image_file).convert('RGB') and the image looks roughly the same?

Array to image with colour map

I have some data in a 2048x2048 array that I want to convert to an image.
import numpy as np
from PIL import Image
path = 'E:\\petra_2018_backup\\final\\raw\data\zn_2_run\\'
file = 'Zn_2_Pos1-01537.tif'
im = Image.open(path+file)
a = np.array(im)
img = Image.frombytes('CMYK', (2048, 2048), a) # pass in the bytestring
img.save('pic.pdf')
img.show()
This result is quite dark and also has a mixture of green and blue colours. I should mention that the attached picture is a screendump of the result as the result picture is to large to attach.
It would also be usefull if people can advice on a way to compress the resulting image.
I simply could not find a solution using pillow. So I started using scikit.
Code as follows:
import numpy as np
from skimage import io
import matplotlib.pyplot as plt
path = 'E:\\petra_2018_backup\\final\\raw\data\zn_2_run\\'
file = 'Zn_2_Pos1-01537.tif'
im =io.imread(path+file,as_gray=True)
b = np.array([im],dtype=np.uint16 )
b[b<150]=150 #Modification to array not included in original code
b[b>6000]=6000 #Modification to array not included in original code
c=b.squeeze()
fig = plt.figure()
ax = plt.subplot(111)
ax = io.imshow(c)
fig.savefig('result_figure.png',dpi=320)
It produces the following plot.

How to properly plot the image converted to an array via img_to_array

I would like to know how to properly plot the image converted into array via keras.preprocessing.image.img_to_array.
Here is my naive approach. To give you minimum example, I download a duck picture from online:
import urllib.request
f = open('duck.jpg','wb')
f.write(requests.get('http://i.imgur.com/Ph4Xw.jpg').content)
f.close()
When I try to plot this before converting the img into numpy array, it works:
from keras.preprocessing.image import load_img ,img_to_array
import matplotlib.pyplot as plt
img = load_img('duck.jpg')
plt.imshow(img)
plt.show()
The resulting plot looks like this:
However, after I convert the image into array via numpy array via keras.preprocessing.image.img_to_array, the plotting the array object does not look right:
arr_img = img_to_array(img)
plt.imshow(arr_img)
plt.savefig("duck2.jpg")
The resulting plot looks like this:
Is there a way to correctly plot arr_img?
I found that all I had to do was devided arr_img by 255.
arr_img = img_to_array(img)
plt.imshow(arr_img/255)
plt.savefig("duck2.jpg")

Convert Image ( png ) To Matrix And Then To 1D Array

I have 5 pictures and i want to convert each image to 1d array and put it in a matrix as vector. I want to be able to convert each vector to image again.
img = Image.open('orig.png').convert('RGBA')
a = np.array(img)
I'm not familiar with all the features of numpy and wondered if there other tools I can use.
Thanks.
import numpy as np
from PIL import Image
img = Image.open('orig.png').convert('RGBA')
arr = np.array(img)
# record the original shape
shape = arr.shape
# make a 1-dimensional view of arr
flat_arr = arr.ravel()
# convert it to a matrix
vector = np.matrix(flat_arr)
# do something to the vector
vector[:,::10] = 128
# reform a numpy array of the original shape
arr2 = np.asarray(vector).reshape(shape)
# make a PIL image
img2 = Image.fromarray(arr2, 'RGBA')
img2.show()
import matplotlib.pyplot as plt
img = plt.imread('orig.png')
rows,cols,colors = img.shape # gives dimensions for RGB array
img_size = rows*cols*colors
img_1D_vector = img.reshape(img_size)
# you can recover the orginal image with:
img2 = img_1D_vector.reshape(rows,cols,colors)
Note that img.shape returns a tuple, and multiple assignment to rows,cols,colors as above lets us compute the number of elements needed to convert to and from a 1D vector.
You can show img and img2 to see they are the same with:
plt.imshow(img) # followed by
plt.show() # to show the first image, then
plt.imshow(img2) # followed by
plt.show() # to show you the second image.
Keep in mind in the python terminal you have to close the plt.show() window to come back to the terminal to show the next image.
For me it makes sense and only relies on matplotlib.pyplot. It also works for jpg and tif images, etc. The png I tried it on has float32 dtype and the jpg and tif I tried it on have uint8 dtype (dtype = data type); each seems to work.
I hope this is helpful.
I used to convert 2D to 1D image-array using this code:
import numpy as np
from scipy import misc
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
face = misc.imread('face1.jpg');
f=misc.face(gray=True)
[width1,height1]=[f.shape[0],f.shape[1]]
f2=f.reshape(width1*height1);
but I don't know yet how to change it back to 2D later in code, Also note that not all the imported libraries are necessary, I hope it helps

How to convert a NumPy array to PIL image applying matplotlib colormap

I have a simple problem, but I cannot find a good solution to it.
I want to take a NumPy 2D array which represents a grayscale image, and convert it to an RGB PIL image while applying some of the matplotlib colormaps.
I can get a reasonable PNG output by using the pyplot.figure.figimage command:
dpi = 100.0
w, h = myarray.shape[1]/dpi, myarray.shape[0]/dpi
fig = plt.figure(figsize=(w,h), dpi=dpi)
fig.figimage(sub, cmap=cm.gist_earth)
plt.savefig('out.png')
Although I could adapt this to get what I want (probably using StringIO do get the PIL image), I wonder if there is not a simpler way to do that, since it seems to be a very natural problem of image visualization. Let's say, something like this:
colored_PIL_image = magic_function(array, cmap)
Quite a busy one-liner, but here it is:
First ensure your NumPy array, myarray, is normalised with the max value at 1.0.
Apply the colormap directly to myarray.
Rescale to the 0-255 range.
Convert to integers, using np.uint8().
Use Image.fromarray().
And you're done:
from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))
with plt.savefig():
with im.save():
input = numpy_image
np.uint8 -> converts to integers
convert('RGB') -> converts to RGB
Image.fromarray -> returns an image object
from PIL import Image
import numpy as np
PIL_image = Image.fromarray(np.uint8(numpy_image)).convert('RGB')
PIL_image = Image.fromarray(numpy_image.astype('uint8'), 'RGB')
The method described in the accepted answer didn't work for me even after applying changes mentioned in its comments. But the below simple code worked:
import matplotlib.pyplot as plt
plt.imsave(filename, np_array, cmap='Greys')
np_array could be either a 2D array with values from 0..1 floats o2 0..255 uint8, and in that case it needs cmap. For 3D arrays, cmap will be ignored.

Categories