How to change dimensions of np.array for greyscale images - python

I have the following code to load an image:
img = imread(os.path.join('./Faces/','10.png'))
print(img.shape)
img = np.mean(img, axis=2)
img = img.astype(int)
print(img.shape)
The output of this code is as follows:
(200, 180, 3)
(200, 180)
I understand that I'm averaging out the RGB layers into a greyscale value, but I have my Keras input layer defined with shape (200, 280, 1). Is there a way to have the shape changed to this? Is there even a functional difference between having a matrix of the two shapes as outputted above?

You could use the expand_dims function in numpy (see documentation).
It works as follows in your case:
img = img.astype(int)
print(img.shape)
# Prints (100, 100)
img = np.expand_dims(img, axis=2)
print(img.shape)
# Prints (100, 100, 1)

You shouldn't average out the channels. There's a particular balance between the RGB channels to transform a picture to grayscale, and it's not conveniently 0.33% each. It's that:
((0.3*R) + (0.59*G) + (0.11*B))
Instead of averaging or doing it manually, I suggest that you use:
import cv2
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
Then add a dimension:
img = img[..., np.newaxis]
or
img = np.expand_dims(img, -1)
The functional difference is that obviously, your CNN will not see color if you turn it into grayscale. So it won't be able to use this information to classify.

Related

cv2 resize gives unwanted artifacts

I have a high resolution image with a size of 1024x1024.
I am trying to downscale it to 256x256 with a code below but it gives unwanted artifacts in the top row.
Here is the python code I tried.
img = np.array(Image.open('image.png'))
res = cv2.resize(img, dsize=(256, 256), interpolation=cv2.INTER_AREA)
Lanczos gives the same results below.
img = np.array(Image.open('image.png'))
res = cv2.resize(img, dsize=(256, 256), interpolation=cv2.INTER_LANCZOS4)
How should I remove this artifacts?

I got this shape (1,254,254,1) while expected shape is (1,254,254,3)

Image comes from the front end in PIL I preprocess it but it giving me a different shape than expected.
my code is
def preprocess(img):
img = np.array(img)
resized = cv2.resize(img, (254, 254))
img = tf.keras.preprocessing.image.img_to_array(resized)/255
img = np.array([img])
return img
this is a pil image
<PIL.JpegImagePlugin.JpegImageFile image mode=L size=2144x1805 at
0x229615E2488>
And when I preprocess it, it gives this shape
the shape of the test image is (1, 254, 254, 1)
and when I try the preprocess code outside of my project it works fine.
This means that your Network needs an image not in grayscale colors and you're unconsciously trimming that info. I suggest you to try resized = cv2.resize(img, (254, 254, 3)) instead of resized = cv2.resize(img, (254, 254)). Because otherwise your telling to the resize method implicitly that you want an image on grayscale and you'll miss that last dimension.

make all images' shape the same in python

