Closed petoor closed 3 years ago
Turns out you have already answered this question : https://github.com/libvips/pyvips/issues/222
In case anyone else comes across this question, here's some demo code:
#!/usr/bin/python3
import sys
import pyvips
im = pyvips.Image.new_from_file(sys.argv[1])
print(f"image has {im.bands} bands")
# put the image together with itself three times, so for example an RGB
# source will become a 9-band image
manyband = im.bandjoin([im, im])
manyband.write_to_file(sys.argv[2])
im2 = pyvips.Image.new_from_file(sys.argv[2])
print(f"after save and reload, image has {im2.bands} bands")
I can run it like this:
john@banana ~/try $ ./manyband.py ~/pics/k2.jpg x.tif
image has 3 bands
after save and reload, image has 9 bands
john@banana ~/try $ !tiff
tiffinfo x.tif
TIFF Directory at offset 0x197d008 (26726408)
Image Width: 1450 Image Length: 2048
Resolution: 72.009, 72.009 pixels/inch
Bits/Sample: 8
Sample Format: unsigned integer
Compression Scheme: None
Photometric Interpretation: RGB color
Extra Samples: 6<unassoc-alpha, unassoc-alpha, unassoc-alpha, unassoc-alpha, unassoc-alpha, unassoc-alpha>
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 9
Rows/Strip: 128
Planar Configuration: single image plane
So the three band RGB image becomes a 9 band RGB TIFF, with the extra six bands tagged as unassoc-alpha
(ie. extra image bands with no alpha premultiplication). This might or might not load into imagej etc.
Some tile formats have strict limits on the number of image bands they allow, for example:
john@banana ~/try $ ./manyband.py ~/pics/k2.jpg x.ppm
image has 3 bands
after save and reload, image has 3 bands
PPM only allows 1 or 3 bands, so the extra 6 are dropped on save.
Thank you John.
While https://github.com/libvips/pyvips/issues/222#issuecomment-748509935
gives the correct image, when loading it pyvips displays.
<pyvips.Image 3360x3456 uchar, 1 bands, b-w>
Would it be possible to get pyvips to state the correct metadata directly? so SizeC, SizeT, SizeX, SizeY, SizeZ from the ome.tiff format. Idearly with the pyramid information as well. Or at least at which page the different C, T and Z are located?
This is simply a feature request as newcommers to vips might look at the above and think it is strange that their ome.tiff image looks "flat"
Ah, this is an OME TIFF? They are rather different (and complicated).
You need to load all the page of the TIFF, then bandjoin them back into an N-band interleaved image. You can use the subifd
parameter to select the pyramid layer.
There's some sample OME save code here:
https://forum.image.sc/t/writing-qupath-bio-formats-compatible-pyramidal-image-with-libvips/51223/6
You'd need to do the inverse for OME load. Do you need sample code?
Actually in this case it is 3 ndpi files (different staining) I need to combine into one image. The format of the combined image is not important, however ome.tiff seems to do the job rather nicely.
I guess the ome.tiff metadata provided in https://forum.image.sc/t/writing-qupath-bio-formats-compatible-pyramidal-image-with-libvips/51223/6 makes it an ome.tiff file?
It would be very nice with some ome load sample code. Ideally where one specifies t, z and c and the corresponding "toilet paper sheet" is returned.
Also, is there a way to see how deep the pyramid is? That is, number of subifd's per sheet.
Yes, use image.get("n-subifds")
to get he number of subifds (pyramid layers). You can use vipsheader -a
to see all the fields, eg.:
$ vips copy CMU-1.svs x.tif[tile,pyramid,compression=jpeg,subifd]
$ vipsheader -a x.tif
x.tif: 46000x32914 uchar, 3 bands, srgb, tiffload
width: 46000
height: 32914
bands: 3
format: uchar
coding: none
interpretation: srgb
xoffset: 0
yoffset: 0
xres: 2004.01
yres: 2004.01
filename: x.tif
vips-loader: tiffload
n-subifds: 9
n-pages: 1
resolution-unit: cm
orientation: 1
Are you planning to load the OME TIFF into QuPath, or bioformats?
Post some (small) sample images and I'll make you a converter.
Perfect. Thanks.
I have a tile server connected to some JavaScript that serves the images, so neither in my case. Is there a difference of how QuPath and bioformats treats the metadata though?
If you haven't any ome.tiff load code already it is fine, I don't want you to spend time on it.
As a feature request it would be nice to have tiffload where you specify the Time and Z (if applicable by the metadata) and maybe channel (I guess you want all by default), this makes as much sense as having page as a argument, at least to me. However I also respect if it doesn't fit into the design of pyvips.
I found an ome load example:
#!/usr/bin/python3
import sys
import pyvips
# ome images load as a tall, thin strip, with page-height indicating the breaks
image = pyvips.Image.new_from_file(sys.argv[1], n=-1)
page_height = image.get("page-height")
# chop into pages
pages = [image.crop(0, y, image.width, page_height)
for y in range(0, image.height, page_height)]
# join pages band-wise to make an interleaved image
image = pages[0].bandjoin(pages[1:])
# set the rgb hint
image = image.copy(interpretation="srgb")
image.write_to_file(sys.argv[2])
You can pick a pyr layer with subifd=
, for example:
$ vipsheader -a x.tif
x.tif: 24960x34560 uchar, 1 band, b-w, tiffload
width: 24960
height: 34560
bands: 1
format: uchar
coding: none
interpretation: b-w
xoffset: 0
yoffset: 0
xres: 2008.05
yres: 2008.05
filename: x.tif
vips-loader: tiffload
n-subifds: 9
n-pages: 5
image-description: <?xml version="1.0" encoding="UTF-8"?><!-- Warning: this comment is an OME-XML metadata block, which contains crucial dimensional parameters and other important metadata. Please edit cautiously (if at all), and back up the original data before doing so...
resolution-unit: cm
orientation: 1
Then:
$ ~/try/ome2vips.py x.tif[subifd=6] layer6.tif[compression=jpeg,tile]
$ vipsheader layer6.tif
layer6.tif: 195x270 uchar, 3 bands, srgb, tiffload
Hi John.
Thank you for the code.
Isn't it a problem to set the interpretation to standard RGB in the case of 5 pages (5 color channels)? If i understand your x.tif image correctly that is of course. One could argue that for images where bands != 3 RGB is doesn't make much sense. Wouldn't it be better to just keep it b-w or multiband ?
I think it doesn't really matter. TIFF only supports 1, 3 and 4 bands, and any others have to be tagged as alpha.
RGB is useful because it'll probably look better in viewers.
Hello John. I have 3 RGB images i have merged in the color channel. It should be possible to save it as a 9 channel image. However, when i save it and reload it, it only saves the first 3 channels.
I know i can use img.join(img2, "vertical") and specify the page height of the image "toilet paper roll" style. However, it will be more clean to be able to save the images combined in the band channels not changing height or width. Is this possible?
Best regards.