I've tried to resize image with scipy and everything seems to work fine until I try to save the image. When I try to save image I get error that you can see in title. Full traceback is available below.
import numpy as np
import scipy.misc
from PIL import Image
image_path = "img0.jpg"
def load_image(img_path):
img = Image.open(img_path)
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)
array_image = load_image(image_path)
array_resized_image = scipy.misc.imresize(array_image, (320, 240), interp='nearest', mode=None)
save_image(array_resized_image, "i1.jpg")
Full traceback of the error:
Traceback (most recent call last):
File "D:/Python/Playground/resize image with scipy.py", line 26, in <module>
save_image(array_resized_image, "i1.jpg")
File "D:/Python/Playground/resize image with scipy.py", line 16, in save_image
img = Image.fromarray(np.asarray(np.clip(npdata, 0, 255), dtype="uint8"), "L")
File "C:\Anaconda2\lib\site-packages\PIL\Image.py", line 2154, in fromarray
raise ValueError("Too many dimensions: %d > %d." % (ndim, ndmax))
ValueError: Too many dimensions: 3 > 2.
don't you need to convert it to a two dimensional array before doing the fromarray(... 'L')?
You can do that using a scipy function or, actually quicker, to multiply the RGB by factors. Like this
npdata = (npdata[:,:,:3] * [0.2989, 0.5870, 0.1140]).sum(axis=2)
array_resized_image has a shape of (320, 240, 3) - three dimensional because red, green and blue components are stored in this way. You can use scipy.misc.imread and scipy.misc.imsave for easier handling file loading and storing, so your example boils down to this:
import scipy.misc
image_path = "img0.jpg"
array_image = scipy.misc.imread(image_path)
array_resized_image = scipy.misc.imresize(array_image, (320, 240), interp='nearest', mode=None)
scipy.misc.imsave("i1.jpg", array_resized_image)
Related
I've been playing around with PIL to get a hang of it and wanted to split up an image into its rgb channels, put it together again and show it.
import PIL.Image as Img
import numpy as np
img = Img.new('RGB', (10,10), color = 'cyan')
r,g,b = img.split()
pixels = np.array([np.asarray(r),np.asarray(g),np.asarray(b)])
new_img = Img.fromarray(pixels.astype(np.uint8))
new_img.show()
when I run the file it returns an Error:
File "C:\Program Files (x86)\Python38-32\lib\site-packages\PIL\Image.py", line 2716, in fromarray
raise TypeError("Cannot handle this data type: %s, %s" % typekey)
TypeError: Cannot handle this data type: (1, 1, 10), |u1
I've also tried it like this:
import PIL.Image as Img
import numpy as np
img = Img.new('RGB', (10,10), color = 'cyan')
r,g,b = img.split()
pixels = [np.asarray(r),np.asarray(g),np.asarray(b)]
new_img = Img.fromarray(pixels)
new_img.show()
Where I got this error:
File "C:\Program Files (x86)\Python38-32\lib\site-packages\PIL\Image.py", line 2704, in fromarray
arr = obj.__array_interface__
AttributeError: 'list' object has no attribute '__array_interface__'
So how do I have to put the r, g and b arrays back together correctly?
RGB image is made by stacking 3 colored channels one over the other on the z-axis. See this image for analogy,
pixels = np.array([np.asarray(r),np.asarray(g),np.asarray(b)])
This command places those 3 colored channels side by side, you can check shape using
print(pixels.shape)
(3, 10, 10)
This makes no sense to the interpreter thus the error message.
Each pixel in an RBG image is a tuple of red, green and blue color values.
thus shape take the form rows x cols x channels. You can achieve this by using np.stack
pixels = np.stack([np.asarray(r),np.asarray(g),np.asarray(b)], axis = 2)
I'm trying to apply a flood_fill method to a certain image. Unfortunately, even though it works on an exemplary image, it doesn't work on mine, which is already binarized.
The code that works:
from skimage import data, filters
from skimage.segmentation import flood, flood_fill
import cv2 as cv
cameraman = data.camera()
flooded = flood_fill(cameraman, (200, 100), 255, tolerance=10)
cv.imshow("aaa",flooded)
cv.waitKey()
And the code that does not:
from skimage import data, filters
from skimage.segmentation import flood, flood_fill
import cv2 as cv
import numpy as np
img = cv.imread("Tubka_binar.png")
flooded = flood_fill(img, (200, 100), 100, tolerance = 10)
cv.imshow("aaa",flooded)
cv.waitKey()
And the errors I get:
Traceback (most recent call last):
File "C:/Users/User/Documents/PW/MAGISTERSKIE/__PRACA/Python/Grubość Tuby.py", line 8, in <module>
flooded = flood_fill(img, (200, 100), 100, tolerance = 10)
File "C:\Users\User\Desktop\PROJEKT_PYTHONOWY\venv\lib\site-packages\skimage\morphology\_flood_fill.py", line 104, in flood_fill
tolerance=tolerance)
File "C:\Users\User\Desktop\PROJEKT_PYTHONOWY\venv\lib\site-packages\skimage\morphology\_flood_fill.py", line 235, in flood
working_image.shape, order=order)
File "<__array_function__ internals>", line 6, in ravel_multi_index
ValueError: parameter multi_index must be a sequence of length 3
Process finished with exit code 1
The image variables in both cases seem to be the same type. The image that I read in the second case is a binarized photo, that takes only two values: 0 and 255.
What is causing this?
Best regards
It looks to me like your second image is not actually grayscale but rather saved (or loaded) as a 3-channel RGB image. If you print img.shape, I bet it’ll be something like (512, 512, 3). You can fix this by changing your reading code to:
img = cv.imread("Tubka_binar.png")[..., 0]
I've been working on building a machine learning algorithm to recognize images, starting by creating my own h5 database. I've been following this tutorial, and it's been useful, but I keep running into one major error - when using OpenCV in the image processing section of the code, the program is unable to save the processed image because it keeps flipping the height and width of my images. When I try to compile, I get the following error:
Traceback (most recent call last):
File "array+and+label+data.py", line 79, in <module>
hdf5_file["train_img"][i, ...] = img[None]
File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper
File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper
File "/Users/USER/miniconda2/lib/python2.7/site-packages/h5py/_hl/dataset.py", line 631, in __setitem__
for fspace in selection.broadcast(mshape):
File "/Users/USER/miniconda2/lib/python2.7/site-packages/h5py/_hl/selections.py", line 299, in broadcast
raise TypeError("Can't broadcast %s -> %s" % (target_shape, count))
TypeError: Can't broadcast (1, 240, 320, 3) -> (1, 320, 240, 3)
My images are supposed to all be sized to 320 by 240, but you can see that this is being flipped somehow. Researching around has shown me that this is because OpenCV and NumPy use different conventions for height and width, but I'm not sure how to reconcile this issue within this code without patching my installation of OpenCV. Any ideas on how I can fix this? I'm a relative newbie to Python and all its libraries (though I know Java well)!
Thank you in advance!
Edit: adding more code for context, which is very similar to what's in the tutorial under the "Load images and save them" code example.
The size of my arrays:
train_shape = (len(train_addrs), 320, 240, 3)
val_shape = (len(val_addrs), 320, 240, 3)
test_shape = (len(test_addrs), 320, 240, 3)
The code that loops over the image addresses and resizes them:
# Loop over training image addresses
for i in range(len(train_addrs)):
# print how many images are saved every 1000 images
if i % 1000 == 0 and i > 1:
print ('Train data: {}/{}'.format(i, len(train_addrs)))
# read an image and resize to (320, 240)
# cv2 load images as BGR, convert it to RGB
addr = train_addrs[i]
img = cv2.imread(addr)
img = cv2.resize(img, (320, 240), interpolation=cv2.INTER_CUBIC)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# save the image and calculate the mean so far
hdf5_file["train_img"][i, ...] = img[None]
mean += img / float(len(train_labels))
Researching around has shown me that this is because OpenCV and NumPy use different conventions for height and width
Not exactly. The only thing that is tricky about images is 2D arrays/matrices are indexed with (row, col) which is opposite from normal Cartesian coordinates (x, y) that we might use for images. Because of this, sometimes when you specify points in OpenCV functions, it wants them in (x, y) coordinates---and similarly, it wants the dimensions of the image to be specified in (w, h) instead of (h, w) like an array would be made. And this is the case inside OpenCV's resize() function. You're passing it in (h, w) but it actually wants (w, h). From the docs for resize():
dsize – output image size; if it equals zero, it is computed as:
dsize = Size(round(fx*src.cols), round(fy*src.rows))
Either dsize or both fx and fy must be non-zero.
So you can see here that the number of columns is the first dimension (the width) and the number of rows is the second (the height).
The simple fix is just to swap your (h, w) to (w, h) inside the resize() function:
img = cv2.resize(img, (240, 320), interpolation=cv2.INTER_CUBIC)
I'm trying to take my HSV values and make an image out of it. Here is my code:
from __future__ import division
from PIL import Image
import numpy as np
import colorsys
fp = open('pixels.txt', 'w')
fp2 = open('hsv.txt', 'w')
im = Image.open('colorimage.png')
imrgb = im.convert("RGB")
scale = 255.0
pixels = list(imrgb.getdata())
width, height = im.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]
for pixel in pixels:
for x in pixel:
print>>fp, x
x = [x[0]/255,x[1]/255,x[2]/255]
y = colorsys.rgb_to_hsv(*x)
w = [y[0]*360, y[1]*100, y[2]*100]
h,s,v = [y[0]*360, y[1]*100, y[2]*100]
print>>fp2, w
newimg = Image.new("HSV", im.size)
print "done"
The Image.new says it takes modes: http://pillow.readthedocs.io/en/4.0.x/handbook/concepts.html#concept-modes
But it doesn't read "HSV" as a mode. It says this as the error:
Traceback (most recent call last):
File "RGBtoHIS.py", line 25, in <module>
newimg = Image.new("HSV", im.size)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL-1.1.7-py2.7-macosx-10.6-x86_64.egg/PIL/Image.py", line 1763, in new
return Image()._new(core.fill(mode, size, color))
ValueError: unrecognized mode
Has anyone else had this issue with the Image module?
Other:
I would like to create a Hue image and a Saturation image. Is there a way to do this with the hue and saturation values I have?
You're referencing the Pillow docs, but you're not using Pillow -- you're using the original PIL version 1.1.7, as shown by your error message:
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/
site-packages/PIL-1.1.7-py2.7-macosx-10.6-x86_64.egg/PIL/Image.py", line 1763, in new
and according to its documentation, it doesn't support HSV as a mode (see here).
Uninstall PIL, install Pillow, and then you should be able to do
In [12]: PIL.__version__
Out[12]: '3.4.2'
In [13]: Image.new("HSV", (100,100))
Out[13]: <PIL.Image.Image image mode=HSV size=100x100 at 0x7F4FA00F4F60>
I want to use ssim to compare similarity in 2 images.
I'm getting this error window_shape is incompatible with arr_in.shape .
Why? (What does it mean?)
from skimage.measure import structural_similarity as ssim
from skimage import io
img1 = io.imread('http://pasteio.com/m85cc2eed18c661bf8a0ea7e43779e742')
img2 = io.imread('http://pasteio.com/m1d45b9c70afdb576f1e3b33d342bf7d0')
ssim( img1, img2 )
Traceback (most recent call last): File "", line 1, in
File
"/var/www/wt/local/lib/python2.7/site-packages/skimage/measure/_structural_similarity.py",
line 58, in structural_similarity
XW = view_as_windows(X, (win_size, win_size)) File "/var/www/wt/local/lib/python2.7/site-packages/skimage/util/shape.py",
line 221, in view_as_windows
raise ValueError("window_shape is incompatible with arr_in.shape") ValueError: window_shape is incompatible with
arr_in.shape
I get the same error even when I feed it the same file twice ssim(img1,img1)
You need to make sure your images are the same size to compare them with scikit's ssim:
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.ndimage import imread
import numpy as np
# resized image sizes
height = 2**10
width = 2**10
a = imread('a.jpg', flatten=True).astype(np.uint8)
b = imread('b.jpg', flatten=True).astype(np.uint8)
a = resize(a, (height, width))
b = resize(b, (height, width))
sim, diff = compare_ssim(a, b, full=True)