Best way imageJ to open an ImagePlus from OMERO using Bioformats

Ah, thats where i went wrong, I now get the context from imageJ and it all works out.

Now managing to get the omero files imported and not showing up.
Thanks for the help.

1 Like

Hi @Joost_Willemse1 and @ctrueden,

that sounds great, I’ve been looking for better way to access images from OMERO. I’m having trouble getting the solution to work. Could you please share a minimal working example as suggested by ctrueden above?

Following ctrueden’s advice above, I can generate a context using:

from net.imagej import ImageJ

ij =  ImageJ()
context = ij.context()

for service in  context.getServiceIndex():
	ident = service.identifier
	print(ident)

I can see the list of services but I can’t see anything related to OMERO in there. I hav the OMERO plugin installed and can connect using the plugin and from scripts using using omero.gateway. is there something I need to do install the OMERO service?

If I have the OMERO service running, from the context javadoc it looks like the only way to get the service would be like

omero_class string = "net.imagej.omero.OMEROService"  # Not sure about this
context.service( omero_class_string )

as the OMEROService class can’t be imported?

Thanks,

Chris

List of services

Started ij2_method.py at Wed Feb 05 09:26:25 AEDT 2020
plugin:org.scijava.event.DefaultEventService
plugin:net.imagej.legacy.display.LegacyImageDisplayService
plugin:net.imagej.lut.DefaultLUTService
plugin:net.imagej.legacy.LegacyService
plugin:fiji.DefaultFijiService
plugin:io.scif.DefaultMetadataService
plugin:io.scif.codec.DefaultCodecService
plugin:io.scif.formats.qt.DefaultQTJavaService
plugin:io.scif.formats.tiff.DefaultTiffService
plugin:io.scif.gui.DefaultGUIService
plugin:io.scif.img.DefaultImgUtilityService
plugin:io.scif.img.converters.DefaultPlaneConverterService
plugin:io.scif.io.DefaultNIOService
plugin:io.scif.ome.services.DefaultOMEMetadataService
plugin:io.scif.ome.services.DefaultOMEXMLService
plugin:io.scif.refs.DefaultRefManagerService
plugin:io.scif.services.DefaultDatasetIOService
plugin:io.scif.services.DefaultFilePatternService
plugin:io.scif.services.DefaultFormatService
plugin:io.scif.services.DefaultLocationService
plugin:io.scif.services.DefaultTranslatorService
plugin:io.scif.services.JAIIIOServiceImpl
plugin:io.scif.xml.DefaultXMLService
plugin:net.imagej.DefaultDatasetService
plugin:net.imagej.DefaultImgPlusService
plugin:net.imagej.animation.DefaultAnimationService
plugin:net.imagej.autoscale.DefaultAutoscaleService
plugin:net.imagej.display.DefaultImageDisplayService
plugin:net.imagej.display.DefaultOverlayService
plugin:net.imagej.display.DefaultWindowService
plugin:net.imagej.display.DefaultZoomService
plugin:net.imagej.legacy.plugin.MacroExtensionAutoCompletionService
plugin:net.imagej.measure.DefaultMeasurementService
plugin:net.imagej.measure.DefaultStatisticsService
plugin:net.imagej.notebook.DefaultImageJNotebookService
plugin:net.imagej.notebook.DefaultNotebookService
plugin:net.imagej.operator.DefaultCalculatorService
plugin:net.imagej.ops.DefaultNamespaceService
plugin:net.imagej.ops.DefaultOpMatchingService
plugin:net.imagej.ops.DefaultOpService
plugin:net.imagej.roi.DefaultROIService
plugin:net.imagej.sampler.DefaultSamplerService
plugin:net.imagej.table.DefaultTableService
plugin:net.imagej.threshold.DefaultThresholdService
plugin:net.imagej.types.DefaultDataTypeService
plugin:net.imagej.ui.DefaultImageJUIService
plugin:net.imagej.ui.awt.AWTRenderingService
plugin:net.imagej.ui.awt.AWTScreenCaptureService
plugin:net.imagej.ui.swing.ops.DefaultOpFinderService
plugin:net.imagej.ui.swing.overlay.JHotDrawService
plugin:net.imagej.units.DefaultUnitService
plugin:net.imagej.updater.DefaultUpdateService
plugin:net.imagej.updater.DefaultUploaderService
plugin:org.scijava.app.DefaultAppService
plugin:org.scijava.app.DefaultStatusService
plugin:org.scijava.command.DefaultCommandService
plugin:org.scijava.console.DefaultConsoleService
plugin:org.scijava.convert.DefaultConvertService
plugin:org.scijava.display.DefaultDisplayService
plugin:org.scijava.download.DefaultDownloadService
plugin:org.scijava.event.DefaultEventHistory
plugin:org.scijava.input.DefaultInputService
plugin:org.scijava.io.DefaultIOService
plugin:org.scijava.io.DefaultRecentFileService
plugin:org.scijava.io.handle.DefaultDataHandleService
plugin:org.scijava.io.location.DefaultLocationService
plugin:org.scijava.io.nio.DefaultNIOService
plugin:org.scijava.jupyter.service.DefaultJupyterService
plugin:org.scijava.main.DefaultMainService
plugin:org.scijava.menu.DefaultMenuService
plugin:org.scijava.module.DefaultModuleService
plugin:org.scijava.notebook.DefaultNotebookService
plugin:org.scijava.object.DefaultObjectService
plugin:org.scijava.options.DefaultOptionsService
plugin:org.scijava.parse.DefaultParseService
plugin:org.scijava.platform.DefaultPlatformService
plugin:org.scijava.plugin.DefaultPluginService
plugin:org.scijava.prefs.DefaultPrefService
plugin:org.scijava.run.DefaultRunService
plugin:org.scijava.script.DefaultScriptHeaderService
plugin:org.scijava.script.DefaultScriptService
plugin:org.scijava.script.process.DefaultScriptProcessorService
plugin:org.scijava.search.DefaultSearchService
plugin:org.scijava.search.javadoc.DefaultJavadocService
plugin:org.scijava.startup.DefaultStartupService
plugin:org.scijava.task.DefaultTaskService
plugin:org.scijava.text.DefaultTextService
plugin:org.scijava.thread.DefaultThreadService
plugin:org.scijava.tool.DefaultToolService
plugin:org.scijava.ui.DefaultUIService
plugin:org.scijava.ui.dnd.DefaultDragAndDropService
plugin:org.scijava.ui.swing.SwingIconService
plugin:org.scijava.ui.swing.script.DefaultLanguageSupportService
plugin:org.scijava.welcome.DefaultWelcomeService
plugin:org.scijava.widget.DefaultWidgetService
plugin:sc.fiji.compat.DefaultFijiService
plugin:sc.iview.DefaultSciViewService
plugin:io.scif.services.DefaultInitializeService
plugin:net.imagej.display.DummyScreenCaptureService
plugin:net.imagej.render.DummyRenderingService
plugin:org.scijava.batch.FileBatchService
plugin:org.scijava.log.StderrLogService
plugin:org.scijava.platform.DefaultAppEventService
plugin:org.scijava.cache.DefaultCacheService

