I have 1000 of images. Now I like to convert those images into grayscale?
import tensorflow as tf
from tensorflow.keras.utils import img_to_array
#df['image_name'] = df['image_name'].apply(str)
df_image = []
for i in tqdm(range(df.shape[0])):
img = image.load_img('/content/drive/MyDrive/Predict DF from Image of Chemical
Structure/2D image/'+df['image_name'][i]+'.png',target_size=(100,100,3))
img = image.img_to_array(img)
img = img/255
df_image.append(img)
X = np.array(df_image)
Per the TensorFlow documentation for tf.keras.utils.load_img, it accepts the argument color_mode, which is
One of "grayscale", "rgb", "rgba". Default: "rgb". The desired image format.
and it also returns "A PIL Image instance.".
The best way to do this is
img = image.load_img(
'/content/drive/MyDrive/Predict DF from Image of Chemical Structure/2D image/'+df['image_name'][i]+'.png',
target_size=(100,100,3),
color_mode="grayscale"
)
If I'm misinterpreting the documentation, the following should also work (put this after load_img but before img_to_array):
img = img.convert("L") # if you need alpha preserved, "LA"
Since this is a PIL Image instance, it has the .convert method. "L" converts the image to just lightness values
Related
I want to use an old script which uses scipy.misc.imresize.
But unfortunately it is removed entirely from scipy.
I do not understand what it does so what code will perform the same action as the above line.
I tried using skimage.transform.resize(image, (num_px*num_px*3, 1), order = 3)
But get the error - ValueError: cannot reshape array of size 12288 into shape (1200,1)
Edit: More Information
It's classifying pictures as belonging to one of two sets.
my_image = "anyimage.jpg" #any image form the internet
#Preprocessing the image
fname = "images/" + my_image
image = np.array(ndimage.imread(fname, flatten=False))
image = image/255.
my_image = scipy.misc.imresize(image, size=(num_px,num_px)).reshape((1, num_px*num_px*3)).T #The original code which worked perfectly
my_predicted_image = predict(d["w"], d["b"], my_image) #predict function uses
#linear regression where the third parameter must be data of
#size (num_px * num_px * 3, number of examples)
Instead of using the scipy image routines imread() and imresize() which have been deprecated and removed, you can do the same thing using pillow, which you should already have since it is required for the scipy functions to work.
from PIL import Image
import numpy as np
my_image = "anyimage.jpg" #any image form the internet
fname = "images/" + my_image
num_px = 20 # a guess based on the shape of (1200, 1) in your error message
#Preprocessing the image
image = Image.open(fname).resize(size=(num_px, num_px)) # use PIL to open and reshape image
my_image = np.array(image, dtype=float) / 255 # convert to numpy array and scale values
my_image = my_image.reshape((1, num_px*num_px*3)).T # reshape and transpose
my_predicted_image = predict(d["w"], d["b"], my_image) #predict function uses
#linear regression where the third parameter must be data of
#size (num_px * num_px * 3, number of examples)
from PIL import Image
import numpy as np
my_image = "anyimage.jpg" #any image form the internet
fname = "images/" + my_image
#Preprocessing the image
image = Image.open(fname).resize(size=(num_px, num_px)) # use PIL to open and reshape image
my_image = np.array(image, dtype=float) / 255 # convert to numpy array and scale values
my_image = my_image.reshape((1, num_px*num_px*3)).T # reshape and transpose
my_predicted_image = predict(d["w"], d["b"], my_image)
I have an RGB image. I want to convert it to numpy array. I did the following
im = cv.LoadImage("abc.tiff")
a = numpy.asarray(im)
It creates an array with no shape. I assume it is a iplimage object.
You can use newer OpenCV python interface (if I'm not mistaken it is available since OpenCV 2.2). It natively uses numpy arrays:
import cv2
im = cv2.imread("abc.tiff",mode='RGB')
print(type(im))
result:
<type 'numpy.ndarray'>
PIL (Python Imaging Library) and Numpy work well together.
I use the following functions.
from PIL import Image
import numpy as np
def load_image( infilename ) :
img = Image.open( infilename )
img.load()
data = np.asarray( img, dtype="int32" )
return data
def save_image( npdata, outfilename ) :
img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
img.save( outfilename )
The 'Image.fromarray' is a little ugly because I clip incoming data to [0,255], convert to bytes, then create a grayscale image. I mostly work in gray.
An RGB image would be something like:
out_img = Image.fromarray( ycc_uint8, "RGB" )
out_img.save( "ycc.tif" )
You can also use matplotlib for this.
from matplotlib.image import imread
img = imread('abc.tiff')
print(type(img))
output:
<class 'numpy.ndarray'>
As of today, your best bet is to use:
img = cv2.imread(image_path) # reads an image in the BGR format
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR -> RGB
You'll see img will be a numpy array of type:
<class 'numpy.ndarray'>
Late answer, but I've come to prefer the imageio module to the other alternatives
import imageio
im = imageio.imread('abc.tiff')
Similar to cv2.imread(), it produces a numpy array by default, but in RGB form.
You need to use cv.LoadImageM instead of cv.LoadImage:
In [1]: import cv
In [2]: import numpy as np
In [3]: x = cv.LoadImageM('im.tif')
In [4]: im = np.asarray(x)
In [5]: im.shape
Out[5]: (487, 650, 3)
You can get numpy array of rgb image easily by using numpy and Image from PIL
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
im = Image.open('*image_name*') #These two lines
im_arr = np.array(im) #are all you need
plt.imshow(im_arr) #Just to verify that image array has been constructed properly
When using the answer from David Poole I get a SystemError with gray scale PNGs and maybe other files. My solution is:
import numpy as np
from PIL import Image
img = Image.open( filename )
try:
data = np.asarray( img, dtype='uint8' )
except SystemError:
data = np.asarray( img.getdata(), dtype='uint8' )
Actually img.getdata() would work for all files, but it's slower, so I use it only when the other method fails.
load the image by using following syntax:-
from keras.preprocessing import image
X_test=image.load_img('four.png',target_size=(28,28),color_mode="grayscale"); #loading image and then convert it into grayscale and with it's target size
X_test=image.img_to_array(X_test); #convert image into array
OpenCV image format supports the numpy array interface. A helper function can be made to support either grayscale or color images. This means the BGR -> RGB conversion can be conveniently done with a numpy slice, not a full copy of image data.
Note: this is a stride trick, so modifying the output array will also change the OpenCV image data. If you want a copy, use .copy() method on the array!
import numpy as np
def img_as_array(im):
"""OpenCV's native format to a numpy array view"""
w, h, n = im.width, im.height, im.channels
modes = {1: "L", 3: "RGB", 4: "RGBA"}
if n not in modes:
raise Exception('unsupported number of channels: {0}'.format(n))
out = np.asarray(im)
if n != 1:
out = out[:, :, ::-1] # BGR -> RGB conversion
return out
I also adopted imageio, but I found the following machinery useful for pre- and post-processing:
import imageio
import numpy as np
def imload(*a, **k):
i = imageio.imread(*a, **k)
i = i.transpose((1, 0, 2)) # x and y are mixed up for some reason...
i = np.flip(i, 1) # make coordinate system right-handed!!!!!!
return i/255
def imsave(i, url, *a, **k):
# Original order of arguments was counterintuitive. It should
# read verbally "Save the image to the URL" — not "Save to the
# URL the image."
i = np.flip(i, 1)
i = i.transpose((1, 0, 2))
i *= 255
i = i.round()
i = np.maximum(i, 0)
i = np.minimum(i, 255)
i = np.asarray(i, dtype=np.uint8)
imageio.imwrite(url, i, *a, **k)
The rationale is that I am using numpy for image processing, not just image displaying. For this purpose, uint8s are awkward, so I convert to floating point values ranging from 0 to 1.
When saving images, I noticed I had to cut the out-of-range values myself, or else I ended up with a really gray output. (The gray output was the result of imageio compressing the full range, which was outside of [0, 256), to values that were inside the range.)
There were a couple other oddities, too, which I mentioned in the comments.
We can use following function of open CV2 to convert BGR 2 RGB format.
RBG_Image = cv2.cvtColor(Image, cv.COLOR_BGR2RGB)
Using Keras:
from keras.preprocessing import image
img = image.load_img('path_to_image', target_size=(300, 300))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
images = np.vstack([x])
Try timing the options to load an image to numpy array, they are quite similar. Go for plt.imread for simplicity and speed.
def time_this(function, times=100):
cum_time = 0
for t in range(times):
st = time.time()
function()
cum_time += time.time() - st
return cum_time / times
import matplotlib.pyplot as plt
def load_img_matplotlib(img_path):
return plt.imread(img_path)
import cv2
def load_img_cv2(img_path):
return cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)
from PIL import Image
import numpy as np
def load_img_pil(img_path):
img = Image.open(img_path)
img.load()
return np.asarray( img, dtype="int32" )
if __name__=='__main__':
img_path = 'your_image_path'
for load_fn in [load_img_pil, load_img_cv2, load_img_matplotlib]:
print('-'*20)
print(time_this(lambda: load_fn(img_path)), 10000)
Result:
--------------------
0.0065201687812805175 10000 PIL, as in [the second answer][1]https://stackoverflow.com/a/7769424/16083419)
--------------------
0.0053211402893066405 10000 CV2
--------------------
0.005320906639099121 10000 matplotlib
You can try the following method. Here is a link to the docs.
tf.keras.preprocessing.image.img_to_array(img, data_format=None, dtype=None)
from PIL import Image
img_data = np.random.random(size=(100, 100, 3))
img = tf.keras.preprocessing.image.array_to_img(img_data)
array = tf.keras.preprocessing.image.img_to_array(img)
I would like to know, whether I used toPILImage from torchvision correctly. I want to use it, to see how the images look after initial image transformations are applied to the dataset.
When I use it like in the code below, the image that comes up has weird colors like this one. The original image is a regular RGB image.
This is my code:
import os
import torch
from PIL import Image, ImageFont, ImageDraw
import torch.utils.data as data
import torchvision
from torchvision import transforms
import matplotlib.pyplot as plt
# Image transformations
normalize = transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
transform_img = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(256),
transforms.ToTensor(),
normalize ])
train_data = torchvision.datasets.ImageFolder(
root='./train_cl/',
transform=transform_img
)
test_data = torchvision.datasets.ImageFolder(
root='./test_named_cl/',
transform=transform_img
)
train_data_loader = data.DataLoader(train_data,
batch_size=4,
shuffle=True,
num_workers=4) #num_workers=args.nThreads)
test_data_loader = data.DataLoader(test_data,
batch_size=32,
shuffle=False,
num_workers=4)
# Open Image from dataset:
to_pil_image = transforms.ToPILImage()
my_img, _ = train_data[248]
results = to_pil_image(my_img)
results.show()
Edit:
I had to use .data on the Torch Variable to get the tensor.
Also I needed to rescale the numpy array before transposing. I found a working solution here, but it doesn't always work well. How can I do this better?
for i, data in enumerate(train_data_loader, 0):
img, labels = data
img = Variable(img)
break
image = img.data.cpu().numpy()[0]
# This worked for rescaling:
image = (1/(2*2.25)) * image + 0.5
# Both of these didn't work:
# image /= (image.max()/255.0)
# image *= (255.0/image.max())
image = np.transpose(image, (1,2,0))
plt.imshow(image)
plt.show()
You can use PIL image but you're not actually loading the data as you would normally.
Try something like this instead:
import numpy as np
import matplotlib.pyplot as plt
for img,labels in train_data_loader:
# load a batch from train data
break
# this converts it from GPU to CPU and selects first image
img = img.cpu().numpy()[0]
#convert image back to Height,Width,Channels
img = np.transpose(img, (1,2,0))
#show the image
plt.imshow(img)
plt.show()
As an update (02-10-2021):
import torchvision.transforms.functional as F
# load the image (creating a random image as an example)
img_data = torch.ByteTensor(4, 4, 3).random_(0, 255).numpy()
pil_image = F.to_pil_image(img_data)
Alternatively
import torchvision.transforms as transforms
img_data = torch.ByteTensor(4, 4, 3).random_(0, 255).numpy()
pil_image = transforms.ToPILImage()(img_data)
The second form can be integrated with dataset loader in pytorch or called directly as so.
I added a modified to_pil_image here
essentially it does what I suggested back in 2018 but it is integrated into pytorch now.
I would use something like this
# Open Image from dataset:
my_img, _ = train_data[248]
results = transforms.ToPILImage()(my_img)
results.show()
I read an image as follows
image_float = cv2.imread('/data/cat.jpg',cv2.IMREAD_UNCHANGED)
The shape of the read image is (1200, 1600, 3).
When this read array is passed to the following code if image.get_shape().ndims != 3:, an error message will appear AttributeError: numpy.ndarray' object has no attribute get_shape
It seems to me that get_shape() and ndims are expecting a Tensorflow tensor. However, I read image using cv2 as the above. How to transform an image read by cv2 to a tensorflow tensor.
Originally, the image is read as follows
rl = ("https://upload.wikimedia.org/wikipedia/commons/d/d9/"
"First_Student_IC_school_bus_202076.jpg")
image_string = urllib2.urlopen(url).read()
image = tf.image.decode_jpeg(image_string, channels=3)
# Convert image to float32 before subtracting the
# mean pixel value
image_float = tf.to_float(image, name='ToFloat')
Try converting it to a tensor first:
image_cv = cv2.imread('/data/cat.jpg', cv2.IMREAD_UNCHANGED)
image_tensor = tf.convert_to_tensor(image_float, dtype=np.int32)
image_float = tf.to_float(image_tensor, name='ToFloat')
BTW why do you need the IMREAD_UNCHANGED flag if it's a JPEG (with no support of alpha channel)?
You can also just ask TF to load the jpeg from that file:
image = tf.image.decode_jpeg(tf.read_file('/data/cat.jpg'), channels=3)
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")