What is the difference between scipy.ndimage.imread and matplotlib.pyplot.imread? - python

scipy.ndimage.imread has just been deprecated in scipy, so I switched my code directly to use pyplot - but the result was not the same. I am importing images for a learning algorithm built in keras - I thought it would be a 1to1 change - but it isn't - I was training fine, after the switch my system doesn't train. Is there a python guru out there that can explain what the difference is?
Scipy returns:
img_array : ndarray
The different colour bands/channels are stored in the third dimension, such that a grey-image is MxN, an RGB-image MxNx3 and an
RGBA-image MxNx4.
scipy documentation
Matplotlib returns:
Return value is a numpy.array. For grayscale images, the return array
is MxN. For RGB images, the return value is MxNx3. For RGBA images the
return value is MxNx4.
matplotlib documentation
MWE:
from scipy import ndimage
import_image = (ndimage.imread("img.png").astype(float) -
255.0 / 2) / 255.0
print import_image[0]
import matplotlib.pyplot as plt
import_image = (plt.imread("img.png").astype(float) -
255.0 / 2) / 255.0
print import_image[0]

Here would be a true mcve:
import matplotlib.pyplot as plt
import numpy as np
import scipy.ndimage
im = np.random.rand(20,20)
plt.imsave("img.png",im)
### Scipy
i2 = scipy.ndimage.imread("img.png")
print i2.shape, i2.min(), i2.max(), i2.dtype
# (20L, 20L, 4L) 1 255 uint8
### Matplotlib
i3 = plt.imread("img.png").astype(float)
print i3.shape, i3.min(), i3.max(), i3.dtype
# (20L, 20L, 4L) 0.00392156885937 1.0 float64
As can be seen
scipy.ndimage.imread creates a numpy array of int type ranging from 0..255 while
pyplot.imread creates a numpy array of float type ranging from 0. .. 1..

Related

Convert RGBA image to array in specific range in python

I have an array of values in range of 1500 to 4500.
I managed to convert the data using matplotlib function. The code as follows:
import matplotlib.pyplot as plt
import numpy as np
norm = plt.Normalize(vmin=1500, vmax=4500)
jet = plt.cm.jet
# generate 100x100 with value in range 1500-4500
original = np.random.randInt(1500,4500, (100,100))
# array in shape (100,100)
# convert the array to rgba image
converted = jet(norm(original))
# image in shape (100,100,4)
How to get the original array from converted images?
Some rounding will take place because of the limited amount of colors in the colormap, so a perfect reversal is not possible.
But you can get close by simply inverting the colormap and subsequent normalization.
Starting with some sample data:
import matplotlib as mpl
import numpy as np
rng = np.random.default_rng(seed=0)
data = rng.integers(1500,4500, (3,3))
# array([[4051, 3410, 3033],
# [2309, 2423, 1622],
# [1725, 1549, 2025]], dtype=int64)
Which can be converted to RGBA:
norm = mpl.colors.Normalize(vmin=1500, vmax=4500)
cmap = mpl.colormaps["jet"].copy()
data_rgb = cmap(norm(data))
Converting the colormap to a lookup table, I'll drop the alpha for simplicity since this colormap doesn't use it.
lut = np.zeros((256,) * 3, dtype=np.uint8)
for i in range(cmap.N):
r,g,b,a = cmap(i)
lut[int(r*255), int(g*255), int(b*255)] = i
The lookup table can then be indexed with the RGB expressed as bytes:
data_rgb_byte = (data_rgb*255).astype(np.uint16)
data_inv_norm = lut[
data_rgb_byte[:,:,0],
data_rgb_byte[:,:,1],
data_rgb_byte[:,:,2],
]/255
data_recovered = norm.inverse(data_inv_norm).data
data_recovered
# array([[4052.94117647, 3405.88235294, 3029.41176471],
# [2311.76470588, 2417.64705882, 1617.64705882],
# [1723.52941176, 1547.05882353, 2017.64705882]])
I guess the loss in accuracy relates to the range of initial normalization (4500 - 1500 = 3000) compared to the resolution of the colormap (N=256), so 3000/256 ~= 11.7.

how to convert image to dataset to process machine learning

