PIL images converted to RGB, getting saved as plain black images (python) - python

I have images that I want to save in jpeg format, after shearing and editing them.
This is my function in python:
import numpy as np
from skimage import data, io, filter, color, exposure
import skimage.transform as tf
from skimage.transform import resize, rescale, rotate, setup, warp, AffineTransform
import os
from os import listdir
from os.path import isfile, join
from PIL import Image
def generateHoGSamples(path, readfile):
print "generating samples from " + path+"\\"+readfile
img = color.rgb2gray(io.imread(path+"\\"+readfile))
img = resize(img, (50,100))
filename = os.path.splitext(readfile)[0]
angles = [3, 0, -3]
shears = [0.13, 0.0, -0.13]
imgidx = 0
for myangle in angles:
myimg = rotate(img, angle=myangle, order=2)
for myshear in shears:
imgidx+=1
afine_tf = tf.AffineTransform(shear=myshear)
mymyimg = tf.warp(myimg, afine_tf)
outputimg = Image.fromarray(mymyimg)
# Saving as "jpg" without the following line caused an error
outputimg = outputimg.convert('RGB')
outputimg.save(path+"//"+str(imgidx)+".jpg", "JPEG")
But what happens instead is that all images are nothing but black.
What's the matter here?

Your image mymyimage goes from 0 to 1 and PIL is expecting an image with values between 0 and 255. During the truncation your jpeg image will have truncated values 0 or 1, resulting in black.
To fix that, just multiply mymyimg by 255, such as
outputimg = Image.fromarray(mymyimg*255)
Hope it helps.
Cheers

Related

Python image library, Select random pictures from files

Hi I need some help with something I'm working on, I have this code that gets 2 pictures from 2 different folders and pastes it over each other creating 1 final merged image, what I want though is to merge two randomly selected pictures from the separate directories, thanks
from PIL import Image
import os
import random
import numpy as np
img1 = Image.open("/Users/Liam/Pictures/1/dfd.jpg").convert("RGBA")
img2 = Image.open("/Users/Liam/Pictures/2/face.png").convert("RGBA")
img1.paste(img2, (0,0), mask = img2)
img1.show()
It is actually pretty easy, check my example below
from PIL import Image
import os
import random
import numpy as np
basedir1 = "/Users/Liam/Pictures/1/"
basedir2 = "/Users/Liam/Pictures/2/"
first_image_list = os.listdir(basedir1)
second_image_list = os.listdir(basedir2)
img1 = Image.open(os.path.join(basedir1, random.choice(first_image_list))).convert("RGBA")
img2 = Image.open(os.path.join(basedir2, random.choice(second_image_list))).convert("RGBA")
img1.paste(img2, (0,0), mask = img2)
img1.show()

Input multiple images in a shape of an array

import os
import cv2
import numpy as np
from google.colab.patches import cv2_imshow
from PIL import Image
train_path_positive = "/content/Dataset_P5/Train/Positive"
positive_patches = []
for filename in os.listdir(train_path_positive):
image = cv2.imread(train_path_positive + "/" +filename,0)
image = cv2.resize(image, (500,500))
print(image.shape)
positive_patches.append(image)
positive_patches_array = np.array(positive_patches)
I have 15 pictures in jpg format
When i try to print the shape, I got (15,) and
I was trying to input those picture and store it on array with the format (15, 500,500)
You need to preallocate a numpy array
# Use your required dtype in below line
positive_patches_array = np.empty((15,500,500), dtype='uint16')
for num, filename in enumerate(os.listdir(train_path_positive)):
image = cv2.imread(train_path_positive + "/" +filename,0)
image = cv2.resize(image, (500,500))
positive_patches_array[num, :, :] = image

Image Reconstruction (Erosion and Dilation) both gives black image as output

