Open petoor opened 4 years ago
Hello @petoor,
Yes, you can get the OME XML from image-description
, eg.:
$ vipsheader -f image-description multi-channel-z-series.ome.tif
Or in Python:
xml = image.get("image-description")
You can set new xml as well, though it's up to you to ensure conformance.
Cheers, this gives exactly what i'm looking for!
When i try to do the same with a .ndpi / .bmp / .png file i get a vips_image_get: field "image-description" not found i guess due to the lack of the files not having a xlm header.
Is there any way to get a standardized output from pyvips containing the metadata of the images?
Also, is there a way to see which key words image.get accepts? I can't find much about it here : https://libvips.github.io/pyvips/vimage.html#pyvips.Image.get
That's right, image-description
is part of libtiff:
https://www.awaresystems.be/imaging/tiff/tifftags/imagedescription.html
And OME uses it to carry the extra XML metadata it needs around.
You can check for the existence of a field with get_typeof()
, eg.:
>>> x = pyvips.Image.new_from_file("k2.jpg")
>>> x.get("banana")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/john/.local/lib/python3.7/site-packages/pyvips/vimage.py", line 771, in get
raise Error('unable to get {0}'.format(name))
pyvips.error.Error: unable to get banana
vips_image_get: field "banana" not found
>>> x.get_typeof("banana")
0
>>> x.get_typeof("width")
24
The int returned by get_typeof
is a GType
, 0 means unknown. Have a look at:
https://github.com/libvips/pyvips/blob/master/pyvips/gvalue.py#L18
vipsheader -a somefile
is a handy way to see what metadata an image has.
libvips is really a colour 2D image processing library, so width / height / bands / format is the standard metadata.
It has some support for things like volumetric, time-series and multi-res images, but it's a bit ad-hoc and it depends on the format to a degree. DICOM volumetric images are loaded as multi-page "toilet roll" images, for example, like PDFs and GIFs. OpenSlide images are opened a layer at a time and use the standard openslide metadata to select subimages at open time, just like pyramidal TIFFs.
... I meant to say, you'll need to check that image-description contains OME XML. Most TIFF files will have image-description
, but it'll usually be something dull like "created with photoshop 12".
Thank you for the elaboration John. running vipsheader -a "image" from the terminal gives me all the information i'm looking for. Is there a way to call vipsheader -a inside a pyton file and save the metadata as a dict or list?
.get()
returns the same information. .get_fields()
gives you the names of all fields.
metadata = [image.get(field) for field in image.get_fields()]
metadata = [image.get(field) for field in image.get_fields()]
returns [] for both the .ndpi file and the ome.tif file
vipsheader -a works for both.
using your multi-channel-z-series.ome.tif file as test
Oh, strange, it works for me:
>>> x = pyvips.Image.new_from_file("multi-channel-z-series.ome.tif")
>>> x.get_fields()
['width', 'height', 'bands', 'format', 'coding', 'interpretation', 'xoffset', 'yoffset', 'xres', 'yres', 'filename', 'vips-loader', 'n-pages', 'image-description', 'resolution-unit', 'orientation']
>>> [x.get(field) for field in x.get_fields()]
[439, 167, 1, 'char', 'none', 'b-w', 0, 0, 0.0, 0.0, ...
Could something else be wrong?
A hash might be more useful, of course:
>>> {field: x.get(field) for field in x.get_fields()}
{'width': 439, 'height': 167, 'bands': 1, 'format': 'char', ...
Actually, the vipsheader -a multi-channel-z-series.ome.tif returns : width: 439 height: 167 bands: 1 format: 1 - char coding: 0 - none interpretation: 1 - b-w
Shouldn't this be 3 bands? Since the image contains 3 color channels. Or is the interpretation bands /= color channels?
Output from terminal :
Python 3.6.9 (default, Nov 7 2019, 10:44:02) [GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
import pyvips
img_path = '/home/peter/Downloads/multi-channel-z-series.ome.tif'
image = pyvips.Image.new_from_file(img_path)
image.get_fields()
[]
{field: image.get(field) for field in image.get_fields()}
{}
Version : Name: pyvips Version: 2.1.11 Summary: binding for the libvips image processing library, API mode Home-page: https://github.com/libvips/pyvips Author: John Cupitt Author-email: jcupitt@gmail.com License: MIT Location: /home/peter/.local/lib/python3.6/site-packages Requires: cffi, pkgconfig Required-by:
Do you have an old libvips? I see:
>>> pyvips.version(0)
8
>>> pyvips.version(1)
9
>>> pyvips.version(2)
1
ie. my pyvips is using libvips version 8.9.1.
OME puts the colour into separate planes, so you need to extract and recombine layers to get a recognisable colour image (I think).
pyvips.version(0) 8 pyvips.version(1) 4 pyvips.version(2) 5
With the sudo apt install libvips libvips-dev this should be the newest version. I can try updating tomorrow. It should be noted that image.get('width') for instance works fine. It is just image.get_fields() that returns an empty list.
Regarding the tif files, I think putting the number of color channels to be the number of bands in the vipsheader is the correct thing to do. However, i could be wrong here.
Ah that's very old, you'll probably need to build libvips from source. It's not hard -- it's a standard autotools package.
The libvips header fields are describing the exact layout of the tiff file, so bands really is 1. OME TIFF stores RGB images like this:
RRR
RRR
RRR
GGG
GGG
GGG
BBB
BBB
BBB
But everyone else stores like this:
RGBRGBRGB
RGBRGBRGB
RGBRGBRGB
So you'll need to do a bit of data reorganisation if you want to make a JPG (for example).
I can confirm that your code works after updating to 8.9.1.
Updating was easy following https://github.com/libvips/libvips/wiki/Build-for-Ubuntu
It should be noted that for python 3.6 the line 'export PYTHONPATH=$VIPSHOME/lib/python2.7/site-packages' should be 'export PYTHONPATH=$VIPSHOME/lib/python3.6/site-packages' and the user should remember to do source .bashrc after updating it.
I also used ./autogen.sh --prefix=/home/peter/vips but this can be excluded out from the guide.
actually, if you add the /home/user_name/vips folder to the prefix argument i guess it shouldn't be sudo make install but make install. I guess for simplification the --prefix should only be mentioned as an option.
Glad it worked!
Anyone can edit that wiki page, if you'd like to add your notes.
Hi again.
If i want to convert the ome.tiff with 15 pages into 5 images with RGB color. I can use something like
# c = 3, z = 5.
# band_nr = img_metadata.get('n-pages') // c
for i in range(1, c):
band = pyvips.Image.tiffload(photo.file_original.path, page=z+i*band_nr)
image = image.bandjoin(band)
Which results : <pyvips.Image 439x167 char, 3 bands, b-w> (times 5 in this case)
Is there any way to convert b-w to rgb?
image.colourspace("rgb")
yields vips_colourspace: no known route from 'b-w' to 'rgb'
Hi again,
It's called srgb
, so:
y = x.colourspace("srgb")
Though that won't work for you -- you have a three band image tagged as b-w
, so libvips thinks it is a mono image with two alpha channels. You need to simply change the tag so your three bands are interpreted as RGB.
You can change the tag on an image with copy
, for example:
y = x.copy(interpretation="srgb")
Now you should have a three band image tagged as srgb
.
Hello. This question is inspired by : https://github.com/libvips/ruby-vips/issues/91 Is there a way to make pyvips.Image.new_from_file() return the dimension of bands and the dimensions of z?
Using your multipage tiff file as example : http://downloads.openmicroscopy.org/images/OME-TIFF/2016-06/bioformats-artificial/multi-channel-z-series.ome.tif
pyvips.Image.new_from_file("multi-channel-z-series.ome.tif", access="sequential") yields : <pyvips.Image 439x167 char, 1 bands, b-w>
And we can then loop over the bands with the pages argument. However, it seems like the colorchannel and the z-channel are multiplied together... That is, pyvips.Image.new_from_file("multi-channel-z-series.ome.tif", access="sequential", pages=13) yields the 3rd channel at the 4th time.
Compare this to bio formats, the metadata is. Axes: 4 Axis 'x' size: 439 Axis 'y' size: 167 Axis 'c' size: 3 Axis 'z' size: 5 Pixel Datatype: i1
So the question is, is there a way to make pyvips return the metadata of (t,x,y,z,c)? (Time, Height, Width, Depth, Color)
This would make it easier to structure data into a database.
Best regards.