Ok, i threw out all the code making it more complicated and ended up with these 50 lines to get my image displayed

import ij.IJ;
import ij.ImagePlus;
import omero.gateway.Gateway;
import omero.gateway.LoginCredentials;
import omero.log.SimpleLogger;
import net.imagej.omero.*;
import net.imagej.Dataset;
import net.imagej.ImageJ;
import net.imagej.ImgPlus;
import omero.client;
import net.imglib2.img.imageplus.ImagePlusImg;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imagej.omero.legacy.LegacyOMEROService;
import org.scijava.Context;

public class getOmeroDatasetSuperMinimal {
    private String Username = "Username";
    private static String HOST = "server";
    private static int PORT = 4064;
    private String Password = "password";
	private long imageId=imageid;

    public void getDatasetImages() {
        Gateway gateway = null;
        try {
			LoginCredentials credentials = new LoginCredentials(Username,Password,HOST,PORT);
        	SimpleLogger simpleLogger = new SimpleLogger();
       		gateway = new Gateway(simpleLogger);
        	gateway.connect(credentials);
        	OMEROLocation ol = new OMEROLocation(HOST,PORT,Username,Password);
			ImageJ ij = new ImageJ();
			Context context = ij.context();
			OMEROService dos = context.service(OMEROService.class);
			OMEROSession os = dos.createSession(ol);
			client cl = os.getClient();
            Dataset d = dos.downloadImage(cl,imageId);
            ImgPlus implu=d.getImgPlus();
            ImageJFunctions.show(implu.getImg());
        } catch (Exception e) {
            IJ.showMessage("An error occurred while loading the image.");
        } finally {
            if (gateway != null) gateway.disconnect();
        }
    }
// used for testing when running the plugin stand alone
    public static void main(String[] args) {
    	getOmeroDatasetSuperMinimal om = new getOmeroDatasetSuperMinimal();
        om.getDatasetImages();
    }
}

