A multipage tiff can be saved to a file using PIL: im.save(filepath, save_all=True). My question is how to convert a list of numpy arrays to the im object recognised by PIL. im = PIL.Image.fromarray() doesn't accept a list.
This functionality was just added to Pillow v.4.1.0.dev0
https://github.com/python-pillow/Pillow/pull/2406
There are also some other solutions with other libs. E.g. with tifffile How to create a multiple frame image using Python PIL
Related
I cannot find a way to save my graphs and images. I have tried from
from PIL import Image
im = Image.fromarray()
im.save("your_file.jpeg")
but doesn't work!
Please format your code correctly, it is important for readability and python is intend-sensitive. Also, there is already a post for this problem:
How can I save an image with PIL?
I have created a JPEG using Python OpenCV, EXIF data being lost in the process and apparently not being able to be re-added when calling imwrite (reference: Can't keep image exif data when editing it with opencv in python).
Two questions:
In general, how can I write the original EXIF data/new custom metadata into a JPEG that exists in memory rather than a file?
Would pillow/PIL be able to maintain the EXIF data and allow supplementary metadata to be added? As of 2013 (reference: how maintain exif data of images resizes using PIL) this did not seem possible except via a tmp file (which is not an option for me).
Thanks as ever
I'm not certain I understand what you are trying to do, but I think you are trying to process an image with OpenCV and then re-insert the EXIF data you lost when OpenCV opened it...
So, hopefully you can do what you are already doing, but also open the image with PIL/Pillow and extract the EXIF data and then write it into the image processed by OpenCV.
from PIL import Image
import io
# Read your image with EXIF data using PIL/Pillow
imWithEXIF = Image.open('image.jpg')
You will now have a dict with the EXIF info in:
imWIthEXIF.info['exif']
You now want to write that EXIF data into your image you processed with OpenCV, so:
# Make memory buffer for JPEG-encoded image
buffer = io.BytesIO()
# Convert OpenCV image onto PIL Image
OpenCVImageAsPIL = Image.fromarray(OpenCVImage)
# Encode newly-created image into memory as JPEG along with EXIF from other image
OpenCVImageAsPIL.save(buffer, format='JPEG', exif=imWIthEXIF.info['exif'])
Beware... I am assuming in the code above, that OpenCVImage is a Numpy array and that you have called cvtColor(cv2.COLOR_BGR2RGB) to go to the conventional RGB channel ordering that PIL uses rather than OpenCV's BGR channel ordering.
Keywords: Python, OpenCV, PIL, Pillow, EXIF, preserve, insert, copy, transfer, image, image processing, image-processing, dict, BytesIO, memory, in-memory, buffer.
I'm using Pillow (version 5.2.0) on Python3 to open both PNG and BMP images, and display them with a Tkinter GUI. The PNG images display correctly with no issues, however, I'm encountering an IOError ("Unsupported BMP compression") with some of the BMP images, when Pillow's BmpImagePlugin.py is used.
Using the bitmap plugin's source and some print statements, I found that the exception is thrown at line 193, and that the images causing the exception are compressed using RLE8 (denoted by the dictionary on line 63); all others work because they're a RAW format.
It would seem to me that if a compression type is listed in that dictionary it should be supported, but apparently that isn't the case.
My question: is anyone aware of a workaround in Pillow or of any other python library that can open RLE8 bitmap images?
Here's an image displaying my PATH environment, as well as the command-line error described in a comment below.
Path issues
I note that your first image (test1.bmp) appears to be corrupt and ImageMagick reports it has incorrect length.
Your second image does not appear to be compressed with RLE8 compression and also is a palettised image, but with alpha/transparency.
Your third image is palletised, non-alpha with RLE8 compression.
My version of PIL can read only the second file - the first and third, which are RLE encoded cannot be read.
You asked for a workaround - may I suggest pyvips which can read the files without issues:
import pyvips
from PIL import Image
# Load troublesome file using vips, and write to a memory buffer
image = pyvips.Image.new_from_file('test1.bmp')
mem_img = image.write_to_memory()
# Read from memory buffer into Numpy array
imgnp=np.frombuffer(mem_img, dtype=np.uint8).reshape(image.height, image.width, 3)
# Convert Numpy array to PIL Image and write to disk
Image.fromarray(imgnp).save('result.png')
I know that PILLOW can convert an image from say jpg to png using the save method but is there a way to convert the image to another format and just keep it as an Image object without actually saving it as another file?
So I want to convert a user supplied image to common format for working with in the program because certain tools I am using only support png.
jpg and png are just compression techniques for saving an image to a file. An image as an object, is just an array of RGB(or any other colorspace/format used by the library which you used to read the file) values of all the pixels.
So technically, you can use the image object as the common format for working with other tools. But you need to keep in mind about the colorspace which is used by each library. Like, OpenCV considers an image object in BGR format, so you need to convert the image object to this format before you use it in OpenCV.
I'm trying to open a tiff stack using gdal in python. It is a single file, within which are mutliple tiff files. When I open it in ImageJ, I can scroll through the stack. But doing "gdal.Open(file).ReadAsArray() only loads the first tiff file. Is there a way I can load the whole stack?
Iterate over GetSubDatasets and (in case all TIFF pages have the same dimensions) create a single numpy array:
import numpy, gdal, gdalconst
dataset = gdal.Open("multipage.tiff", gdalconst.GA_ReadOnly)
data = numpy.array([gdal.Open(name, gdalconst.GA_ReadOnly).ReadAsArray()
for name, descr in dataset.GetSubDatasets()])