Crop roi from czi file and downscale - all in python

Hello everybody!

I am writing a script in python to crop out several rois from a huge czi file (with different channels and timepoints) to then rescale it and do some processing. I usually use fiji to do this, but for several reasons I prefer in this case to do all in python. So, I need two advices:

  1. I open the czi file using czifile and I crop by slicing it. I then save the file as a tif, but when I open the file in fiji all timepoints and z stacks are fused together. Is there a way to save it in a way that can be read by fiji as multichannel, multi z stack ?
img = czifile.imread('path/to/file.czi')
# img.shape is [1, 1, 1, 183, 2, 190, 960, 960, 1] for a file having :
# 2 channels, 183 timepoints, 190 slices and 960 pixels in xy
# i am not sure about the other numbers
resized = img[:, :, :, :, :, 20:40, 106:300, 625:840, :] 
imsave('crop.tif', resized)
  1. When I downscale my images in fiji, in the macro I write that I want to downscale by a factor of e.g. 0.5 in xy, no interpolation and averaging when downscaling. Does anybody know how I can reproduce the same output using opencv.resize or skimage.transform or another function?

Thanks!!

Hi @LucreziaF ,

As for your first question, you may want to have a look at the python bioformats package, I think it offers a bit more control with regard to how channels/stacks/timepoints are opened. It also provides an image writer (which I haven’t used yet) that should also provide the same level of functionality, e.g. allows you to set channel/timepoint/stack dimensions.

Downsampling in python: If you are downsampling by a factor of 0.5, then the following could be a cheap hack:

A = np.arange(0, 100*100, 1).reshape(-1, 100)  # Allocate array with linear gradient
A1 = A[::2, ::2]  # Slicing/Downsampling

The second line basically samples the input array at every 2nd index and consequently doesn’t do any interpolation whatsoever.

Hope this helps!

Edit: Python bioformats

1 Like

I suggest using:

cropped = img[0, 0, 0, :, :, 20:40, 106:300, 625:840, 0]

That gets rid of dimensions other than tczyx, which will probably confuse imsave & co, at least some implementations of it. You can also use np.squeeze, though that might get rid of dimensions you don’t necessarily want to get rid of:

cropped = np.squeeze(img[:, :, :, :, :, 20:40, 106:300, 625:840, :])

I then recommend using tifffile.imsave instead of skimage.imsave. But I’m not 100% sure that will fix your loading-in-Fiji problem. Perhaps @cgohlke will have advice on the right way to specify dimension identity when using tifffile.

The function you’re after is skimage.transform.downscale_local_mean.

Try to save the image array as an ImageJ hyperstack or OME-TIFF, e.g.:

tifffile.imwrite(
    'crop.ome.tif',
    img[0, 0, 0, :, :, 20:40, 106:300, 625:840, 0],
    metadata={'axes': 'TCZYX'}
)
1 Like

I tried to save the image array as an hyperstack but it still does not recognise stacks and timepoints when I open in FIJI. Anyway, I decided to process the whole file in Python and for that I have no problem…

Thank you!