How to load an image and show the image using keras? - python

%matplotlib inline
from keras.preprocessing import image
import matplotlib.pyplot as plt
import numpy as np
img = np.random.rand(224,224,3)
plt.imshow(img)
plt.show()
img_path = "image.jpeg"
img = image.load_img(img_path, target_size=(224, 224))
print(type(img))
x = image.img_to_array(img)
print(type(x))
print(x.shape)
plt.imshow(x)
I have some code like this which should print the image. But it shows the image in wrong channels. What am i missing here?

This is a image scaling issue. The input to the imshow() expects it to be in the 0-1 range, while you are passing it a [0-255] range input. Try to view it as:
plt.imshow(x/255.)

This question is kind of old, but there is a very comfortable way to
display images:
tf.keras.preprocessing.image.array_to_img(image[0]).show()
Your image has to have 3 dimensions (if its in a batch as normally, just take desired_element). Works fine on EagerTensors or numpy arrays.

Related

Turn a image to grayscale in python

I'm a newbie to tensorflow and keras, and I'm trying to create a CNN model for The Street View House Numbers (SVHN) dataset. The dataset contains color images, and I want to turn them in grayscale. I found some code on the web that claims they're turning image to grayscale, but it just changes colors.
People are reading the second image with a gray colormap. Is there any way to actually turn this image to grayscale?
(I do not know how to process an image in this kind of programming languages. If this is a dumb question, please forgive me and provide a brief explain.)
I provided images and code below, I'll be grateful for any help.
Code:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
#Read picture:
picture = plt.imread('google.jpg')
print("google logo's shape is: ",picture.shape) #(500, 500, 3)
#saving picture as an np array:
pic_array = np.array(picture)
#Turning image to grayscale
grayscale_pic = np.expand_dims(np.dot(pic_array[...,:3],[0.299, 0.587, 0.144]),axis = 0)
#Dimensions shifted, (probly my mistake):
grayscale_pic = np.moveaxis(grayscale_pic, 0, -1)
print("shape of grayscale pic = ", grayscale_pic.shape) # (500, 500, 1)
plt.imshow(picture) #Figure_1
plt.show()
plt.imshow(grayscale_pic) #Figure_2
plt.show()
U can convert a normal image to grayscale using opencv like this:
import cv2
gray = cv2.cvtColor(picture,cv2.COLOR_RGB2GRAY)
If u prefer numpy over opencv, then u can use this:
gray = np.dot(picture[...,:3], [0.2989, 0.5870, 0.1140])
You can use matplotlib with weights:
import numpy as np
import matplotlib.pyplot as plt
an_image = plt.imread('google.png')
rgb_weights = [0.2989, 0.5870, 0.1140]
grayscale_image = np.dot(an_image[..., :3], rgb_weights)
plt.axis('off')
plt.imshow(grayscale_image, cmap=plt.get_cmap("gray"), aspect='auto')
plt.show()
Output:
If you remove aspect='auto' parameter:
or you can use opencv
import cv2
an_image = cv2.imread("google.png")
grey_image = cv2.cvtColor(an_image, cv2.COLOR_BGR2GRAY)
or you can use PIL library
from PIL import Image
img = Image.open('google.png').convert('LA')
LA mode is L (8-bit pixels, black and white) with ALPHA desinged for .gif and .png. If your images are .jpeg use L.
Output:
There can be several ways to do this. One potential way is to utilize PIL(Pillow) library:
from PIL import Image
import matplotlib.pyplot as plt
picture = Image.open('google.jpg')
grayscale_pic = picture.convert('LA')
grayscale_pic.save('grayscale.png')
fig,ax = plt.subplots(nrows=1, ncols=2)
plt.subplot(1,2,1)
plt.imshow(picture)
plt.subplot(1,2,2)
plt.imshow(grayscale_pic)
plt.show()
Output:

inverse reshaping giving different results

