How to convert RGB PIL image to numpy array with 3 channels? - python

I am loading image with the following code
image = PIL.Image.open(file_path)
image = np.array(image)
It works, but the size of array appears to be (X, X, 4), i.e. it has 4 layers. I would like normal RGB layers. Is it possible?
UPDATE
I found that just removing 4th channel is unsufficcient. The following code was required:
image = PIL.Image.open(file_path)
image.thumbnail(resample_size)
image = image.convert("RGB")
image = np.asarray(image, dtype=np.float32) / 255
image = image[:, :, :3]
Why?

The fourth layer is the transparency value for image formats that support transparency, like PNG. If you remove the 4th value it'll be a correct RGB image without transparency.
EDIT:
Example:
>>> import PIL.Image
>>> image = PIL.Image.open('../test.png')
>>> import numpy as np
>>> image = np.array(image)
>>> image.shape
(381, 538, 4)
>>> image[...,:3].shape
(381, 538, 3)

As mentioned by other answers, some images are saved with a 4th channel.
To load image with just RGB channels without using numpy at all:
from PIL import Image
image = Image.open('../test.png').convert('RGB')

Related

Reshaping png image read by skimage.imread return ValueError

It works fine using a 616x346 png image as input in the following code:
from skimage import io
image = io.imread('img.png')
image = image.reshape(image.shape[0] * image.shape[1], 3)
...but if I change the image dimensions to say 640x451, I get the error
ValueError: cannot reshape array of size 1154560 into shape (288640,3)
Any thouhts?
The shape of 640x451 image you are trying to reshape is (640, 451, 4) instead of (640, 451, 3). That's why you won't be able to convert it to (640*451, 3). Have a look at the output of image.shape in both the 616x346 and 640x451 cases. One workaround is to convert it to rgb from rgba first -
from skimage import io, color
image = io.imread('img.png')
image = color.rgba2rgb(image)
image = image.reshape(image.shape[0] * image.shape[1], 3)

Converting Color Images to Grayscale but shape of the image stays identical

I've converted some images from RGB to Grayscale for ML purpose.
However the shape of the converted grayscale image is still 3, the same as the color image.
The code for the Conversion:
from PIL import Image
img = Image.open('path/to/color/image')
imgGray = img.convert('L')
imgGray.save('path/to/grayscale/image')
The code to check the shape of the images:
import cv2
im_color = cv2.imread('path/to/color/image')
print(im_color.shape)
im_gray2 = cv2.imread('path/to/grayscale/image')
print(im_gray2.shape)
You did
im_gray2 = cv2.imread('path/to/grayscale/image')
OpenCV does not inspect colorness of image - it does assume image is color and desired output is BGR 8-bit format. You need to inform OpenCV you want output to be grayscale (2D intensity array) as follows
im_gray2 = cv2.imread('path/to/grayscale/image', cv2.IMREAD_GRAYSCALE)
If you want to know more about reading images read OpenCV: Getting Started with Images
cv.imread, without any flags, will always convert any image content to BGR, 8 bits per channel.
If you want any image file, grayscale or color, to be read as grayscale, you can pass the cv.IMREAD_GRAYSCALE flag.
If you want to read the file as it really is, then you need to use cv.IMREAD_UNCHANGED.
im_color = cv2.imread('path/to/color/image', cv2.IMREAD_UNCHANGED)
print(im_color.shape)
im_gray2 = cv2.imread('path/to/grayscale/image', cv2.IMREAD_UNCHANGED)
print(im_gray2.shape)

Python | cv2.imshow() loading arrays as BGR?

