too many values to unpack (while reading image's shape) - python

I am trying to run this code snippet:
from scipy.stats import wasserstein_distance
from imageio import imread
import numpy as np
def get_histogram(img):
h, w = img.shape
hist = [0.0] * 256
for i in range(h):
for j in range(w):
hist[img[i, j]] += 1
return np.array(hist) / (h * w)
a = imread("./IMG_4835.jpg")
b = imread("./IMG_4836.jpg")
a_hist = get_histogram(a)
b_hist = get_histogram(b)
dist = wasserstein_distance(a_hist, b_hist)
print(dist)
but I get an error at:
h, w = img.shape
b = imread('b.jpg', mode='L')
ValueError: too many values to unpack (expected 2)
The original code used:
from scipy.ndimage import imread
to read the image file but since I was unable to import it, I used imread from another library instead. Could that have anything to do with the error?

h,w = img.shape[:2] should fix the problem.

RGB image has 3 channels, your code works with 2 channels only.
You could convert your images to grey:
from skimage.color import rgb2gray
from skimage import img_as_ubyte
img = img_as_ubyte(rgb2gray(img))
Or if you do not care about correct RGB 2 grey:
(see https://e2eml.school/convert_rgb_to_grayscale.html)
img = np.mean(img, axis=2).astype(np.uint8)
But it looks like you are reinventing a wheel. To get histogram use:
a_hist, _ = np.histogram(a, bins=256)
b_hist, _ = np.histogram(b, bins=256)

Related

How to perform operations on images in python

I am trying to complete a challenge where i use an equation to construct a new image (d) from other images. Then i must get the flag in the image (d). The given images are a.png, b.png c.png and y.png and they can be found here: https://drive.google.com/drive/folders/1bZOm_0apr5ZmaRNf9R5UVIEmtMuYSphn?usp=sharing
The equation: d = y - 21a - 3b + 41c
My current code
from PIL import Image
imagey = Image.open('y.png')
imagea = Image.open('a.png')
imageb = Image.open('b.png')
imagec = Image.open('c.png')
size = width, height = imagey.size
new = Image.new('RGB', size)
imgy = imagey.load()
imga = imagea.load()
imgb = imageb.load()
imgc = imagec.load()
data = new.load()
for x in range(width):
for y in range(height):
they = imgy[x, y]
thea = imga[x, y]
theb = imgb[x, y]
thec = imgc[x, y]
new_color = ((int(they[0])) & ~(int((21 * thea[0])) ^ int((3 * theb[0])) ^ int(~(41 * thec[0]))),
(int(they[1])) & ~(int((21 * thea[1])) ^ int((3 * theb[1])) ^ int(~(41 * thec[1]))),
(int(they[2])) & ~(int((21 * thea[2])) ^ int((3 * theb[2])) ^ int(~(41 * thec[2]))))
data[x, y] = new_color
new.save('final.png')
new.show()
If you would convert Pillow image to numpy array or you would use OpenCV or imageio to load image (and get directly numpy array) then you could do
directly
new = imagey - 21*imagea - 3*imageb + 41*imagec
Result:
Not ideal but much better than with your code.
It can be problem with overflow. It may create array with 8bits values and calculations can gives 16bits or 32bits values which can be reduced to 8bits in every calculation.
Full working code:
import imageio
imagey = imageio.imread('y.png')
imagea = imageio.imread('a.png')
imageb = imageio.imread('b.png')
imagec = imageio.imread('c.png')
new = imagey - 21*imagea - 3*imageb + 41*imagec
imageio.imwrite('final.png', new)
# --- imageio doesn't have function to display it ---
import matplotlib.pyplot as plt
plt.imshow(new)
plt.show()
EDIT:
If I use OpenCV then I get ideal result
Full working code:
import cv2
imagey = cv2.imread('y.png')
imagea = cv2.imread('a.png')
imageb = cv2.imread('b.png')
imagec = cv2.imread('c.png')
new = imagey - 21*imagea - 3*imageb + 41*imagec
cv2.imwrite('final.png', new)
# --- show window with image and wait for press any key ---
cv2.imshow('Image', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT:
By the way: version which converts PIL Image to numpy array and later it converts back to PIL Image - but it gives the same result as imageio.
from PIL import Image
import numpy as np
imagey = Image.open('y.png')
imagea = Image.open('a.png')
imageb = Image.open('b.png')
imagec = Image.open('c.png')
arr_y = np.array(imagey)
arr_a = np.array(imagea)
arr_b = np.array(imageb)
arr_c = np.array(imagec)
arr_new = arr_y - 21*arr_a - 3*arr_b + 41*arr_c
new = Image.fromarray(arr_new)
new.save('final.png')
new.show()
BTW:
If I check images on Linux using program file then it shows that b.png and c.png are JPEG, not PNG.
$ file b.png
b.png: JPEG image data, JFIF standard 1.01, resolution (DPI),
density 300x300, segment length 16,
Exif Standard: [TIFF image data, big-endian, direntries=0], baseline,
precision 8, 960x640, components 3
I found that cv2.imread() gives little different values for c.png(which is JPG file) then other modules - and I don't mean that cv2 gives colors in BGR instead of RGB - and later this gives correct result. Probably cv2 uses different C library to read JPG.

How to convert RGB image pixels to L*a*b*?

Well, I'm working with image processing to identify the color variation of an image and to be able to plot that data in a histogram. For this, I use images of skin spots in the RGB color space. The code below I can get the colors of each pixel and convert to HSV using color.rgb2lab. But as I want to convert to L*a*b*, because it is closer to human vision, in the python library there is no conversion to L*a*b*. With this, through the separated pixels of RGB, how do I transform these pixels into LAB colors?
import numpy as np
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.pyplot as plt
import colorsys
from PIL import Image
# (1) Import the file to be analyzed!
img_file = Image.open("IMD006.png")
img = img_file.load()
# (2) Get image width & height in pixels
[xs, ys] = img_file.size
max_intensity = 100
hues = {}
# (3) Examine each pixel in the image file
for x in xrange(0, xs):
for y in xrange(0, ys):
# (4) Get the RGB color of the pixel
[r, g, b] = img[x, y]
# (5) Normalize pixel color values
r /= 255.0
g /= 255.0
b /= 255.0
# (6) Convert RGB color to HSV
[h, s, v] = colorsys.rgb_to_hsv(r, g, b)
# (7) Marginalize s; count how many pixels have matching (h, v)
if h not in hues:
hues[h] = {}
if v not in hues[h]:
hues[h][v] = 1
else:
if hues[h][v] < max_intensity:
hues[h][v] += 1
You can do it with PIL/Pillow using the built-in Colour Management System and building a transform like this:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image, ImageCms
# Open image and discard alpha channel which makes wheel round rather than square
im = Image.open('colorwheel.png').convert('RGB')
# Convert to Lab colourspace
srgb_p = ImageCms.createProfile("sRGB")
lab_p = ImageCms.createProfile("LAB")
rgb2lab = ImageCms.buildTransformFromOpenProfiles(srgb_p, lab_p, "RGB", "LAB")
Lab = ImageCms.applyTransform(im, rgb2lab)
And Lab is now your image in Lab colourspace. If you carry on and add the following lines to the end of the above code, you can split the Lab image into its constituent channels and save them each as greyscale images for checking.
# Split into constituent channels so we can save 3 separate greyscales
L, a, b = Lab.split()
L.save('L.png')
a.save('a.png')
b.save('b.png')
So, if you start with this image:
you will get this as the L channel:
this as the a channel:
and this the b channel:
Being non-scientific for a moment, the a channel should be negative/low where the image is green and should be high/positive where the image is magenta so it looks correct. And the b channel should be negative/low where the image is blue and high/positive where it is yellow, so that looks pretty good to me! As regards the L channel, the RGB to greyscale formula is (off the top of my head) something like:
L = 0.2*R + 0.7*G + 0.1*B
So you would expect the L channel to be much brighter where the image is green, and darkest where it is blue.
Alternatively, you can do it with the scikit-image module, maybe even more simply like this:
import numpy as np
from skimage import color, io
# Open image and make Numpy arrays 'rgb' and 'Lab'
rgb = io.imread('image.png')
Lab = color.rgb2lab(rgb)
I am not 100% sure of the scaling, but I suspect the L channel is a float in range 0..100, and that a and b are also floats in range -128..+128, though I may be wrong!
With my colour wheel image above I got the following minima/maxima for each channel:
Lab[:,:,0].min() # L min
32.29567256501352
Lab[:,:,0].max() # L max
97.13950703971322
Lab[:,:,1].min() # a min
-86.18302974439501
Lab[:,:,1].max() # a max
98.23305386311316
Lab[:,:,2].min() # b min
-107.85730020669489
Lab[:,:,2].max() # b max
94.47812227647823
from colormath.color_objects import sRGBColor, LabColor
from colormath.color_conversions import convert_color
def rgb_to_cielab(a):
"""
a is a pixel with RGB coloring
"""
a1,a2,a3 = a/255
color1_rgb = sRGBColor(a1, a2, a3);
color1_lab = convert_color(color1_rgb, LabColor);
return color1_lab
rgb_to_cielab(np.array([255,0,255]))
Output: LabColor(lab_l=60.32364943499053,lab_a=98.23532017664644,lab_b=-60.83501679458592)
Using cv2 you can easily implement this conversion. RGB->LAB, LAB->RGB.
import numpy as np
import cv2
img = cv2.imread('1.jpg')
LAB = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
cv2.imwrite('L.png', LAB[:,:,0])
cv2.imwrite('a.png', LAB[:,:,1])
cv2.imwrite('b.png', LAB[:,:,2])
BGR = cv2.cvtColor(LAB, cv2.COLOR_LAB2BGR)
# img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imwrite('new.png', BGR)
I've seen this problem like you 'bout for 3 months and here is my solution for this
import numpy as np
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.pyplot as plt
import colorsys
from PIL import Image
from past.builtins import xrange
img_file = Image.open("F:/coding/Project/FDD/neo5.png")
img = img_file.load()
[xs, ys] = img_file.size
max_intensity = 100
hues = {}
for x in xrange(0, xs):
for y in xrange(0, ys):
[r, g, b] = img[x, y]
r /= 255.0
g /= 255.0
b /= 255.0
[h, s, v] = colorsys.rgb_to_hsv(r, g, b)
if h not in hues:
hues[h] = {}
if v not in hues[h]:
hues[h][v] = 1
else:
if hues[h][v] < max_intensity:
hues[h][v] += 1
h_ = []
v_ = []
i = []
colours = []
for h in hues:
for v in hues[h]:
h_.append(h)
v_.append(v)
i.append(hues[h][v])
[r, g, b] = colorsys.hsv_to_rgb(h, 1, v)
colours.append([r, g, b])
fig = plt.figure()
ax = p3.Axes3D(fig)
ax.scatter(h_, v_, i, s=5, c=colours, lw=0)
ax.set_xlabel('Hue')
ax.set_ylabel('Value')
ax.set_zlabel('Intensity')
fig.add_axes(ax)
plt.show()

histogram equalization for colored image give error using python opencv

Error : Assertion failed (0 < cn && cn <= CV_CN_MAX) in merge
In the merge function
cv2.merge(channels,img2)
if the arguments are replaced as shown:
cv2.merge(img2,channels)
it will not give an error, but the histograms will be the same before and after equalization. What can I do in this piece of code.
Code:
import cv2,cv
import cv2.cv as cv
import numpy as np
from matplotlib import pyplot as plt
capture = cv.CaptureFromCAM(0)
img = cv.QueryFrame(capture)
img_size = cv.GetSize(img)
width,height = img_size
size = width,height,3
channels = np.zeros(size , np.uint8)
while (1):
img = cv.QueryFrame(capture)
img = np.asarray(img[:,:])
cv2.imshow("original",img)
hist = cv2.calcHist([img],[2],None,[256],[0,256])
#convert img to YCR_CB
img2 = cv2.cvtColor(img,cv2.COLOR_BGR2YCR_CB)
#split image to Y, CR, CB
cv2.split(img2,channels)
#histogram equalization to Y-MATRIX
cv2.equalizeHist(channels[0],channels[0])
#merge this matrix to reconstruct our colored image
cv2.merge(channels,img2)
#convert this output image to rgb
rgb = cv2.cvtColor(img2,cv2.COLOR_YCR_CB2BGR)
hist2 = cv2.calcHist([rgb],[2],None,[256],[0,256])
plt.plot(hist)
plt.plot(hist2)
plt.show()
Instead of using split and merge, take advantage of numpy slicing.
img2[:, :, 0] = cv2.equalizeHist(img2[:, :, 0])
# or run a small loop over each channel
you got the split() wrong here. it returns the channels.
since you don't catch the return values, your channels are not initialized
>>> import cv2
>>> help(cv2.split)
Help on built-in function split in module cv2:
split(...)
split(m[, mv]) -> mv
so it should look like:
channels = cv2.split(img2)
and please, avoid the old cv api, instead stick with cv2 consistently. (use cv2.VideoCapture, not cv.CaptureFromCAM)

How can I convert an RGB image into grayscale in Python?

I'm trying to use matplotlib to read in an RGB image and convert it to grayscale.
In matlab I use this:
img = rgb2gray(imread('image.png'));
In the matplotlib tutorial they don't cover it. They just read in the image
import matplotlib.image as mpimg
img = mpimg.imread('image.png')
and then they slice the array, but that's not the same thing as converting RGB to grayscale from what I understand.
lum_img = img[:,:,0]
I find it hard to believe that numpy or matplotlib doesn't have a built-in function to convert from rgb to gray. Isn't this a common operation in image processing?
I wrote a very simple function that works with the image imported using imread in 5 minutes. It's horribly inefficient, but that's why I was hoping for a professional implementation built-in.
Sebastian has improved my function, but I'm still hoping to find the built-in one.
matlab's (NTSC/PAL) implementation:
import numpy as np
def rgb2gray(rgb):
r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
return gray
How about doing it with Pillow:
from PIL import Image
img = Image.open('image.png').convert('L')
img.save('greyscale.png')
If an alpha (transparency) channel is present in the input image and should be preserved, use mode LA:
img = Image.open('image.png').convert('LA')
Using matplotlib and the formula
Y' = 0.2989 R + 0.5870 G + 0.1140 B
you could do:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])
img = mpimg.imread('image.png')
gray = rgb2gray(img)
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()
You can also use scikit-image, which provides some functions to convert an image in ndarray, like rgb2gray.
from skimage import color
from skimage import io
img = color.rgb2gray(io.imread('image.png'))
Notes: The weights used in this conversion are calibrated for contemporary CRT phosphors: Y = 0.2125 R + 0.7154 G + 0.0721 B
Alternatively, you can read image in grayscale by:
from skimage import io
img = io.imread('image.png', as_gray=True)
Three of the suggested methods were tested for speed with 1000 RGBA PNG images (224 x 256 pixels) running with Python 3.5 on Ubuntu 16.04 LTS (Xeon E5 2670 with SSD).
Average run times
pil : 1.037 seconds
scipy: 1.040 seconds
sk : 2.120 seconds
PIL and SciPy gave identical numpy arrays (ranging from 0 to 255). SkImage gives arrays from 0 to 1. In addition the colors are converted slightly different, see the example from the CUB-200 dataset.
SkImage:
PIL :
SciPy :
Original:
Diff :
Code
Performance
run_times = dict(sk=list(), pil=list(), scipy=list())
for t in range(100):
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = skimage.color.rgb2gray(skimage.io.imread(z))
run_times['sk'].append(time.time() - start_time)
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = np.array(Image.open(z).convert('L'))
run_times['pil'].append(time.time() - start_time)
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = scipy.ndimage.imread(z, mode='L')
run_times['scipy'].append(time.time() - start_time)
for k, v in run_times.items():
print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))
Output
z = 'Cardinal_0007_3025810472.jpg'
img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
img2 = np.array(Image.open(z).convert('L'))
IPython.display.display(PIL.Image.fromarray(img2))
img3 = scipy.ndimage.imread(z, mode='L')
IPython.display.display(PIL.Image.fromarray(img3))
Comparison
img_diff = np.ndarray(shape=img1.shape, dtype='float32')
img_diff.fill(128)
img_diff += (img1 - img3)
img_diff -= img_diff.min()
img_diff *= (255/img_diff.max())
IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
Imports
import skimage.color
import skimage.io
import random
import time
from PIL import Image
import numpy as np
import scipy.ndimage
import IPython.display
Versions
skimage.version
0.13.0
scipy.version
0.19.1
np.version
1.13.1
You can always read the image file as grayscale right from the beginning using imread from OpenCV:
img = cv2.imread('messi5.jpg', 0)
Furthermore, in case you want to read the image as RGB, do some processing and then convert to Gray Scale you could use cvtcolor from OpenCV:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
The fastest and current way is to use Pillow, installed via pip install Pillow.
The code is then:
from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')
The tutorial is cheating because it is starting with a greyscale image encoded in RGB, so they are just slicing a single color channel and treating it as greyscale. The basic steps you need to do are to transform from the RGB colorspace to a colorspace that encodes with something approximating the luma/chroma model, such as YUV/YIQ or HSL/HSV, then slice off the luma-like channel and use that as your greyscale image. matplotlib does not appear to provide a mechanism to convert to YUV/YIQ, but it does let you convert to HSV.
Try using matplotlib.colors.rgb_to_hsv(img) then slicing the last value (V) from the array for your grayscale. It's not quite the same as a luma value, but it means you can do it all in matplotlib.
Background:
http://matplotlib.sourceforge.net/api/colors_api.html
http://en.wikipedia.org/wiki/HSL_and_HSV
Alternatively, you could use PIL or the builtin colorsys.rgb_to_yiq() to convert to a colorspace with a true luma value. You could also go all in and roll your own luma-only converter, though that's probably overkill.
Using this formula
Y' = 0.299 R + 0.587 G + 0.114 B
We can do
import imageio
import numpy as np
import matplotlib.pyplot as plt
pic = imageio.imread('(image)')
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114])
gray = gray(pic)
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
However, the GIMP converting color to grayscale image software has three algorithms to do the task.
you could do:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb_to_gray(img):
grayImage = np.zeros(img.shape)
R = np.array(img[:, :, 0])
G = np.array(img[:, :, 1])
B = np.array(img[:, :, 2])
R = (R *.299)
G = (G *.587)
B = (B *.114)
Avg = (R+G+B)
grayImage = img.copy()
for i in range(3):
grayImage[:,:,i] = Avg
return grayImage
image = mpimg.imread("your_image.png")
grayImage = rgb_to_gray(image)
plt.imshow(grayImage)
plt.show()
If you're using NumPy/SciPy already you may as well use:
scipy.ndimage.imread(file_name, mode='L')
Use img.Convert(), supports “L”, “RGB” and “CMYK.” mode
import numpy as np
from PIL import Image
img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')
print np.array(img)
Output:
[[135 123 134 ..., 30 3 14]
[137 130 137 ..., 9 20 13]
[170 177 183 ..., 14 10 250]
...,
[112 99 91 ..., 90 88 80]
[ 95 103 111 ..., 102 85 103]
[112 96 86 ..., 182 148 114]]
With OpenCV its simple:
import cv2
im = cv2.imread("flower.jpg")
# To Grayscale
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite("grayscale.jpg", im)
# To Black & White
im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite("black-white.jpg", im)
I came to this question via Google, searching for a way to convert an already loaded image to grayscale.
Here is a way to do it with SciPy:
import scipy.misc
import scipy.ndimage
# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
img = scipy.misc.face()
# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000
# Show the image
scipy.misc.imshow(img_gray)
When the values in a pixel across all 3 color channels (RGB) are same then that pixel will always be in grayscale format.
One of a simple & intuitive method to convert a RGB image to Grayscale is by taking the mean of all color channels in each pixel and assigning the value back to that pixel.
import numpy as np
from PIL import Image
img=np.array(Image.open('sample.jpg')) #Input - Color image
gray_img=img.copy()
for clr in range(img.shape[2]):
gray_img[:,:,clr]=img.mean(axis=2) #Take mean of all 3 color channels of each pixel and assign it back to that pixel(in copied image)
#plt.imshow(gray_img) #Result - Grayscale image
Input Image:
Output Image:
image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()
You can use greyscale() directly for the transformation.

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