As usual, i get into the next issue,

I can only open images from the default group. No idea why that would be, any suggestions?

@evenhuis From your list of services, it looks like you are running Fiji. So you probably don’t have the net.imagej:imagej-omero and net.imagej:imagej-omero-legacy artifacts on your classpath? Did you enable the OMERO update site?

From your script, it looks like you are using Jython? Are you running that from inside Fiji’s Script Editor? If so, do not make a new ImageJ() object, but instead use script parameters:

#@ OMEROService omeroService
omeroService.doAllTheThings()

@Joost_Willemse1 I’ll have to defer to the @ome team (@OMETeam?) on that one. But I’m guessing it’s related to the group context of the OMERO connection. Changes might be needed to ImageJ-OMERO to make this work better—if so, please let me know. (And PRs warmly welcomed!)

1 Like

@Joost_Willemse1 Yes, thank you, you are completely right about the default group. Our scripts, such as https://github.com/ome/training-scripts/blob/master/practical/groovy/open_image_after_download.groovy will not open an image from non-default group. We will follow-up on this and deliver a better answer soon, with some more concrete suggestion about how to manage the group context.

All the best
Petr

OME Team

Hi @Joost_Willemse1 ,

I’m not an expert, but this how I’ve handled group changes in Omero. This assumes you’ve logged in created the gateway.

Once you have the security ctx and in the imageID I open it with browse.getImage(ctx, image_id).

Cheers,

Chris

user=gateway.getLoggedInUser()				

	
# create a browse Facility service 
from omero.gateway.facility import BrowseFacility
browse = gateway.getFacility(BrowseFacility)

# get the list of groups
groups = user.getGroups()

# some boring code here to select one of the groups
# .....  snip ..
group = groups[ iselected ]

# create a security context for this group (changes from default)
from omero.gateway import SecurityContext
ctx = SecurityContext( group.getId() )

# get a list of projects and screens
# I had to treat the default group different, not sure why exactly
params = ParametersI()		
if( groups[igroup].getName()=='default'):
	projects=browse.getHierarchy(ctx, ProjectData, user.getId())
	screens =browse.getHierarchy(ctx, ScreenData, user.getId())
else:
	projects=browse.getHierarchy(ctx,ProjectData,[],params)		
	screens =browse.getHierarchy(ctx,ScreenData, [],params)	

# boring code to select a project
# ... snip ...
project = projects[iproject]
datasets = projects.getDatasets()

# boring code to select a dataset
# .. snip ...
dataset = datasets[idataset]
images = browse.getImagesForDatasets(ctx,[Long(datasets[i_data].getId())]) 

Nevermind, issue still not solved, though i thought so for a sec

Hi @Joost_Willemse1,

I’ve adapted one of the solution from higher up in the thread. I’m sure this the wrong way to go about it as

  • this is a very manual process that belongs in a proper library
  • it is in hacked together Jython
  • it doesn’t get the calibration, LUTs or image metadata yet
  • it is very much old-school imageJ,1 rather than the new hotness of SciJava, imglib, IJ2, Abstract Service Provider etc