How to convert a image to datasets or numpy array and to predict by fiting it to clf
import PIL as pillow
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
infilename=input()
im=Image.open(infilename)
imarr=np.array(im)
flatim=imarr.flatten('F')
clf=svm.SVC(gamma=0.0001,C=100)
x,y=im.size
#how to fit the numpy array to clf
clf.fit(flatim[:-1],flatim[:-1])
print("prediction:",clf.predict(flatim[-1]))
plt.imshow(flatim,camp=plt.cm.gray_r,interpolation='nearest')
plt.show()
Anyone please and thanks!!!
there is no other reason of using SVM on a single image except for fun of doing it. Here are the fixes I did. 1) use .convert("L") to convert the image as 2D array grayscale. 2) created a dummy target variable y as randomized 1D array. 3) fix type error displaying the image again (plt.imshow) cmap (instead of camp) and im (instead of flatim)
import PIL as pillow
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
im=Image.open("sample.jpg").convert("L")
imarr=np.array(im)
flatim=imarr.flatten('F')
clf=svm.SVC()
#X,y=im.size
X = imarr
y = np.random.randint(2, size=imarr.shape[0])
clf.fit(X, y)
#how to fit the numpy array to clf
#clf.fit(flatim[:-1],flatim[:-1])
# I HAVE NO IDEA WHAT I"M DOING HERE!
print("prediction:", clf.predict(X[-2:-1]))
plt.imshow(im,cmap=plt.cm.gray_r,interpolation='nearest')
plt.show()
I see a good example in scikit-learn website of using SVM. I guess this is what you are trying to copy. Isn't?

How to generate the same image with the function of imshow() from matplotlib(python) and imshow() in matlab?