I am trying to remove the black spots from a face of this image using the erosion methods.
I have implemented:
img = skimage.io.imread('blemish.jpeg')
img = skimage.color.rgb2gray(img)
img_inten = skimage.exposure.rescale_intensity(img,in_range=(50,100))
diliation_seed = img_inten.copy()
diliation_seed[1:-1,1:-1] = img_inten.min()
mask = img_inten
eroded_img = skimage.morphology.reconstruction(diliation_seed,mask,method='dilation')
matplotlib.pyplot.imshow(eroded_img,cmap='gray')
My output is always a black image in both the cases. What is going wrong here?
rgb2gray is outputting an image as a matrix of floats, with values in [0;1]
So the rescale_intensity is just outputting a matrix of 0, since you ask for values between 50 and 100 and there is none in the gray img.
you can fix it like this :
import skimage
from skimage import data, exposure, img_as_float
from skimage.morphology import reconstruction
import matplotlib.pyplot as plt
img = skimage.io.imread('blemish.jpeg')
gray_img = 255*skimage.color.rgb2gray(img) # multiply by 255 to get back in the [0;255] range
img_inten = exposure.rescale_intensity(gray_img,in_range=(50,100))
diliation_seed = img_inten.copy()
diliation_seed[1:-1,1:-1] = img_inten.min()
mask = img_inten
eroded_img = reconstruction(diliation_seed,mask,method='dilation')
plt.imshow(eroded_img,cmap='gray')
plt.show()

Resize image with skimage library without stretching

Hey i am trying to resize an image without stretching it but adding white pixels instead. I looked arround but i found nothing specifying how that can be achieved from within skimage. So instead i used numpy to add the extra pixels before the resize as arrays of [float(255)].
from skimage.io import imread
from skimage.io import imsave
from skimage.transform import resize
from matplotlib import pyplot as plt
from pylab import cm
import numpy as np
from skimage import morphology
from skimage import measure
from scipy import misc
def process(file_):
im = imread(file_, as_grey=True)
#im = misc.imread(file_)
#im=np.fromfile(file_, dtype=np.int64)
#Filler to avoid stretching
orig_rows, orig_cols = im.shape
print orig_rows, orig_cols
if orig_rows < orig_cols:
for addition in range(0,orig_cols-orig_rows):
#adding white rows
lst = np.array(list(float(255) for x in range(0,orig_cols)))
im= np.vstack((im,lst))
if orig_rows > orig_cols:
for addition in range(0,orig_rows-orig_cols):
#adding white columns
lst = np.array(list([float(255)] for x in range(0,orig_rows)))
im= np.hstack((im,lst))
image = resize(im, (48, 48))
imsave('test.jpg',im)
imsave('test1.jpg',image)
plt.imshow(im, cmap=cm.gray)
plt.show()
When i view the image with pyplot it looks like this
We can see that the columns have been added, but after i save the image with
image = resize(im, (48, 48))
imsave('test.jpg',im)
imsave('test1.jpg',image)
The the images look like negatives, and the resized image looks completely white(next to the dark its invisible on the sites background). Any ideas?
The code below should work. Note that the padded areas' color is not exactly white in order to see the image boundaries in the uploaded image. For white padding set fill_cval = np.max(img).
def resize_padded(img, new_shape, fill_cval=None, order=1):
import numpy as np
from skimage.transform import resize
if fill_cval is None:
fill_cval = np.max(img)
ratio = np.min([n / i for n, i in zip(new_shape, img.shape)])
interm_shape = np.rint([s * ratio for s in img.shape]).astype(np.int)
interm_img = resize(img, interm_shape, order=order, cval=fill_cval)
new_img = np.empty(new_shape, dtype=interm_img.dtype)
new_img.fill(fill_cval)
pad = [(n - s) >> 1 for n, s in zip(new_shape, interm_shape)]
new_img[[slice(p, -p, None) if 0 != p else slice(None, None, None)
for p in pad]] = interm_img
return new_img
import numpy as np
import matplotlib.pylab as plt
from skimage.data import astronaut
from skimage.color import rgb2gray # using luminance
from skimage.io import imsave
img = rgb2gray(astronaut())
# set desired image size
out_size = (30, 100) # height, width
# set the color of the padded area. Here: "95% luminance"
fill_cval = np.max(img) * 0.95
resized_img = resize_padded(img, out_size, fill_cval=fill_cval)
imsave('img.png', img)
imsave('img_res.png', resized_img)

how to convert an RGB image to numpy array?

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)

Categories