Bioformats in Julia?

Hi All,

I look how Julia may be suitable for my current project (related to Bioimaging), and as I see, there is no connection to Bioformats.

Bioformats is Biomicroscopy format crunching I/O software easily accessible from Java and Matlab, and also from Python.

https://github.com/openmicroscopy/bioformats
http://pythonhosted.org/python-bioformats/

Well-known Image processing and visualization packages like ImageJ/FIJI and Icy use it as default I/O.
Briefly, it is indispensible there, and if a convenient bridge to Bioformats existed in Julia, that would be great invitation to Bioimaging community.

I looked at JavaCall project but found that it isn’t enough, as it can’t keep Java objects.
We work with Bioformats basic OME.tiff format that Julia can open, but unfortunately without access to the metadata.
So I even think about compiling some standalone metadata grabbing command-line utility in Java or Matlab, to save metadata to file and then open it in Julia. This is clumsy.

I’m new to Julia, so maybe I’m missing something very crucial, here?:slight_smile:
I think sooner or later, the Bioformats question would appear anyway from someone else.

Thanks,
Y.
/Yuriy Alexandrov

2 Likes

Yes, getting support for Bioformats seems quite important. There was some discussion about this at last year’s JuliaCon, but I don’t think anything has moved forward yet and I haven’t looked at this myself. I’ve never used JavaCall (or Java, for that matter), but do the JavaObjects not provide a mechanism to achieve this?

I’ve also heard rumors that a rewrite of BioFormats in C++ was in the works, but I haven’t followed its development.

If you’re interested in working on this, I’d suggest opening an issue over at JavaCall to discuss missing functionality.

haven’t heard about that.
In Matlab you simply get Java objects and voila.

Bioformats C++ covers OME.tiff only.
BTW would be enough for me, but, as they only added support for crucial pieces of metadata couple of weeks ago? risky…
Microscopy uses tons of other formats.

and my intention was exactly the opposite, to escape horrors of C++ syntax while designing algorithms.
…

Yes, I think the C++ one is too immature for now.

If you look at the usage demo in JavaCall.jl -- Call Java from Julia, gurl appears to be a stateful Java object. You can read more about JavaObject on the Types and Methods pages. Will those do what you want?

thanks for the suggestion.
I’ll draw some nice Bioformats metadata example from Matlab.
should be interesting.
…

not sure.
as I understand, the whole set of recipes, is it named API, for creating Java objects is stored in corresponding jar files.
they have that magic single file now, named “bioformats_package.jar” AFAIR.
if access to what is inside is supported then yes.
maybe I just don’t know how to call it correctly. would be good.
…

Given my lack of any kind of Java experience, I’m afraid I’m not going to be much help here. If you don’t get an answer from someone who knows more, maybe try opening an issue over at JavaCall.

Also, I suspect you’re familiar with these already, but in case not: FileIO may be useful towards the end stages of this project, and if you encounter trouble ImageMagick might be a useful model.

these packages do open images as XYZ arrays, but the problem is metadata.
the same image Bioformats interpret as having 5 dimensions - XYZCT (+channel, +time)
and we have additional attributes/indices for FLIM time gate delay, and tomography projection angle, packed into T and Z.
I’ll open issue at JavaCall in Monday.
…

See: How to add classpath · Issue #3 · JuliaInterop/JavaCall.jl · GitHub

JavaCall.jl works by creating an instance of JVM and calling Java through JNI. Except for a few corner cases, you can do from Julia whatever you can do from Java itself. Do you have example code in Java to read image and metadata?

Encoding the “meaning” of the axes is no sweat; among programming languages, I suspect we’re in unusually good shape. See ImageAxes, ImageMetadata, and AxisArrays. For a model, you can check NRRD to see how it handles metadata. We need to get color-channel information as the first dimension, but you can always use permutedims or, for images too big to store in memory at once, permuteddimsview. For now, things like FLIM parameters and tomography projection angle are probably best stored in an ImageMeta.

Also, ImageMagick does have a magickinfo function for querying metadata. It’s pretty simple, but the general idea of having some kind of info function seems almost necessary for Bio-Formats.

yes certainly - but I have it actually in Matlab.
https://github.com/yalexand/Imperial-OMEkit
(in project itself there are lot of garbage, but also a functional feature, too… hidden…)

here is the function reading angles:

     function ret = get_angles(obj,full_filename,~)
            
            ret = [];
            
            try
            
                r = loci.formats.ChannelFiller();
                r = loci.formats.ChannelSeparator(r);

                OMEXMLService = loci.formats.services.OMEXMLServiceImpl();
                r.setMetadataStore(OMEXMLService.createOMEXMLMetadata());
                r.setId(full_filename);
                %
                modlo = r.getModuloZ();
                if ~isempty(modlo)

                     if ~isempty(modlo.labels)
                         ret = str2num(modlo.labels)';
                     end

                     if ~isempty(modlo.start)
                         if modlo.end > modlo.start
                            nsteps = round((modlo.end - modlo.start)/modlo.step);
                            ret = 0:nsteps;
                            ret = ret*modlo.step;
                            ret = ret + modlo.start;
                         end
                     end
                     
                end
                        
            catch
            end
            
        end