But it is best solution I’ve found so far. My wish list is to be able to:

  • Limit the range of X,Y,T,C,Z, resolution pyramid or fields of view. We have some 50GB image files so any approach that downloads the raw image file is out of the question
  • Doesn’t open the image. I’d rather just get the ImagePlus object or whatever it’s called in IJ2.
  • Read/write metadata in OMERO like key-values pairs and tables
  • Access all the groups the user is a member of.

Hope it helps. Let me know if you’d me to put it up on GitHub.

Cheers,

Chris


def open_omero_image(gateway, ctx, image_id ):
	from omero.gateway.facility import BrowseFacility
	browse = gateway.getFacility(BrowseFacility)
    
	image = browse.getImage(ctx, image_id)	
	pixels = image.getDefaultPixels()
	size_z = pixels.getSizeZ()
	size_t = pixels.getSizeT()
	size_c = pixels.getSizeC()
	size_x = pixels.getSizeX()
	size_y = pixels.getSizeY()

	
	pixtype = pixels.getPixelType()
	from loci.formats import FormatTools
	pixels_type = FormatTools.pixelTypeFromString(pixtype)
	bpp = FormatTools.getBytesPerPixel(pixels_type)

	is_signed = FormatTools.isSigned(pixels_type)
	is_float = FormatTools.isFloatingPoint(pixels_type)
	is_little = False
	interleave = False

	# setup the pixelStore
	store = gateway.getPixelsStore(ctx)
	pixels_id = pixels.getId()
	store.setPixelsId(pixels_id, False)

	from ij import IJ
	imp   = IJ.createHyperStack("tmp",size_x,size_y,size_c,size_z,size_t,bpp*8)
	stack = imp.getImageStack()
	

	from loci.formats import ImageTools
	from loci.common import DataTools
	from ij.process import ByteProcessor, ShortProcessor, FloatProcessor
	from java.lang import Short
	
	for t in range(size_t):
		for z in range(size_z):
			for c in range(size_c):
				
				n = imp.getStackIndex(c+1,z+1,t+1)
				print(t,z,c,n)
				plane = store.getPlane(z, c, t)
				ImageTools.splitChannels(plane, 0, 1, bpp, False, interleave)
				pixels = DataTools.makeDataArray(plane, bpp, is_float, is_little)	
				
				ip = stack.getProcessor(n)
				ip.setPixels(pixels)
				stack.setProcessor(ip,n)
				
	imp.setStack(stack)
	store.close()

	imp.setOpenAsHyperStack(True)
	from ij import IJ
	imp.setDisplayMode(IJ.COMPOSITE)

	return imp

Ok, after some more fiddling i really solved it now.

The trick is to connect via a gateway,
read out in which group the image is located,
Then reconnect with changed credentials (new groupId)
and then the images load like you want to

public void getDatasetImages() {
        Gateway gateway = null;
        try {
			LoginCredentials credentials = new LoginCredentials(Username,Password,HOST,PORT);
        	SimpleLogger simpleLogger = new SimpleLogger();
       		gateway = new Gateway(simpleLogger);
        	gateway.connect(credentials);
        	ExperimenterData ed = gateway.getLoggedInUser();
        	List<GroupData> grda= ed.getGroups();
        	
        	//This is the way to get via browsefacility, can be opened with 
        	 //* 
        	BrowseFacility browser = gateway.getFacility(BrowseFacility.class);
        	Iterator<GroupData> gidit=grda.iterator();
        	int counter =0;
        	ImageData id =null;
        	IJ.log("ngroups "+grda.size()); 
        	while (gidit.hasNext() && id==null){
	        	try {
	        		SecurityContext ctx = new SecurityContext(grda.get(counter).getGroupId());
	        		id = browser.getImage(ctx, imageId);
	        		credentials.setGroupID(ctx.getGroupID());
	        		gateway.connect(credentials);
	        	} catch (Exception e){
	        		//IJ.showMessage("Image not found in group " +grda.get(counter).getGroupId());
	        	}
	        	counter++;
        	}
        	if (id==null) {
        		IJ.showMessage("Image not found");
        		return;
        	}
        	ImageJ ij = new ImageJ();
        	Context context = ij.getContext();
        	OMEROService dos = context.service(OMEROService.class);
        	OMEROLocation ol = new OMEROLocation(HOST,PORT,Username,Password);
        	OMEROSession os = dos.createSession(ol);	
			client cl = os.getClient();
            Dataset d = dos.downloadImage(cl,imageId);
            ImgPlus implu=d.getImgPlus();
           	ImagePlus imp = ImageJFunctions.wrap(implu,"My desired imageplus");
           	imp.show();
        } catch (Exception e) {
        	IJ.log(e.getMessage());
        	StackTraceElement[] t = e.getStackTrace();
        	for (int i=0;i<t.length;i++){
        		IJ.log(t[i].toString());
        	}
            IJ.showMessage("An error occurred while loading the image.");
        } finally {
            if (gateway != null) gateway.disconnect();
        }
    }
