Python image analysis: reading a multidimensional

2019-07-17 10:37发布

问题:

I have a TIFF image file from a confocal microscope which I can open in ImageJ, but which I would like to get into Python.

The format of the TIFF is as follows: There are 30 stacks in the Z dimension. Each Z layer has three channels from different fluorescent markers. Each channel has a depth of 8 bits. The image dimensions are 1024x1024.

I can, in principle, read the file with skimage (which I plan to use to further analyse the data) using the tifffile plugin. However, what I get is not quite what I expect.

merged = io.imread("merge.tif", plugin="tifffile")
merged.shape
# (30, 3, 3, 1024, 1024)
# (zslice, RGB?, channel?, height, width)
merged.dtype
# dtype('uint16')

What confused me initially was the fact that I get two axes of length 3. I think that this is because tifffile treats each channel as separate RGB images, but I can work around this by subsetting or using skimage.color.rgb2grey on the individual channels. What concerns me more is that the file is imported as a 16 bit image. I can convert it back using skimage.img_as_ubyte, but afterwards, the histogram does no longer match the one I see in ImageJ.

I am not fixated on using skimage to import the file, but I would like to get the image into a numpy array eventually to use skimage's functionality on it.

回答1:

I've encountered the same issue working on .tif files. I recommend to use bioformats python package.

    import javabridge
    import bioformats

    javabridge.start_vm(class_path=bioformats.JARS)

    path_to_data = '/path/to/data/file_name.tif'

    # get XML metadata of complete file
    xml_string = bioformats.get_omexml_metadata(path_to_data)
    ome = bioformats.OMEXML(xml_string) # be sure everything is ascii
    print ome.image_count

depending on data, one file can hold multiple images. Each image can be accessed as follows:

    # read some metadata
    iome = ome.image(0) # e.g. first image
    print iome.get_Name()
    print iome.get_ID()

    # get pixel meta data
    print iome.Pixels.get_DimensionOrder()
    print iome.Pixels.get_PixelType()
    print iome.Pixels.get_SizeX()
    print iome.Pixels.get_SizeY()
    print iome.Pixels.get_SizeZ()
    print iome.Pixels.get_SizeT()
    print iome.Pixels.get_SizeC()
    print iome.Pixels.DimensionOrder

loading raw data of image 0 into numpy array is done like that:

    reader = bioformats.ImageReader(path_to_data)
    raw_data = []
    for z in range(iome.Pixels.get_SizeZ()):
        # returns 512 x 512 x SizeC array (SizeC = number of channels)
        raw_image = reader.read(z=z, series=0, rescale=False) 
        raw_data.append(raw_image)
    raw_data = np.array(raw_data) # 512 x 512 x SizeC x SizeZ array

Hope this helps processing .tif files, Cheers!



回答2:

I am not sure if the 'hyperstack to stack' function is that what you want. Hyperstacks are simply multidimensional images, could be 4D or 5D (width, hight, slices, channels (e.g. 3 for RGB) and time frames). In ImageJ you have a slider for each dimension in a hyperstack.

Stacks are just stacked 2D images that are somehow related and you have only one slider, in the simplest case it represents the z-slices in a 3D data set.

The 'hyperstack to stack' function stacks all dimensions in your hyperstack. So if you have a hyperstack with 3 channels, 4 slices and 5 time frames (3 sliders) you will get a stack of 3x4x5 = 60 images (one slider). Basically the same thing as you mentioned above with sliding through the focal planes on a per-channel basis. You can go the other way around using 'stack to hyperstack' and make a hyperstack by defining which slices from your stack represent which dimension. In the example file I mentioned above just select order xyzct, 3 channels and 7 time points.

So if your tiff file has 2 sliders, it seems that it is a 4D hyperstack with hight, width, 30 slices and 3 channels. 'hyperstack to stack' would stack all dimensions on top of each other, so you will get 3x30=90 slices.

However, according to the skimage tiff reader it seems that your tiff file is some kind of a 5D hyperstack. Width, hight (1024x1024), 30 z-slices, 3 channels (RGB) and another dimension with 3 entries (e.g. time frames).

In order to find out what is wrong, I would suggest to compare the dimensions with 3 entries of the array you get from skimage. Find out which one of them represents the RGB channels and what the other one is. You can for example use pyqtgraph's image function:

import pyqtgraph as pg
merged = io.imread("merge.tif", plugin="tifffile")

#pg.image takes the dimensions in the following order: z-slider,x,y,RGB channel
#if merged.shape = (30, 3, 3, 1024, 1024), you have to compare the 1st and 2nd dimension

pg.image(merged[:,0,:,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,1,:,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,2,:,:,:].transpose(0, 2, 3, 1))

pg.image(merged[:,:,0,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,:,1,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,:,2,:,:].transpose(0, 2, 3, 1))