matlplotlib with opencv gives a different image with the same pixel values - python

I've been trying to modify the pixels of an image slightly, but the colors are getting distorted. So, I multiplied every pixel with 1 and saw the result.
Here's my code
import numpy as np
from matplotlib import pyplot as plt
import cv2
mud1 = cv2.imread('mud.jpeg')
print mud1.shape
mask = np.random.random_integers(1,1,size=(81,81,3))
print mask.shape
print mask[21][21][2]
print mud1[21][21][2]
mud1new = np.multiply(mud1,mask)
print mud1new[21][21][2]
plt.subplot(121),plt.imshow(mud1),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(mud1new),plt.title('Masked')
plt.xticks([]), plt.yticks([])
plt.savefig('problem.jpeg')
plt.show()
The pixels remain unchanged but somehow the image I see is different.

The issue is because np.random.random_integers returns objects that are int64 whereas your loaded image is uint8 so when you multiply the two together, mud1new becomes an int64 array. When using imshow, it expects the following types
MxN – values to be mapped (float or int)
MxNx3 – RGB (float or uint8)
MxNx4 – RGBA (float or uint8)
To fix this, you should cast mud1new as a uint8 prior to display with imshow
mud1new = mud1new.astype(np.unit8)
plt.imshow(mud1new)
You could also convert mud1new to a float but that would require that all of your values should be between 0 and 1 so you'd have to divide everything by 255.
The value for each component of MxNx3 and MxNx4 float arrays should be in the range 0.0 to 1.0.
mud1new_float = mud1new.astype(np.float) / 255.0;
plt.imshow(mud1new_float)

Related

Numpy matshow produces blank image despite dtype is float

I have script that takes 3 same size numpy array, create ndarray using dstack and suppose to display them as rgb image.However, the last part of the RGB image seems to be working but I cannot display the image and all I get is blank image.
This is how I create the image from 3 arrays:
rgb_result=np.dstack((result[3,:,:],result[2,:,:],result[1,:,:]))
plt.figure(figsize=(10,6))
plt.matshow(rgb_result*5,fignum=1,aspect='auto')
plt.title(d)
plt.show()
The result is blank image:
whenever I plot one of the bands that constructs "rgb_result" it works (the three images are very similar to this):
I have also checked the dype of each band and of the ndarray, and it was float64.
My question is how can I make matshow work and show the image in RGB.
matshow uses imshow under the hood, which expects the data to be between 0-1 for floats or 0-255 for ints:
(M, N, 3): an image with RGB values (0-1 float or 0-255 int).
Since rgb_result contains floats, it should be normalized to 0-1 (subtract min and divide by max):
plt.matshow((rgb_result-rgb_result.min())/rgb_result.max(), fignum=1, aspect='auto')
Or if rgb_result is guaranteed to be positive, just divide by max:
plt.matshow(rgb_result/rgb_result.max(), fignum=1, aspect='auto')
With some fake data, this is the pre- and post-normalized output:

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers)

I tried to run the graph cut algorithm for a slice of an MRI after converting it into PNG format. I keep encountering the following problem:
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
This is even after setting vmin and vmax as follows:
plt.imshow(out, vmin=0, vmax=255)
Cast the image to np.uint8 after scaling [0, 255] range will dismiss this warning. It seems like a feature in matplotlib, as discussed in this issue.
plt.imshow((out * 255).astype(np.uint8))
Instead of plt.imshow(out), use plt.imshow(out.astype('uint8')). That's it!
If you want to show it, you can use img/255.
Or
np.array(img,np.int32)
The reason is that if the color intensity is a float, then matplotlib expects it to range from 0 to 1. If an int, then it expects 0 to 255. So you can either force all the numbers to int or scale them all by 1/255.
As the warning is saying, it is clipping the data in between (0,1)....
I tried above methods the warning was gone but my images were having missing pixel values.
So I tried following steps for my numpy array Image (64, 64, 3).
Step 1: Check the min and max values of array by
maxValue = np.amax(Image)
minValue = np.amin(Image)
For my case min values of images were negative and max value positive, but all were in between about (-1, 1.5) so
Step 2: I simply clipped the data before imshow by
Image = np.clip(Image, 0, 1)
plt.imshow(Image)
Note if your pixel values are ranged something like (-84, 317) etc. Then you may use following steps
Image = Image/np.amax(Image)
Image = np.clip(Image, 0, 1)
plt.imshow(Image)
Simply make it within this range [0:1]
if it is between [-1, 1] after calling the amax() and amin() then
img = img / 2 + 0.5
if it is between [0, 250]
img = img / 250
Just use .astype("uint8"), therefore you should have something like:
plt.imshow(image.astype("uint8"))
plt.show(Image) Expect the image range to be between 0 to 1 if image dtypefloat and 0-255 if image dtype int
type image.dtype if it floats then the problem is that it's range -1 to 1, and you need to make the range between 0 and 1, and this is how you do it:
image=(image+1)/2
if 'image.dtype output int then the problem is that values are 0 and 1 and its type is int so convert type to float
np.array(img,np.float32)
or multiple values of image by 255 so values between 0 and 1 become between 0 and 255
img=img*255
ref https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.imshow.html
For Pytorch based grad_cam I was getting similar errors in show_cam_on_image and what worked cleanly was
input_image = Image.open(filename)
img=np.array(input_image.resize((227,227)),np.float32)
img *= (1.0/img.max())
I had a similar problem that was solved through first casting the image to a numpy array.
plt.imshow(image.numpy().astype("uint8"))