1 Like

Hi Joost

As mentioned (and tested) you can change the context using the OMERO java gateway
You cannot do that using imagej-omero.
Glad you managed to find a workaround. This is not ideal but at least you could move forward.

Cheers
Jmarie

Hi @ctrueden,

OMERO through the update site

When I enable the OMERO 5.4 site from the update section I can see the libraries.

But it breaks the connection to OMERO. Attempts to connect result in the following:

    reason = "IceSSL: handshake error"
	at IceInternal.AsyncResultI.__wait(AsyncResultI.java:276)
	at Ice.ObjectPrxHelperBase.end_ice_isA(ObjectPrxHelperBase.java:310)
	at Ice.ObjectPrxHelperBase.ice_isA(ObjectPrxHelperBase.java:92)
	at Ice.ObjectPrxHelperBase.ice_isA(ObjectPrxHelperBase.java:69)
	at Ice.ObjectPrxHelperBase.checkedCastImpl(ObjectPrxHelperBase.java:2810)
	at Ice.ObjectPrxHelperBase.checkedCastImpl(ObjectPrxHelperBase.java:2770)
	at Glacier2.RouterPrxHelper.checkedCast(RouterPrxHelper.java:1787)
	at omero.client.getRouter(client.java:802)
	at omero.client.createSession(client.java:723)
	at net.imagej.omero.DefaultOMEROSession.<init>(DefaultOMEROSession.java:114)
	at net.imagej.omero.DefaultOMEROSession.<init>(DefaultOMEROSession.java:85)
	at net.imagej.omero.DefaultOMEROService.createSession(DefaultOMEROService.java:890)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Del

This happens for the IJ2 approach and for other approaches listed above (which I’ll call IJ1). The error for the IJ1 approach is similar:

    reason = "IceSSL: handshake error"
	at IceInternal.AsyncResultI.__wait(AsyncResultI.java:276)
	at Ice.ObjectPrxHelperBase.end_ice_isA(ObjectPrxHelperBase.java:310)
	at Ice.ObjectPrxHelperBase.ice_isA(ObjectPrxHelperBase.java:92)
	at Ice.ObjectPrxHelperBase.ice_isA(ObjectPrxHelperBase.java:69)
	at Ice.ObjectPrxHelperBase.checkedCastImpl(ObjectPrxHelperBase.java:2810)
	at Ice.ObjectPrxHelperBase.checkedCastImpl(ObjectPrxHelperBase.java:2770)
	at Glacier2.RouterPrxHelper.checkedCast(RouterPrxHelper.java:1787)
	at omero.client.getRouter(client.java:802)
	at omero.client.createSession(client.java:723)
	at omero.gateway.Gateway.createSession(Gateway.java:1054)
	at omero.gateway.Gateway.connect(Gateway.java:259)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

I have the omero-ij plugin manually installed from the download section on the OME page - our OMERO version is 5.4.9-ice36-b101. So I tried all the combinations