I wanted to utilize some images using CNN classification.
however, the problem is the image shape is different for example
for i in range(1,len(x_train)):
print(print(x_train_resize[i].shape))
this shows the images' shapes for all the images that i am using this gives output of
None
(100, 100)
None
(100, 100)
None
(100, 100, 3)
None
(100, 100, 4)
as shown above, is there a way to make the shapes of the images that i have all the same as
(100, 100, 1) or (100, 100, 3)
(100, 100) means grayscale image.
(100, 100, 3) means RGB image.
(100, 100, 4) means RGBA image.
If you have numpy grayscale image img_gray with shape (100,100) then you can duplicate layers to create (100, 100, 3) like in RGB
img_rgb = np.dstack((img_gray, img_gray, img_gray))
If you add alpha layer with values 255 then you get (100, 100, 4) like in RGBA
alpha = np.ones((100, 100), dtype='uint8') * 255
img_rgba = np.dstack((img_rgb, alpha))
If you have img_rgba with (100, 100, 4) then you can skip alpha layer to get img_rgb
img_rgb = img_rgba[:,:,:3]
to convert rgb to grayscale you could calculate
img_gray = (img_rgb[:,:,0] + img_rgb[:,:,1] + img_rgb[:,:,2]) // 3
but better is formula GRAY = 0.2126 * R + 0.7152 * G + 0.0722 * B
img_gray = int(0.2126 * img_rgb[:,:,0] + 0.7152 * img_rgb[:,:,1] + 0.0722 * img_rgb[:,:,2])
Wikipedia: Converting colour to greyscale
If you use OpenCV which also use numpy arrays then it has function to convert colors.
gray to RGB
img_rgb = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGB)
gray to RBGA
img_rgba = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGBA)
RGB to RBGA
img_rgba = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2RGBA)
and in other direction
RGB to gray
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
RBGA to gray
img_gray = cv2.cvtColor(img_rgba, cv2.COLOR_RGBA2GRAY)
RGBA to RBG
img_rgb = cv2.cvtColor(img_rgba, cv2.COLOR_RGBA2RGB)
You could also use pillow Image.convert but it needs to
convert numpy array to pillow Image - img = Image.fromarray(array),
convert color - img = img.convert(...),
convert back pillow Image to numpy array - array = np.asarray(img).
Doc: Image.fromarray()
EDIT:
Minimal working example
import numpy as np
img_gray = np.zeros((100, 100), dtype='uint8')
# create image with cross
for y in range(100):
img_gray[y,y] = int(255 * (y/100))
img_gray[y,99-y] = int(255 * (y/100))
print('img_gray.shape:', img_gray.shape) # (100, 100)
img_rgb = np.dstack((img_gray, img_gray, img_gray))
print('img_rgb.shape:', img_rgb.shape) # (100, 100, 3)
alpha = np.ones((100, 100), dtype='uint8') * 255
img_rgba = np.dstack((img_rgb, alpha))
print('img_rgba.shape:', img_rgba.shape)
import matplotlib.pyplot as plt
plt.imshow(img_gray)
plt.show()
plt.imshow(img_rgb)
plt.show()
plt.imshow(img_rgba)
plt.show()
# --- OpenCV ---
import cv2
img_cv2_rgb = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGB)
print('img_cv2_rgb.shape:', img_cv2_rgb.shape)
img_cv2_rgba = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGBA)
print('img_cv2_rgba.shape:', img_cv2_rgba.shape)
img_cv2_rgba2 = cv2.cvtColor(img_cv2_rgb, cv2.COLOR_RGB2RGBA)
print('img_cv2_rgba2.shape:', img_cv2_rgba2.shape)
cv2.imshow('gray', img_gray)
cv2.imshow('rgb', img_cv2_rgb)
cv2.imshow('rgba', img_cv2_rgba)
cv2.waitKey(0)
cv2.destroyAllWindows()

Can't convert black&white image to grayscale in Opencv

I'm new to opencv so don't mind me!
I want to convert an image which is a black and white image to gray scale image and save it by using cv2.imwrite(). The problem is that after I saved it to my local drive and read it back it returned as a 3 channels image. What is the problem here?
Here is my code
import cv2
image = cv2.imread("path/to/image/image01.jpg")
print(image.shape) # return (128, 128, 3)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
print(gray_image.shape) # return (128, 128)
cv2.imwrite("path/to/dir/gray01.jpg", gray_image)
new_gray_img = cv2.imread("path/to/dir/gray01.jpg")
print(new_gray_img.shape) # return (128, 128, 3)
here is the image i want to convert to gray.
cv2.imread loads images with 3 channels by default
You can replace the last two lines of code using:
new_gray_img = cv2.imread("path/to/dir/gray01.jpg",cv2.CV_LOAD_IMAGE_GRAYSCALE)
print(new_gray_img.shape)
Another method is to load image with scipy:
from scipy.ndimage import imread
new_gray_image=imread("path/to/dir/gray01.jpg")
Try to read the image directly in grayscale
cv2.imread("path/to/dir/gray01.jpg", 0)
import cv2
image = cv2.imread("path/to/image/image01.jpg")
print(image.shape) # return (128, 128, 3)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
print(gray_image.shape) # return (128, 128)
cv2.imwrite("path/to/dir/gray01.jpg", gray_image)
# here is the change
new_gray_img = cv2.imread("path/to/dir/gray01.jpg", 0)
print(new_gray_img.shape) # return (128, 128)

Resizing RGB image with cv2 numpy and Python 2.7

I want to resize an RGB image using Python 2.7. I tried using cv2.resize funcion, but it always returns a single channel image:
(Pdb) x = cv2.imread('image.jpg')
(Pdb) x.shape
(50, 50, 3)
(Pdb) x = cv2.resize(x, (40, 40))
(Pdb) x.shape
(40, 40)
I would like the final output of x.shape to be (40, 40, 3).
Is there a more pythonic way to resize the RGB image other than looping through the three channels and resizing each one separately?
Try this code:
import numpy as np
import cv2
image = cv2.imread('image.jpg')
cv2.imshow("Original", image)
"""
The ratio is r. The new image will
have a height of 50 pixels. To determine the ratio of the new
height to the old height, we divide 50 by the old height.
"""
r = 50.0 / image.shape[0]
dim = (int(image.shape[1] * r), 50)
resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)
cv2.imshow("Resized (Height) ", resized)
cv2.waitKey(0)

Categories