Accessing OMERO from macros

Good evening!

This morning there was a talk about using OMERO from IJ1 macros.
So I tried to play a bit with it (starting from our wrapper library), and I got to this:

package fr.igred.omero;


import fr.igred.omero.exception.AccessException;
import fr.igred.omero.exception.ServiceException;
import fr.igred.omero.repository.DatasetWrapper;
import fr.igred.omero.repository.ImageWrapper;
import fr.igred.omero.repository.ProjectWrapper;
import fr.igred.omero.roi.ROIWrapper;
import ij.IJ;
import ij.ImagePlus;
import ij.gui.Roi;
import ij.macro.ExtensionDescriptor;
import ij.macro.Functions;
import ij.macro.MacroExtension;
import ij.plugin.PlugIn;
import ij.plugin.frame.RoiManager;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;


public class Client_Extensions implements PlugIn, MacroExtension {

    private final Client client = new Client();

    private ExtensionDescriptor[] extensions = {
            ExtensionDescriptor.newDescriptor("connectToOMERO", this, ARG_STRING, ARG_NUMBER, ARG_STRING, ARG_STRING),
            ExtensionDescriptor.newDescriptor("listProjects", this, ARG_OUTPUT + ARG_STRING),
            ExtensionDescriptor.newDescriptor("getProjectName", this, ARG_NUMBER, ARG_OUTPUT + ARG_STRING),
            ExtensionDescriptor.newDescriptor("listDatasetsInProject", this, ARG_NUMBER, ARG_OUTPUT + ARG_STRING),
            ExtensionDescriptor.newDescriptor("getDatasetName", this, ARG_NUMBER, ARG_OUTPUT + ARG_STRING),
            ExtensionDescriptor.newDescriptor("listImagesInDataset", this, ARG_NUMBER, ARG_OUTPUT + ARG_STRING),
            ExtensionDescriptor.newDescriptor("getImageName", this, ARG_NUMBER, ARG_OUTPUT + ARG_STRING),
            ExtensionDescriptor.newDescriptor("getImage", this, ARG_NUMBER),
            ExtensionDescriptor.newDescriptor("getImageWithROIs", this, ARG_NUMBER),
            ExtensionDescriptor.newDescriptor("disconnect", this),
            };


    public void run(String arg) {
        if (!IJ.macroRunning()) {
            IJ.error("Cannot install extensions from outside a macro!");
            return;
        }
        Functions.registerExtensions(this);
    }


    public ExtensionDescriptor[] getExtensionFunctions() {
        return extensions;
    }