I have recorded some data as npy file. And I tried to diplay the image (data[0]) to check if it makes sense with the following code
import numpy as np
import cv2
train_data = np.load('c:/data/train_data.npy')
for data in train_data:
output = data[1]
# only take the height, width and channels of the 4 dimensional array
image = data[0][0, :, :, :]
# image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2.imshow('test', image)
print('output {}'.format(output))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
But if I display the images without the line image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) the images seem to be BGR based. If I comment this line into the code the images are displayed correctly.
My question: Does this observation imply that the image array is already in BGR format? Or does this imply that cv2.imshow() does by
default interprete the array as BGR array?
Matplotlib and Numpy read images into RGB and processes them as RGB. OpenCV reads images into BGR and processes them as BGR. Either system recognizes a range of input types, has ways to convert between color spaces of almost any type, and offers support of a variety of image processing tasks.
This gives three different ways to load an image (plt.imread(), ndimage.imread() and cv2.imread()), two systems for processing the data (Numpy and CV2), and two ways to display the image (plt.imshow() and cv2.imshow()), and really, there is a third way to display the image using pyplot, if you want to treat the image as numerical data in 2-d plus another dimension for each color.
Here is some simple code to demonstrate some of this.
#!/usr/bin/python
import matplotlib.pyplot as plt
from scipy.ndimage import imread
import numpy as np
import cv2
img = imread('index.jpg')
print( "img data type: %s shape %s"%( type(img), str( img.shape) ) )
plt.imshow( img )
plt.title( 'pyplot as read' )
plt.savefig( 'index.plt.raw.jpg' )
cv2.imshow('cv2, read by numpy', img)
cv2.imwrite('index.cv2.raw.jpg',img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow('after conversion', img)
cv2.imwrite('index.cv2.bgr2rgb.jpg',img)
This generates the following line of text, and the following three example image files.
img data type: <type 'numpy.ndarray'> shape (225, 225, 3)
The correct image has red as the upper circle. We read the image into a numpy array, using ndimage.imread(), and show it with Pyplot's imshow() and get the correct image. We then show it with cv2.imshow() and we see that the red channel is interpreted as the blue channel and vice versa. Then we convert the colorspace and we see that cv2.imshow() now interprets the result correctly.
plt.imshow(), as read by ndimage():
cv2.imshow(), the image as read by ndimage:
cv2.imshow(), after converting from RGB to BGR:

Discarding alpha channel from images stored as Numpy arrays

I load images with numpy/scikit. I know that all images are 200x200 pixels.
When the images are loaded, I notice some have an alpha channel, and therefore have shape (200, 200, 4) instead of (200, 200, 3) which I expect.
Is there a way to delete that last value, discarding the alpha channel and get all images to a nice (200, 200, 3) shape?
Just slice the array to get the first three entries of the last dimension:
image_without_alpha = image[:,:,:3]
scikit-image builtin:
from skimage.color import rgba2rgb
from skimage import data
img_rgba = data.logo()
img_rgb = rgba2rgb(img_rgba)
https://scikit-image.org/docs/dev/user_guide/transforming_image_data.html#conversion-from-rgba-to-rgb-removing-alpha-channel-through-alpha-blending
https://scikit-image.org/docs/dev/api/skimage.color.html#rgba2rgb
Use PIL.Image to remove the alpha channel
from PIL import Image
import numpy as np
img = Image.open("c:\>path_to_image")
img = img.convert("RGB") # remove alpha
image_array = np.asarray(img) # converting image to numpy array
print(image_array.shape)
img.show()
If images are in numpy array to convert the array to Image use Image.fromarray to convert array to Image
pilImage = Image.fromarray(numpy_array)

How to create a white image in Python?

Upon doing my homework, I stumbled across a problem concerning Python and image manipulation. I must say, using the Image lib is not an option. So here it is
from scipy.misc import imread,imsave
from numpy import zeros
imga = zeros([100,100,3])
h = len(imga)
w = len(imga[0])
for y in range(h):
for x in range(w):
imga[y,x] = [255,255,255]
imsave("Result.jpg",imga)
I would assume it makes my picture white, but it turns it black, and I have no idea why
It's not about the code (and I know it looks very ugly). Its just about the fact, that it is a black image.
Every color in an image is represented by one byte. So to create an image array, you should set it's dtype to uint8.
And, you don't need for-loop to set every elements to 255, you can use fill() method or slice index:
import numpy as np
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # or img[:] = 255
Easy!
Check the below Code:
whiteFrame = 255 * np.ones((1000,1000,3), np.uint8)
255 is the color for filling the bytes.
1000, 1000 is the size of the image.
3 is the color channel for the image.
And unit8 is the type
Goodluck
Here's a simple way to create a white image with a python one liner.
$ python3 -c "from PIL import Image;Image.new('RGB', (1900, 1080), color = (255,255,255)).save('Img.jpg')"
This will create a white image with a width of 1900 and hight of 1080.
When creating imga, you need to set the unit type. Specifically, change the following line of code:
imga = zeros([100,100,3], dtype=np.uint8)
And, add the following to your imports:
import numpy as np
That gives a white image on my machine.
The headline is too broad and shows up at Google first. I needed a white image and used PIL and numpy. PILlow actually works well with numpy
import numpy as np
from PIL import Image
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # numpy array!
im = Image.fromarray(img) #convert numpy array to image
im.save('whh.jpg')
Just regarding the headline of this question, I did need a white image as well as a pillow input. And the solutions presented here did not work for me.
Therefore here a different way to generate white images for other purposes:
from PIL import Image
img = Image.new('RGB', (200, 50), color = (255,255,255))
Size and color may be changed in the 2nd and 3rd parameter of the Image.new()-function.
And if you want to write something on this image or save it, this would be example code for this.
from PIL import ImageFont, ImageDraw
fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 30)
ImageDraw.Draw(img).text((0,0), "hello world", font=fnt, fill=(0,0,0))
img.save('test.jpg')
# Create an array with a required colours
# The colours are given in BGR [B, G, R]
# The array is created with values of ones, the size is (H, W, Channels)
# The format of the array is uint8
# This array needs to be converted to an image of type uint8
selectedColor = [75, 19, 77] * np.ones((640, 480, 3), np.uint8)
imgSelectedColor = np.uint8(np.absolute(selectedColor))

Categories