Adding ImageDepth support to pylibtiff
markemus opened this issue · 5 comments
Hey @pearu, I wrote some code to allow pylibtiff to read 3D TIFF images. It's a modified version of the TIFF.read_tiles() method in libtiff_ctypes.py. Currently it's a monkeypatch that is applied to libtiff at runtime.
If you're interested in it, I'd be happy to refactor it to be part of:
- read_tiles(), or
- a separate method, TIFF.read_z_tiles()
I'm hopefully also going to be doing this for write_tiles() in the near future.
Thanks for writing this great library!
Here's the code:
"""Adds a method to libtiff.TIFF to read z-stack tiff images (images with an ImageDepth tag).
Import this module anywhere in your code but before instantiating the TIFF class to apply the patch."""
import numpy as np
from libtiff import TIFF
def read_z_tiles(self, dtype=np.uint8):
num_tcols = int(self.GetField("TileWidth")/2)
num_trows = int(self.GetField("TileLength")/2)
num_icols = int(self.GetField("ImageWidth")/2)
num_irows = int(self.GetField("ImageLength")/2)
num_depths = self.GetField("ImageDepth")
# this number includes extra samples
samples_pp = self.GetField('SamplesPerPixel') * 2
def read_plane(plane, tmp_tile, plane_index=0, depth_index=0):
for y in range(0, num_irows, num_trows):
for x in range(0, num_icols, num_tcols):
# input data is 2x as many dims per pixel as parameters state.
r = self.ReadTile(tmp_tile.ctypes.data, x*2, y*2, depth_index, plane_index)
if not r:
raise ValueError(
"Could not read tile x:%d,y:%d,z:%d,sample:%d from file" %
(x, y, plane_index, depth_index))
# if the tile is on the edge, it is smaller
tile_width = min(num_tcols, num_icols - x)
tile_height = min(num_trows, num_irows - y)
plane[y:y + tile_height, x:x + tile_width] = \
tmp_tile[:tile_height, :tile_width]
full_image = np.zeros((num_depths, num_irows, num_icols, samples_pp), dtype=dtype, order='C')
tmp_tile = np.zeros((num_trows, num_tcols, samples_pp), dtype=dtype, order='C')
for depth_index in range(num_depths):
read_plane(full_image[depth_index], tmp_tile, depth_index=depth_index)
return full_image
# Apply monkeypatch
TIFF.read_z_tiles = read_z_tiles```
Just to be clear, this is for color image stacks- the current version already should support 3D grayscale stacks. So I guess these are really "4D" stacks.
Thanks for reporting the issue and sorry for the long delay in responding.
Could you submit your changes as a PR?
I've developed it more since then, including code for rewriting the data into separate directories. I'll post a PR when I get a chance.