For the same matrix, the image generated by the function imshow() from matplotlib and matlab is different. how to change some parameters of imshow() in matplotlib can get same result in matlab
%matlab
img = 255*rand(101);
img(:,1:50)=3;
img(:,52:101)=1;
img(:,51)=2;
trans_img=imtranslate(img,[3*cos(pi/3),3*sin(pi/3)]);
imshow(trans_img)
This is an image generated by matlab
#python
import numpy as np
import matplotlib.pyplot as plt
from mlab.releases import latest_release as mtl #call matlab function
img = 255 * np.random.uniform(0, 1, (101, 101))
img[:, 51:101] = 1
img[:, 0:50] = 3
img[:, 50] = 2
trans_img = mtl.imtranslate(img, [[3*math.cos(math.pi/3),3*math.sin(math.pi/3)]]
i = plt.imshow(trans_img, cmap=plt.cm.gray)
plt.show(i)
This is an image generated by matplotlib
The trans_img matrix is the same in both cases, but the images in matlab and python are different
Unfortunately I don't have an up-to-date enough version of Matlab that has the imtranslate function, but thankfully the image package in Octave does, which I'm sure is equivalent. Equally, I will be using the oct2py module instead of mlab as a result, for python to access the imtranslate function from octave within python.
Octave code:
img = 255*rand(101);
img(:,1:50)=3;
img(:,52:101)=1;
img(:,51)=2;
trans_img = imtranslate(img, 3*cos(pi/3),3*sin(pi/3));
imshow(trans_img, [min(trans_img(:)), max(trans_img(:))])
Python code:
import numpy as np
import matplotlib.pyplot as plt
import math
from oct2py import octave
octave.pkg('load','image'); # load image pkg for access to 'imtranslate'
img = 255 * np.random.uniform(0, 1, (101, 101))
img[:, 51:101] = 1
img[:, 0:50] = 3
img[:, 50] = 2
trans_img = octave.imtranslate(img, 3*math.cos(math.pi/3), 3*math.sin(math.pi/3))
i = plt.imshow(trans_img, cmap=plt.cm.gray)
plt.show(i)
Resulting image (identical) in both cases:
My only comment on why you may have been seeing the discrepancy, is that I did specify the min and max values in imshow, to ensure appropriate intensity scaling. Equally you could have just used imagesc(trans_img) instead (I actually prefer this). I didn't specify such limits explicitly in python for plt.imshow ... perhaps it performs scaling by default.
Also, your code has a small bug; in the octave version of imtranslate at least, the function takes 3 arguments, not two. (Also, your original code has an unbalanced bracket).

Histogram equalization of grayscale images with NumPy

How to do histogram equalization for multiple grayscaled images stored in a NumPy array easily?
I have the 96x96 pixel NumPy data in this 4D format:
(1800, 1, 96,96)
Moose's comment which points to this blog entry does the job quite nicely.
For completeness, I give an example here using nicer variable names and a looped execution on 1000 96x96 images which are in a 4D array as in the question. It is fast (1-2 seconds on my computer) and only needs NumPy.
import numpy as np
def image_histogram_equalization(image, number_bins=256):
# from http://www.janeriksolem.net/histogram-equalization-with-python-and.html
# get image histogram
image_histogram, bins = np.histogram(image.flatten(), number_bins, density=True)
cdf = image_histogram.cumsum() # cumulative distribution function
cdf = (number_bins-1) * cdf / cdf[-1] # normalize
# use linear interpolation of cdf to find new pixel values
image_equalized = np.interp(image.flatten(), bins[:-1], cdf)
return image_equalized.reshape(image.shape), cdf
if __name__ == '__main__':
# generate some test data with shape 1000, 1, 96, 96
data = np.random.rand(1000, 1, 96, 96)
# loop over them
data_equalized = np.zeros(data.shape)
for i in range(data.shape[0]):
image = data[i, 0, :, :]
data_equalized[i, 0, :, :] = image_histogram_equalization(image)[0]
Very fast and easy way is to use the cumulative distribution function provided by the skimage module. Basically what you do mathematically to proof it.
from skimage import exposure
import numpy as np
def histogram_equalize(img):
img = rgb2gray(img)
img_cdf, bin_centers = exposure.cumulative_distribution(img)
return np.interp(img, bin_centers, img_cdf)
As of today janeriksolem's url is broken.
I found however this gist that links the same page and claims to perform histogram equalization without computing the histogram.
The code is:
img_eq = np.sort(img.ravel()).searchsorted(img)
Here's an alternate implementation for a single channel image that is fast. See skimage.exposure.histogram for reference. Using timeit, 'image_histogram_equalization' in Trilarion's answer has a mean execution time was 0.3696 seconds, while this function has a mean execution time of 0.0534 seconds. However this implementation also relies on skimage.
import numpy as np
from skimage import exposure
def hist_eq(image):
hist, bins = exposure.histogram(image, nbins=256, normalize=False)
# append any remaining 0 values to the histogram
hist = np.hstack((hist, np.zeros((255 - bins[-1]))))
cdf = 255*(hist/hist.sum()).cumsum()
equalized = cdf[image].astype(np.uint8)
return equalized

What is the equivalent of imagesc in OpenCV

What would be the equivalent of imagesc in OpenCV?
To get the nice colors in imagesc you have to play around with OpenCV a little bit. In OpenCV 2.46 there ss a colormap option.
This is code I use in c++. Im sure its very similar in Python.
mydata.convertTo(display, CV_8UC1, 255.0 / 10000.0, 0);
applyColorMap(display, display, cv::COLORMAP_JET);
imshow("imagesc",display);
The image data or matrix data is stored in mydata. I know that it has a maximum value of 10000 so I scale it down to 1 and then multiply by the range of CV_8UC1 which is 255. If you dont know what the range is the best option is to first convert your matrix in the same way as Matlab does it.
EDIT
Here is a version which automatically normalizes your data.
float Amin = *min_element(mydata.begin<float>(), mydata.end<float>());
float Amax = *max_element(mydata.begin<float>(), mydata.end<float>());
Mat A_scaled = (mydata - Amin)/(Amax - Amin);
A_scaled.convertTo(display, CV_8UC1, 255.0, 0);
applyColorMap(display, display, cv::COLORMAP_JET);
imshow("imagesc",display);
It's close to imshow in matlab.
It depends on modules you use in python:
import cv2
import cv2.cv as cv
I_cv2 = cv2.imread("image.jpg")
I_cv = cv.LoadImage("image.jpg")
#I_cv2 is numpy.ndarray norm can be done easily
I_cv2_norm = (I_cv2-I_cv2.min())/(I_cv2.max()-I_cv2.min())
cv2.imshow("cv2Im scaled", I_cv2_norm)
#Here you have to normalize your cv iplimage as explain by twerdster to norm
cv.ShowImage("cvIm unscaled",I_cv)
The best way I think to be close to imagesc, is to use cv2.imread which load image as numpy.ndarray and next use imshow function from matplotlib.pyplot module:
import cv2
from matplolib.pyplot import imshow, show
I = cv2.imread("path")
#signature:
imshow(I, cmap=None, norm=None, aspect=None, interpolation=None,
alpha=None, vmin=None, vmax=None, origin=None, extent=None,
**kwargs)
Here you can choose whatever you want if normalized or your clims (scale)...

Categories

Resources