How do I display an image in a plot using Python?

I imported matplotlib.pyplot and also NumPy
I wanted to display an image from my desktop to the plot but I get a TypeError.
code :
img = (image) ( here do we need to give the location of the file or the file directly)
imshow(img, extent=[-25,25,-25,25], cmap = cm.bone)
colorbar()
Error: TypeError: Image data can not convert to float
I am using Pycharm as my ide.
You are a bit ambiguous about
here do we need to give the location of the file or the file directly
No you don't. You need to use some imaging library to read an image. img="C:\image.jpg" does not read an image!
For example, to read a 'png' image, you could:
# Copypaste from docs
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
img=mpimg.imread('myimage.png')
# end
# from now on you can use img as an image, but make sure you know what you are doing!
imgplot=plt.imshow(img)
plt.show()
Read more at Image tutorial at matplotlib's doc
Is img a numpy array of the right type?
If you read the image using pillow,etc. and have an Image object you have to get the numpy array from it ( img.getdata() )
X : array_like, shape (n, m) or (n, m, 3) or (n, m, 4)
Display the image in X to current axes. X may be a float array, a
uint8 array or a PIL image. If X is an array, it can have the
following shapes:
MxN – luminance (grayscale, float array only) MxNx3 – RGB (float or
uint8 array) MxNx4 – RGBA (float or uint8 array)
The value for each component of MxNx3 and MxNx4 float arrays should be in the range 0.0 to 1.0;
Either normalize img so it's between 0.0 and 1.0 or convert it to uint8 ( img=np.array(img, dtype=np.uint8) ).

Given a 2D numpy array of real numbers, how to generate an image depicting the intensity of each number?

I have a 2D numpy array and would like to generate an image such that the pixels corresponding to numbers that have a high value (relative to other pixels) are coloured with a more intense colour. For example if the image is in gray scale, and a pixel has value 0.4849 while all the other pixels correspond to values below 0.001 then that pixel would probably be coloured black, or something close to black.
Here is an example image, the array is 28x28 and contains values between 0 and 1.
All I did to plot this image was run the following code:
import matplotlib.pyplot as plt
im = plt.imshow(myArray, cmap='gray')
plt.show()
However, for some reason this only works if the values are between 0 and 1. If they are on some other scale which may include negative numbers, then the image does not make much sense.
You can use different colormaps too, like in the example below (note that I removed the interpolation):
happy_array = np.random.randn(28, 28)
im = plt.imshow(happy_array, cmap='seismic', interpolation='none')
cbar = plt.colorbar(im)
plt.show()
And even gray is going to work:
happy_array = np.random.randn(28, 28)
im = plt.imshow(happy_array, cmap='gray', interpolation='none')
cbar = plt.colorbar(im)
plt.show()
You can normalize the data to the range (0,1) by dividing everything by the maximum value of the array:
normalized = array / np.amax(a)
plt.imshow(normalized)
If the array contains negative values you have two logical choices. Either plot the magnitude:
mag = np.fabs(array)
normalized = mag / np.amax(mag)
plt.imshow(normalized)
or shift the array so that everything is positive:
positive = array + np.amin(array)
normalized = positive / np.amax(positive)
plt.imshow(normalized)

How to plot the equalized histogram of an image with Python?

So this is my code. The variable img is the original image. The variable eq is the equalized image.
from matplotlib.pyplot import imread, imshow, show, subplot, title, get_cmap, hist
from skimage.exposure import equalize_hist
img = imread('images/city.tif')
eq = equalize_hist(img)
subplot(221); imshow(img, cmap=get_cmap('gray')); title('Original')
subplot(222); hist(img.flatten(), 256, range=(0,256)); title('Histogram of origianl')
subplot(223); imshow(eq, cmap=get_cmap('gray')); title('Histogram Equalized')
subplot(224); hist(eq.flatten(), 256, range=(0,256));
show()
Now when I run, the code, I get the histogram of the original just fine. But the histogram of the equalized is incorrect. This is all of my output
What am I doing wrong ?!?!
EDIT: The builtin matlab commands from the answer works fine for the particular image
It looks like it's converting the image from uint8 format (integer values between 0 and 255 inclusive) to a float32 or float64 format (floating point values between 0 and 1 inclusive). Try eq = np.asarray(equalize_hist(img) * 255, dtype='uint8').

Categories

Resources