OMERO 5.4 update OMERO manual IJ2 method IJ1 method
:black_circle: :x: IceSSL :x: IceSSL
:black_circle: :x: no Service :white_check_mark:
:black_circle: :black_circle: :x: IceSSL :x: IceSSL
  • Does the OMERO 5.4 instal through update site clash with a manually installed OMERO plugin?

Script parameters

Beyond simple scripts, I’ve not had much success with script parameters. When I refactor and call functions from modules / libraries the script parameter magic doesn’t work. Is this right?

Anyway, my I’d like the option to explicitly do what the script parameter magic is doing. Is there a place the code can see what the script parameters are doing?

Cheers,

Chris

Hi Chris

For OMERO 5.4 it should not clash.
We certainly had to make changes in newer version of OMERO (5.5. and 5.6) to work.

Have you tried to modify the system property jdk.tls.disabledAlgorithms
and remove the anon from the list
something like that

property = "jdk.tls.disabledAlgorithms"
value = Security.getProperty(property)
if (!(value == null || value.trim().isEmpty())) {
	algorithms = new ArrayList();
	isChanged = false;
	for (algorithm in value.split(",")) {
		algorithm = algorithm.trim();
		if (algorithm.isEmpty()) {
					/* ignore */
		} else if ("anon".equals(algorithm.toLowerCase())) {
			isChanged = true;
		} else {
			algorithms.add(algorithm);
		}
	}
	if (isChanged) {
		needsComma = false;
		newValue = new StringBuilder();
		for (algorithm in algorithms) {
			if (needsComma) {
				newValue.append(", ");
			} else {
				needsComma = true;
			}
			newValue.append(algorithm);
		}
		Security.setProperty(property, newValue.toString());
	}
}```
and see if it solved the issue

Cheers

Jmarie
1 Like

If you have script functions you want to use in library fashion, make the functions accept the needed services as arguments. And then pass them from your top-level scripts. And the top-level scripts can use script parameters to receive the from the framework.

Here is a hack to obtain the SciJava Context object currently in use, and then ask for the associated OMEROService from there:

Context ctx = (Context) IJ.runPlugIn("org.scijava.Context", "");
OMEROService omeroService = ctx.service(OMEROService.class);

This will work when executing code from within ImageJ/Fiji, when imagej-legacy is on the classpath.

This code will not work if:

  • You run from outside ImageJ—e.g. using the jython command line tool.
  • You run ImageJ without image-legacy on the classpath.
  • You instantiate a net.imagej.ImageJ gateway without including the LegacyService.
  • You instantiate multiple SciJava contexts.

But in the common case of running Fiji as a desktop application, or from the CLI, it should do the trick. But in that case, script parameters will also work from the top-level script. So the hack is not really necessary…

Thank you for posting that! Very helpful to understand what you tried.

I believe it is OK, based on a recent thread here:

However, I am not sure what, if anything, the OME team has uploaded to those OMERO-5.x update sites, as of this writing. Their primary purpose was to ship the ImageJ-OMERO extension, but then in the thread linked above, we were discussing also shipping the OMERO.insight-ij plugin as well. It would be awesome if the OME team could provide more details by expanding the stub page at:

We have not updated anything yet to the OMERO 5.x
After @ctrueden created it, we encountered an ssl issue (fixed) and focused on 5.6 upgrade.
We should now be able to push a version of OMERO.insight-ij plugin compatible with OMERO 5.5 and 5.6 server
The ImageJ-OMERO extension will also have to be updated.
I will hopefully have time next week to look into that

Cheers
Jmarie

A post was split to a new topic: Updating ImageJ-OMERO for OMERO 5.5 and 5.6

A post was split to a new topic: Loading images with imagej-omero

A post was split to a new topic: How to get all ImageIDs for a dataset via imagej-omero

For those awaiting the new ImageJ-OMERO: you can follow this issue:

I’ll be out for the next four weeks, but will try to complete it upon my return in October.

2 Likes

A post was split to a new topic: Imagej-omero isn’t working with scifio 0.41.0