    public String handleExtension(String name, Object[] args) {
        if (name.equals("connectToOMERO")) {
            String host     = ((String) args[0]);
            int    port     = ((Double) args[1]).intValue();
            String username = ((String) args[2]);
            String password = ((String) args[3]);
            try {
                client.connect(host, port, username, password);
            } catch (ServiceException | ExecutionException e) {
                IJ.log("Could not connect: " + e.getMessage());
            }
        } else if (name.equals("listProjects")) {
            try {
                List<ProjectWrapper> projects = client.getProjects();
                StringBuilder        ids      = new StringBuilder();
                for (ProjectWrapper project : projects) {
                    if (!ids.toString().equals("")) {
                        ids.append(",");
                    }
                    ids.append(project.getId().toString());
                }
                ((String[]) args[0])[0] = ids.toString();
            } catch (ServiceException | AccessException e) {
                IJ.log("Could not retrieve projects: " + e.getMessage());
            }
        } else if (name.equals("getProjectName")) {
            try {
                ProjectWrapper project = client.getProject(((Double) args[0]).longValue());
                ((String[]) args[1])[0] = project.getName();
            } catch (ServiceException | AccessException e) {
                IJ.log("Could not retrieve project name: " + e.getMessage());
            }
        } else if (name.equals("listDatasetsInProject")) {
            try {
                ProjectWrapper       project  = client.getProject(((Double) args[0]).longValue());
                List<DatasetWrapper> datasets = project.getDatasets();
                StringBuilder        ids      = new StringBuilder();
                for (DatasetWrapper dataset : datasets) {
                    if (!ids.toString().equals("")) {
                        ids.append(",");
                    }
                    ids.append(dataset.getId().toString());
                }
                ((String[]) args[1])[0] = ids.toString();
            } catch (ServiceException | AccessException e) {
                IJ.log("Could not retrieve datasets: " + e.getMessage());
            }
        } else if (name.equals("getDatasetName")) {
            try {
                DatasetWrapper dataset = client.getDataset(((Double) args[0]).longValue());
                ((String[]) args[1])[0] = dataset.getName();
            } catch (ServiceException | AccessException e) {
                IJ.log("Could not retrieve dataset name: " + e.getMessage());
            }
        } else if (name.equals("listImagesInDataset")) {
            try {
                DatasetWrapper     dataset = client.getDataset(((Double) args[0]).longValue());
                List<ImageWrapper> images  = dataset.getImages(client);
                StringBuilder      ids     = new StringBuilder();
                for (ImageWrapper image : images) {
                    if (!ids.toString().equals("")) {
                        ids.append(",");
                    }
                    ids.append(image.getId().toString());
                }
                ((String[]) args[1])[0] = ids.toString();
            } catch (ServiceException | AccessException e) {
                IJ.log("Could not retrieve images: " + e.getMessage());
            }
        } else if (name.equals("getImageName")) {
            try {
                ImageWrapper image = client.getImage(((Double) args[0]).longValue());
                ((String[]) args[1])[0] = image.getName();
            } catch (ServiceException | AccessException e) {
                IJ.log("Could not retrieve image name: " + e.getMessage());
            }
        } else if (name.equals("getImage")) {
            try {
                ImageWrapper image = client.getImage(((Double) args[0]).longValue());
                ImagePlus imp = image.toImagePlus(client);
                imp.show();
            } catch (ServiceException | AccessException | ExecutionException e) {
                IJ.log("Could not retrieve image: " + e.getMessage());
            }
        } else if (name.equals("getImageWithROIs")) {
            try {
                ImageWrapper image = client.getImage(((Double) args[0]).longValue());
                ImagePlus imp = image.toImagePlus(client);
                imp.show();
                List<ROIWrapper> rois = image.getROIs(client);
                List<Roi> ijRois = new ArrayList<>();
                int index = 0;
                for(ROIWrapper roi : rois) {
                    List<Roi> shapes = roi.toImageJ();
                    for(Roi r : shapes) {
                        r.setProperty("INDEX", String.valueOf(index));
                        if(rois.size() < 255) {
                            r.setGroup(index);
                        }
                    }
                    ijRois.addAll(shapes);
                    index++;
                }
                RoiManager rm = RoiManager.getRoiManager();
                for(Roi roi : ijRois) {
                    rm.addRoi(roi);
                }
            } catch (ServiceException | AccessException | ExecutionException e) {
                IJ.log("Could not retrieve image with ROIs: " + e.getMessage());
            }
        } else if (name.equals("disconnect")) {
            client.disconnect();
        }

        return null;
    }


}

It’s rudimentary, as it only allows to connect, list basic objects (projects, datasets, images), and retrieve images with their (5D) ROIs. I guess putting every OMERO functionality in macro language would be quite cumbersome…
Retrieving a list of IDs is also kind of limited, as arrays can’t be returned from macro extensions.

Anyway, if someone wants to try it, here it is:
OMERO-Macros.zip (70.9 KB)
(To keep the file lightweight, the JAR inside the ZIP does not include the dependencies and so requires the OMERO plugin. There’s an example macro as well.)

3 Likes

Very interesting!

Is there a reference to this talk?

Hi @phaub. This was during the Q&A of @stoffelc’s OMERO/BDV demo, I think. We’re still getting the videos uploaded from the first day of #ome2021, but we’ll keep you posted.

~Josh

2 Likes

Hi @phaub. The video mentioned by @pierre.pouchin and @joshmoore is not available at OME2021 | Claire Stoffel | Connector between OMERO and the BigDataViewer - YouTube - the discussion mentioned by @pierre.pouchin is captured at 19:30 of that video (it is only related to the topic of the video, actually it is a new topic emerging during the follow-up discussion)

All the best

Petr

4 Likes