to open OME.tiff file, we do something like in this excerpt:

            try
            omedata = bfopen(full_filename);
            catch err
            %
            end
            
            if ~isempty(omedata)
                                
            r = loci.formats.ChannelFiller();
            r = loci.formats.ChannelSeparator(r);
            OMEXMLService = loci.formats.services.OMEXMLServiceImpl();
            r.setMetadataStore(OMEXMLService.createOMEXMLMetadata());
            r.setId(full_filename);
            r.setSeries(0);            
            omeMeta = r.getMetadataStore();  
            
            obj.PixelsPhysicalSizeX = 1;
            obj.PixelsPhysicalSizeY = 1;
            try
                obj.PixelsPhysicalSizeX = omeMeta.getPixelsPhysicalSizeX(0).getValue;
                obj.PixelsPhysicalSizeY = omeMeta.getPixelsPhysicalSizeY(0).getValue;
            catch
                disp('no PixelsPhysicalSize info, set to 1');
            end
            
            imgdata = omedata{1,1};  % actual stack of XY planes              
            n_planes = length(imgdata(:,1));
            % etc. etc.

here “r” is the “reader” object that also may be returned by bfGetReader function, which is the part of “bfmatlab.zip” package, as well as “bfopen”.
The package was designed by Sebastien Besson.

I think some of our file opening excerpts may be in Java, but the whole idea is that in any place in the code you can create reader like here

  r = loci.formats.ChannelFiller();
  % and so on.

and it’s yours.
…

the matter is, our acquisition software uses tools like MicroManager and LabView, the convention on output is OME.tiff and Bioformats and for now I don’t see how that can change. but always good to know about alternatives, thanks.
…

Just to get you started…

using JavaCall

try
    # init JVM wtih bioformats_package.jar on classpath
    JavaCall.init(["-ea", "-Xmx1024M", "-Djava.class.path=bioformats_package.jar"])
end

# import java classes
const JChannelFiller = @jimport loci.formats.ChannelFiller
const JChannelSeparator = @jimport loci.formats.ChannelSeparator
const JOMEXMLServiceImpl = @jimport loci.formats.services.OMEXMLServiceImpl
const JOMEXMLMetadata = @jimport loci.formats.ome.OMEXMLMetadata
const JOMEXMLService = @jimport loci.formats.services.OMEXMLService
const JMetadataStore = @jimport loci.formats.meta.MetadataStore

# example of how get_angles function may look like
function get_angles(obj, full_filename)
    ret = []
    try
        # same as `new ChannelFiller()`
        # empty tuple `()` here means that constructor doesn't take any args
        r = JChannelFiller(())

        # same as new ChannelSeparator(r)
        # again, first argument - `(JChannelFiller,)` - a tuple of input types
        # the rest - `r` - is a list of actual arguments
        r = JChannelSeparator((JChannelFiller,), r)

        # same as `new OMEXMLServiceImpl()`
        OMEXMLService = JOMEXMLServiceImpl(())

        # same as `meta = OMEXMLService.createMEXMLMetadata()`
        meta = jcall(OMEXMLService, "createOMEXMLMetadata", JOMEXMLMetadata, ())

        # same as `r.setMetadataStore(meta)`
        jcall(r, "setMetadataStore", Void, (JMetadataStore,), meta)
        ...
    end
end

As you may guess, I know nothing about the domain or BioFormats, so it’s mostly just a hint for you to see how it may look like. Basically, you need to learn how to:

  1. Add .jar files using JavaCall.init()
  2. Import Java classes using @jimport.
  3. Create new objects using constructor syntax, e.g. r = JChannelFiller(()).
  4. Call methods using jcall, e.g. jcall(r, "setMetadataStore", Void, (JMetadataStore,), meta).

So I think it’s pretty doable.

Note that this example requires bioformats_package.jar and some other lib because creating ChannelFiller throws:

ClassNotFoundException: loci.formats.in.SlideBook6Reader

5 Likes

I didn’t mean you should use that function, I just meant there’s a precedent for having a separate function to query metadata (i.e., outside the load/save API of FileIO).

this is superb!!
albeit, when I think about amount of work Sebastien did to design bfMatlab… it’s a lot.

when there is opportunity I’ll try to investigate it further, as it really looks practical.

but, to get it at the same level of convenience, like “bfJulia”, - someone will need to allocate an FTE, possibly in sort of, joint project with Bioformats team? not joking, they may be interested.

may I say Julia community way exceeded my expectations in every topic I pasted.
wow.

many thanks all,
Y.
…

well - then, could FileIO be a place for bfJulia?
I would like it. :slight_smile:
…

Or a BioFormats.jl could extend FileIO

I used bfMatlab in many places and it is always pleasure.
opens every murky proprietary microscope format.
I think Melissa Linkert who is in charge of Bioformats, deserves a Damehood for this work. :sunglasses:
not joking again.
already quite Kantian, but still not a meritocracy.
…