Saving an ND image with pyimagej


I was trying to write a 4d c-z-x-y series from python today, and tried both pyimagej and python-bioformats. I wasn’t able to get either to work perfectly.

First I create a nd numpy array

# 4 channels, 50 slices,  512 by 512
nz = 50
ny = 512
nx = 512

test=((2**16-1)*np.random.rand(nc, nz, ny, nx)).astype('uint16')

Then try to save with pyimagej

import imagej
ij=imagej.init(), 'frompyimagej.tif')

It saves, but it doesn’t seem to save the axis info. When loading into Fiji I get a 3D array with 200 frames instead of a 4d array. Any advice on how to save as 4d? I also tried converting to xarray first but that didn’t work.

I also tried python-bioformats

import bioformats as bf

That didn’t work, as it failed with an error, however I’m not sure I expected it to, because if I remember I have to set things up and write one plane at a time with python-bioformats. Is that correct?

I actually don’t have a preference at all between bioformats and pyimagej. Whatever one works, and will be supported in the future is fine with me.


1 Like

@bcimini , @hinerm

Just flagging you both, as I know you are looking at how to best support python-bioformats and pyimagej in the future.

I often deal with 4d data-sets with greater than 3 channels, recently I tried to figure out how to save these with Python. (let me know if I am missing something in terms of documentation. I could not find an example so just sort pieced things together by experimentation).

Here is what I have with python-bioformats

for z in range(nz):
        for c in range(nc):
            bf.write_image(file_name,img[z,c,:,:],'uint16',c=c,z=z,t=0,size_t=1,size_c=nc, size_z=nz, channel_names=channel_names)

It works but I’ve experienced an intermittent crash where it seems the file gets locked at some point in the loop. Is there any additional step I have to take like locking the file while writing a plane?

I also tried pyimagej, using an x-array as a means to set the channel types. This runs but the image is not 4D when I load it back in Fiji. Any suggestions?

import imagej
import xarray as xr

#ij = imagej.init()
ij = imagej.init('sc.fiji:fiji:2.1.1')
data = xr.DataArray(test, dims=('C','z','y','x'))
dataset = dataset =
dataset =, 'frompyfiji.tif')

The goal is simply to write a 4d dataset, I’m not attached to pyimagej, or python-bioformats or anything else. Would be happy to look at a third alternative if there is one.

Let me know if you have any suggestions



tifffile directly or via scikit-image works great for such cases. Here you first have to re-arrange your dimensions to ZCYX order and then use tifffile.imwrite:

import tifffile
test = np.moveaxis(test,0,1)
tifffile.imwrite('test.tiff', test, imagej=True, metadata={'axes': 'ZCYX'})

With the following result when you open it in Fiji:

tifffile is very well supported by @cgohlke and continuously updated.

I hope that helps!

1 Like

Thanks @guiwitz

That is extremely helpful. I was not aware that tifffile supported ND (N>3) data. One small addition, to get the image to display as a color composite I had to add 'mode':'composite' to metadata.

It looks like if I want to customize the colormaps for each channel I have to potentially follow this example. Or is there possibly an easier way to pass in the colormaps?


Hi @bnorthan

I just wanted to chime in on what’s happening to your 4D array in ImageJ. Your code actually is working as intended – the numpy array is converted into a Dataset just fine. If you set pyimagej to be headless with ij = imagej.init(headless=False) and show the Dataset before saving you’ll see its good to go! The issue is that .tif does not support >3D normally. SCIFIO writes a header on the these files that lets it do so however. The trick now is to read it back with the right reader to understand SCIFIO’s flavor of .tifs.

If you drag and drop the output .tif image into Fiji you’ll trigger ImageJ’s tif reader which doesn’t understand SCIFIO’s .tif. If you open the image with File > Import > Image> you’ll get SCIFIO which can properly understand the 4D image.

More info

1 Like

Hi @elevans

Thanks. That works. Although it is a bit cumbersome to dive down into the menu and choose the additional option.

Is a scifio tiff different than an ome tiff? The default opener seems smart enough to start up bioformats when I choose the xml associated with an ome tiff series.

What is the easiest way to output an ome tif (with xml) using PyImageJ ?

The use case is that I have some very large complicated ND ome tiff datasets. I want to open them in Python, re-organize or extract a subset of data, then save again, preferably still as ome tif with the xml header.