I need to resize and then reshape certain image. Then I want to apply the inverse reshaping which should give the original picture, but it is not working. Let us have this code:
images=[]
image = imread('1.png')
resized = np.resize(image, (320, 440))
images.append(resized)
arr=np.asarray(images)
newArray=arr.astype('float32')
plt.figure(figsize=[5, 5])
reshaped = np.reshape(newArray[0], (320,440))
plt.imshow(reshaped, cmap='gray')
plt.show()
Original picture 1.png:
Reshaped picture shown by plt.show():
Inverse reshaped image is not like the original, can someone tell me where is the problem? Thanks.
Edit:
After clarification, it looks like the confusion comes from np.resize, which is not an image processing operation, and is not used for rescaling an image while retaining content.
It looks as though image processing wrappers such as imresize have been removed from the scipy library, and while you can in principle use the scipy.interpolate package to reproduce the functionality of imresize, I recommend either using pillow, or scikit-image
with pillow:
import numpy as np
from PIL import Image
image = Image.open("my_image.jpg")
image = image.resize((224, 224))
image = np.asarray(image) # convert to numpy
with sckit-image:
from skimage.transform import resize
image = imread("my_image.jpg")
image = resize(image, (224, 224))
original answer
np.reshape will first ravel the elements, then sort them into the new shape specified, losing a lot of spatial relationships, as you're seeing. Likely, what you actually want to do is np.transpose the image, swapping two axes:
images=[]
image = imread('1.png')
resized = np.resize(image, (320, 440))
images.append(resized)
arr=np.asarray(images)
newArray=arr.astype('float32')
plt.figure(figsize=[5, 5])
transposed = np.transpose(newArray[0])
plt.imshow(transposed, cmap='gray')
plt.show()

How to convert a RGB image (3 channel) to grayscale (1 channel) and save it?

Working with a deep learning project and I have a lot of images, that don't need to have colors. I saved them doing:
import matplotlib.pyplot as plt
plt.imsave('image.png', image, format='png', cmap='gray')
However later when I checked the shape of the image the result is:
import cv2
img_rgb = cv2.imread('image.png')
print(img_rgb.shape)
(196,256,3)
So even though the image I view is in grayscale, I still have 3 color channels. I realized I had to do some algebric operations in order to convert those 3 channels into 1 single channel.
I have tried the methods described on the thread "How can I convert an RGB image into grayscale in Python?" but I'm confused.
For example, when to do the conversion using:
from skimage import color
from skimage import io
img_gray = color.rgb2gray(io.imread('image.png'))
plt.imsave('image_gray.png', img_gray, format='png')
However when I load the new image and check its shape:
img_gr = cv2.imread('image_gray.png')
print(img_gr.shape)
(196,256,3)
I tried the other methods on that thread but the results are the same. My goal is to have images with a (196,256,1) shape, given how much less computationally intensive it will be for a Convolutional Neural Network.
Any help would be appreciated.
Your first code block:
import matplotlib.pyplot as plt
plt.imsave('image.png', image, format='png', cmap='gray')
This is saving the image as RGB, because cmap='gray' is ignored when supplying RGB data to imsave (see pyplot docs).
You can convert your data into grayscale by taking the average of the three bands, either using color.rgb2gray as you have, or I tend to use numpy:
import numpy as np
from matplotlib import pyplot as plt
import cv2
img_rgb = np.random.rand(196,256,3)
print('RGB image shape:', img_rgb.shape)
img_gray = np.mean(img_rgb, axis=2)
print('Grayscale image shape:', img_gray.shape)
Output:
RGB image shape: (196, 256, 3)
Grayscale image shape: (196, 256)
img_gray is now the correct shape, however if you save it using plt.imsave, it will still write three bands, with R == G == B for each pixel. This is because, I believe, a PNG file requires three (or four) bands. Warning: I am not sure about this: I expect to be corrected.
plt.imsave('image_gray.png', img_gray, format='png')
new_img = cv2.imread('image_gray.png')
print('Loaded image shape:', new_img.shape)
Output:
Loaded image shape: (196, 256, 3)
One way to avoid this is to save the images as numpy files, or indeed to save a batch of images as numpy files:
np.save('np_image.npy', img_gray)
new_np = np.load('np_image.npy')
print('new_np shape:', new_np.shape)
Output:
new_np shape: (196, 256)
The other thing you could do is save the grayscale png (using imsave) but then only read in the first band:
finalimg = cv2.imread('image_gray.png',0)
print('finalimg image shape:', finalimg.shape)
Output:
finalimg image shape: (196, 256)
As it turns out, Keras, the deep-learning library I'm using has its own method of converting images to a single color channel (grayscale) in its image pre-processing step.
When using the ImageDataGenerator class the flow_from_directory method takes the color_mode argument. Setting color_mode = "grayscale" will automatically convert the PNG into a single color channel!
https://keras.io/preprocessing/image/#imagedatagenerator-methods
Hope this helps someone in the future.
if you want to just add extra channels that have the same value as the graysacale , maybe to use a specific model that requires 3 channel input_shape .
lets say your pictures are 28 X 28 and so you have a shape of (28 , 28 , 1)
def add_extra_channels_to_pic(pic):
if pic.shape == (28 , 28 , 1):
pic = pic.reshape(28,28)
pic = np.array([pic , pic , pic])
# to make the channel axis in the end
pic = np.moveaxis(pic , 0 , -1)
return pic
Try this method
import imageio
new_data = imageio.imread("file_path", as_gray =True)
imageio.imsave("file_path", new_data)
The optional argument "as_gray = True" in line 2 of the code does the actual conversion.

