How to generate valid HyperStack ImageJ data files from Matlab?

2.3k Views Asked by At

ImageJ HyperStacks have a data type (8-32 bit), a width, a height, a number of channels, a number of slices and a number of frames. They represent 5D (XYCZT) data sets. ImageJ stores them as multipage tiff files where number of channels times number of slices times number of frames 2D (XY) images are stored. The first image seems to have two custom tags with IDs 50838 and 50839.

I want to create tif files containing 5D data from Matlab that can be read by ImageJ as a valid 5D HyperStack.

I can store a number of 2D images in a multipage tiff file in Matlab using imwrite(matrix, file, 'WriteMode','append') but ImageJ will read that as 3D (XYZ) image stack only. The information about the channels, slices and frames is not contained.

I guess I could look at the ImageJ sources to find out where they store this missing information, then use Matlab's wrapper of LibTIFF to recreate the meta information of ImageJ. If you, however, already know what to do or if there is an alternative, I would like to hear it.

3

There are 3 best solutions below

2
On BEST ANSWER

Using Matlab's Tiff class.

I can assemble an ImageDescription tag that I think looks fine and ImageJ reads it (File>Open) as a 5D Hyperstack but the data is partly corrupted. There seem to be offset problems (I can read the data just fine in again with Matlab).

However, if reading the tiff file with File>Import>Bio-Formats it becomes 5D (XYCZT) stack in ImageJ if view stack with Hyperstack is marked in the Bio-Formats import dialog. Thanks to ctrueden for his helpful comment.

d = ones(100, 200, 10, 2, 3, 'single') * 3.765;
hyperstack_write('test.tif', d);

function hyperstack_write(file, hyperstack)
% Writes an (up to) 5D stack into a (XYCZT) HyperStack Tiff file
% readable by ImageJ
%
% hyperstack must have class single

% simple checks
assert(nargin == 2, 'Not enough arguments');
assert(isa(hyperstack, 'single'), 'hyperstack must be single');

% get all five dimensions
d = zeros(5, 1);
for i = 1 : 5
    d(i) = size(hyperstack, i);
end

% assemble image description
s = sprintf('ImageJ=1.51\nnimages=%d\nchannels=%d\nslices=%d\nframes=%d\nhyperstack=true\nmode=color\nloop=false\nmin=%.1f\nmax=%.1f\n', prod(d(3:5)), d(3), d(4), d(5), floor(min(hyperstack(:))*10)/10, ceil(max(hyperstack(:))*10)/10);

% open tif file for writing and set file tags
t = Tiff(file, 'w');

ts.ImageLength = d(1);
ts.ImageWidth = d(2);
ts.Photometric = Tiff.Photometric.MinIsBlack;
ts.Compression = Tiff.Compression.None;
ts.BitsPerSample = 32;
ts.SamplesPerPixel = 1;
ts.SampleFormat = Tiff.SampleFormat.IEEEFP;
ts.RowsPerStrip = 5;
ts.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
ts.Software = 'MATLAB';
ts.ImageDescription = s;

% loop over dimensions 3, 4, and 5
for k = 1 : d(5)
    for j = 1 : d(4)
        for i = 1 : d(3)
            frame = hyperstack(:, :, i, j, k);
            t.setTag(ts)            
            t.write(frame);
            t.writeDirectory();
        end
    end
end

% close tif file
t.close();

end

It seems Bio-Formats is the only fully paved and available way to export >2D data from Matlab to ImageJ, although this solution here could be a lightweight alternative in cases where not much metadata is available and needs to be transferred.

5
On

I also thought that Bio-Fomats was the only way. But then I realized that Fiji's ImageJ-MATLAB allows you to pass MATLAB data to ImageJ. Then, you can save the image by ImageJ, so ImageJ can open it for sure.

The problem was that people (or just one guy?) created ImageJ-MATLAB did a great job in creating a route from MATLAB to ImageJ, but they didn't seem to bother optmizing the behaviour. ImageJ-MATLAB's IJM.show('name') had a lot of hidden or undocumented limitations (I massively changed the documentation, so it should be clearer now). Eventually, I enede up wriring a wrapper function

ijmshow

https://github.com/kouichi-c-nakamura/ijmshow

Example MATLAB code

You can do it with 4 lines.

addpath '/Applications/Fiji.app/scripts' % depends your Fiji installation
ImageJ

imp = ijmshow(I,'YXCZT') % I is 5D array of uint8 or uint16
% the second argument determines which dimension represents what
% imp is a 5D hyperstack

ij.IJ.saveAsTiff(imp, 'image1.tif');

You may want to set Display Range of each channel before saving.

Added on 5/7/2018

copytoImagePlus provides better solution than ijmshow above (you can use the same syntax), because copytoImagePlus does not rely on the IJM variable in the base workspace anymore.

https://github.com/kouichi-c-nakamura/copytoImagePlus

addpath '/Applications/Fiji.app/scripts' % depends your Fiji installation
ImageJ

imp = copytoImagePlus(I,'YXCZT') % I is 5D array of uint8 or uint16
% the second argument determines which dimension represents what
% imp is a 5D hyperstack

ij.IJ.saveAsTiff(imp, 'image1.tif');

Also see copytoImgPlus which create ImageJ2 ImgPlus object instead.

https://github.com/fiji/fiji/blob/master/scripts/copytoImgPlus.m

1
On

ImageJ uses the ImageDescription tag of the TIFF's first IFD to store its meta-information. Here is an example from the Mitosis sample dataset (File > Open Samples > Mitosis):

ImageJ=1.51d
images=510
channels=2
slices=5
frames=51
hyperstack=true
mode=composite
unit=\u00B5m
finterval=0.14285714285714285
loop=false
min=1582.0
max=6440.0

MATLAB's Tiff class might give you fine-grained enough control to write a custom ImageDescription to the first IFD; I am not sure.

Probably easier would be to use the Bio-Formats library's bfsave.m function to write OME-TIFF, which can be 5-dimensional; ImageJ can read this format via the Bio-Formats plugin. I recommend using the Fiji distribution of ImageJ, which comes with Bio-Formats pre-installed.

There was also this same question posted on MATLAB Central.