I have an image that I have encoded and sent out using protobuf like so:
message.image = numpy.ndarray.tobytes(image)
when I receive and parse that message I use this:
image_array = numpy.frombuffer(request.image, numpy.uint8)
This gives me a one-dimensional array. I cannot get this back into an image format. I have tried using numpy's reshape command like so but with no luck:
image = image_array.reshape( 400, 600, 3 )
The image being sent is 400x600 pixels and it is a 3 channel color image. Any suggestions on what I am missing?
You would also need to store the img.shape data of the original image you wanted to encode and whole decoding you need that img.shape value to reshape the matrix to it's original form as:
import numpy as np
# Create a dummy matrix
img = np.ones((50, 50, 3), dtype=np.uint8) * 255
# Save the shape of original matrix.
img_shape = img.shape
message_image = np.ndarray.tobytes(img)
re_img = np.frombuffer(message_image, dtype=np.uint8)
# Convert back the data to original image shape.
re_img = np.reshape(re_img, img_shape)
Related
I have an image stored in a numpy array that I want to convert to PIL.Image in order to perform an interpolation only available with PIL.
When trying to convert it through Image.fromarray() it raises the following error:
TypeError: Cannot handle this data type
I have read the answers here and here but they do not seem to help in my situation.
What I'm trying to run:
from PIL import Image
x # a numpy array representing an image, shape: (256, 256, 3)
Image.fromarray(x)
tl;dr
Does x contain uint values in [0, 255]? If not and especially if x ranges from 0 to 1, that is the reason for the error.
Explanation
Most image libraries (e.g. matplotlib, opencv, scikit-image) have two ways of representing images:
as uint with values ranging from 0 to 255.
as float with values ranging from 0 to 1.
The latter is more convenient when performing operations between images and thus is more popular in the field of Computer Vision.
However PIL seems to not support it for RGB images.
If you take a look here
it seems that when you try to read an image from an array, if the array has a shape of (height, width, 3) it automatically assumes it's an RGB image and expects it to have a dtype of uint8!
In your case, however, you have an RBG image with float values from 0 to 1.
Solution
You can fix it by converting your image to the format expected by PIL:
im = Image.fromarray((x * 255).astype(np.uint8))
I solved it different way.
Problem Situation:
When working with gray image or binary image, if the numpy array shape is (height, width, 1), this error will be raised also.
For example, a 32 by 32 pixel gray image (value 0 to 255)
np_img = np.random.randint(low=0, high=255, size=(32, 32, 1), dtype=np.uint8)
# np_img.shape == (32, 32, 1)
pil_img = Image.fromarray(np_img)
will raise TypeError: Cannot handle this data type: (1, 1, 1), |u1
Solution:
If the image shape is like (32, 32, 1), reduce dimension into (32, 32)
np_img = np.squeeze(np_img, axis=2) # axis=2 is channel dimension
pil_img = Image.fromarray(np_img)
This time it works!!
Additionally, please make sure the dtype is uint8(for gray) or bool(for binary).
In my case it was only because I forgotted to add the "RGB" arg in the "fromarray" func.
pil_img = Image.fromarray(np_img, 'RGB')
I found a different issue for the same error in my case. The image I used was in RGBA format, so before using fromarray() function just convert it to RGB using the convert() function and it will work perfectly fine.
image_file = Image.open(image_file)
image_file = image_file.convert('RGB')
P.S.: Posting this solution as an initial step, before converting the image to np.
In my case file format of the images was changed to png to jpg. It worked well when I corrected the image format of the error images.
According to the scikit-image's documentation, you can convert an image to unsigned byte format, with values in [0, 255] using img_as_ubyte:
from skimage import img_as_ubyte
from PIL import Image
new_image = Image.fromarray(img_as_ubyte(image))
Using base64 encoding on images gives the opportunity to fully restore the image to its original shape, with all its dimension (2D, RGB) without knowing the resolutions directly - they are stored inside the base64 information
However, when I have a numpy array representing an image like:
test_image = np.random.rand(10,10,3)
and then put it into base64 with:
b64_test_image = base64.b64encode(test_image)
I am able to get back to the content of the array with:
decoded = base64.b64decode(b64_test_image)
test_image_1D = np.frombuffer(decoded)
However, test_image_1D is only one-dimensional in comparison to the orignal image which had the dimension 10x10x3. Is it possible to restore the orignal array without knowing the buffer size, like it is the case with images?
Assuming your data is always an image, you need to use a library to get the image back from the base64 encoded string. For example with OpenCV:
retval, buffer = cv2.imencode('.jpg', test_image)
jpg_as_text = base64.b64encode(buffer)
nparr = np.fromstring(base64.b64decode(jpg_as_text), np.uint8)
img2 = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
I am trying to read a image file using PIL and then obtaining the raw pixel values in form of numpy array and then i am trying to put together the values to form a copy of original image. The code does not produce any runtime error but the image formed ("my.png") is unreadable.
from PIL import Image
import numpy as np
img_filename = "image.png"
img = Image.open(img_filename)
img = img.convert("RGB")
img.show()
aa = np.array(img.getdata())
alpha = Image.fromarray(aa,"RGB")
alpha.save('my.png')
alpha.show()
np.array(img.getdata()) gives a 2D array of shape (X, 3), where X depends on the dimensions of the original image.
Just change the relevant line of code to:
aa = np.array(img)
This will assign a 3D array to aa, and thus solve your problem.
I am trying to customize an existing code to suit my own need. Originally, the code use imgs = np.ndarray((total, 1, image_rows, image_cols), dtype=np.uint8) to store a list of image files in an numpy array format. Iterating the folder, each image file is read as follows img = skimage.io.imread(os.path.join(train_data_path, image_name)) It works just fine.
The code is as follows:
image_rows = 420
image_cols = 580
imgs = np.ndarray((total, 1, image_rows, image_cols), dtype=np.uint8)
i=0
for image_name in images:
img = skimage.io.imread(os.path.join(train_data_path, image_name))
img = np.array([img])
imgs[i]=img
i+=1
In order to suit my own need, I tend to have image file array with the shape [total, image_rows,image_cols,1]. In other words, I modified it as imgs = np.ndarray((total,image_rows, image_cols,1), dtype=np.uint8) However, running the code causes the following error
imgs[i] = img
ValueError: could not broadcast input array from shape (1,420,580) into shape
(420,580,1)
Are there any way to change the shape of img, which originally has shape of [1,420,580] after reading from file. How can I change it to [420,580,1] without affecting the corresponding pixel values in the image.
You want to transpose the dimensions. It can be done using the transpose method:
img = img.transpose(1,2,0)
(for your case)
I load images with numpy/scikit. I know that all images are 200x200 pixels.
When the images are loaded, I notice some have an alpha channel, and therefore have shape (200, 200, 4) instead of (200, 200, 3) which I expect.
Is there a way to delete that last value, discarding the alpha channel and get all images to a nice (200, 200, 3) shape?
Just slice the array to get the first three entries of the last dimension:
image_without_alpha = image[:,:,:3]
scikit-image builtin:
from skimage.color import rgba2rgb
from skimage import data
img_rgba = data.logo()
img_rgb = rgba2rgb(img_rgba)
https://scikit-image.org/docs/dev/user_guide/transforming_image_data.html#conversion-from-rgba-to-rgb-removing-alpha-channel-through-alpha-blending
https://scikit-image.org/docs/dev/api/skimage.color.html#rgba2rgb
Use PIL.Image to remove the alpha channel
from PIL import Image
import numpy as np
img = Image.open("c:\>path_to_image")
img = img.convert("RGB") # remove alpha
image_array = np.asarray(img) # converting image to numpy array
print(image_array.shape)
img.show()
If images are in numpy array to convert the array to Image use Image.fromarray to convert array to Image
pilImage = Image.fromarray(numpy_array)