Trouble with Canny Edge Detector - Returning black image

I'm trying to run the canny edge detector on this image:
With this code:
def edges(img):
from skimage import feature
img = Image.open(img)
img.convert('L')
array = np.array(img)
out = feature.canny(array, sigma=1, )
return Image.fromarray(out,'L')
edges('Q_3.jpg').save('Q_3_edges.jpg')
But I'm just getting a black image back. Any ideas what I could be doing wrong? I tried sigma of 1 and of 3.
I have the same situation and this helps for me. Before use the Canny filter, just convert your elements of image array to float32 type:
array = np.array(img)
array = array.astype('float32')
out = feature.canny(array, sigma=1, )
Your images need to be in the correct range for the relevant dtype, as discussed in the user manual here: http://scikit-image.org/docs/stable/user_guide/data_types.html
This should be automatically handled if you use the scikit-image image I/O functions:
from skimage import io
img = io.imread('Q_3.jpg')
So the issue was with the canny function returning and array of type boolean.
Oddly, setting the Image.fromarray mode to '1' didn't help. Instead this was the only way I could get it working; converting the output array to grayscale:
def edges(img):
from skimage import feature
img = Image.open(img)
img.convert('L')
array = np.array(img)
out = np.uint8(feature.canny(array, sigma=1, ) * 255)
return Image.fromarray(out,mode='L')
The problem happens when the image is loaded as float (i.e. in the range 0-1). The loader does that for some types of images. You can check the type of the loaded image by:
print(img.dtype)
If the output is something like float64 (i.e. not uint8), then your image is in the range 0-1.
Canny expects an image in the range 0-255. Therefore, the solution is as easy as:
from skimage import img_as_ubyte
img = io.imread("an_image.jpg")
img = img_as_ubyte(img)
Hope this helps,
The problem happens when the image is saved. You can save image with other library like matplotlib:
import numpy as np
import matplotlib.pyplot as plt
from skimage import feature
from skimage import io
def edges(img):
img = io.imread(img)
array = np.array(img)
out = feature.canny(array, sigma=1, )
return out
plt.imsave("canny.jpg", edges("input.jpg"), cmap="Greys")

how to save an array as a grayscale image with matplotlib/numpy?

I am trying to save a numpy array of dimensions 128x128 pixels into a grayscale image.
I simply thought that the pyplot.imsave function would do the job but it's not, it somehow converts my array into an RGB image.
I tried to force the colormap to Gray during conversion but eventhough the saved image appears in grayscale, it still has a 128x128x4 dimension.
Here is a code sample I wrote to show the behaviour :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mplimg
from matplotlib import cm
x_tot = 10e-3
nx = 128
x = np.arange(-x_tot/2, x_tot/2, x_tot/nx)
[X, Y] = np.meshgrid(x,x)
R = np.sqrt(X**2 + Y**2)
diam = 5e-3
I = np.exp(-2*(2*R/diam)**4)
plt.figure()
plt.imshow(I, extent = [-x_tot/2, x_tot/2, -x_tot/2, x_tot/2])
print I.shape
plt.imsave('image.png', I)
I2 = plt.imread('image.png')
print I2.shape
mplimg.imsave('image2.png',np.uint8(I), cmap = cm.gray)
testImg = plt.imread('image2.png')
print testImg.shape
In both cases the results of the "print" function are (128,128,4).
Can anyone explain why the imsave function is creating those dimensions eventhough my input array is of a luminance type?
And of course, does anyone have a solution to save the array into a standard grayscale format?
Thanks!
With PIL it should work like this
from PIL import Image
I8 = (((I - I.min()) / (I.max() - I.min())) * 255.9).astype(np.uint8)
img = Image.fromarray(I8)
img.save("file.png")
There is also an alternative of using imageio. It provides an easy and convenient API and it is bundled with Anaconda. It can save grayscale images as a single color channel file.
Quoting the documentation
>>> import imageio
>>> im = imageio.imread('imageio:astronaut.png')
>>> im.shape # im is a numpy array
(512, 512, 3)
>>> imageio.imwrite('astronaut-gray.jpg', im[:, :, 0])
I didn't want to use PIL in my code and as noted in the question I ran into the same problem with pyplot, where even in grayscale, the file is saved in MxNx3 matrix.
Since the actual image on disk wasn't important to me, I ended up writing the matrix as is and reading it back "as-is" using numpy's save and load methods:
np.save("filename", image_matrix)
And:
np.load("filename.npy")
There is also a possibility to use scikit-image, then there is no need to convert numpy array into a PIL object.
from skimage import io
io.imsave('output.tiff', I.astype(np.uint16))

Categories

Resources