Using a plugin called BaSiC with pyimagej

Hello,

I would like to use the plugin called BaSiC within some python code that I’m writing. I’ve been going through the pyimagej and imagej API tutorial notebooks (I had never used either before and I’m not good with java so it’s slow progress!) but I’m starting to be uncertain that it will be possible to use BaSiC with pyimagej at all… for example, I wasn’t able to find BaSiC on maven and I saw some other discussions here where that seemed to be important (for other plugins).

I manage to setup an imagej gateway using my local Fiji installation (which has BaSiC installed) but I don’t get much further than that:

import imagej
ij = imagej.init(r"C:\Users\Tom\fiji-win64\Fiji.app",headless=False)
plugin = "BaSiC"
args = {}
ij.py.run_plugin(plugin,args)

gives the error:

Unrecognised command: "BaSiC" in line 1

So my question before I invest a lot of time into understanding the API is: will it be possible (=reasonably simple) to use BaSiC through pyimagej?

Thanks in advance for any help and sorry for a question that is probably very naive!

Hi Tom,

Here is how we setup to call BaSiC. It took a bit to figure out, because we were not able to call BaSiC in headless mode. We ended up launching an interactive ImageJ session, passing the image from Python to Java, and displaying the image. We found we had to re-order the image stack when it is passed from Python to Java. We then execute macros to run BaSiC and transfer the calculated flatfield and darkfield images back to Python from Java.

We are not experts, so this may not be “best” practice!! But it works for us,.

We actually call BaSiC in a set of helper functions as part of a larger routine. I tried to flatten it here to make it a script. This script assumes you have a variable called image that contains your image in Python ordering.

import imagej
import scyjava
from scyjava import jimport
import numpy as np # not used here, but we do call numpy in our code.
from pathlib import Path

# open pyimagej in interactive mode because BaSiC flat-fielding plugin cannot run in headless mode
scyjava.config.add_option('-Xmx12g')
plugins_dir = Path('/path/to/Fiji.app/plugins')
scyjava.config.add_option(f'-Dplugins.dir={str(plugins_dir)}')
ij_path = Path(''/path/to/Fiji.app')
ij = imagej.init(str(ij_path), headless=False)
ij.ui().showUI()

# convert dataset from numpy -> java
image_iterable = ij.op().transform().flatIterableView(ij.py.to_java(image)

# show image in imagej since BaSiC plugin cannot be run headless
ij.ui().show(image_iterable)
WindowManager = jimport('ij.WindowManager')
current_image = WindowManager.getCurrentImage()

# convert virtual stack to real stack and reorder for BaSiC
macro = """
rename("active")
run("Duplicate...", "duplicate")
selectWindow("active")
run("Close")
selectWindow("active-1")
run("Re-order Hyperstack ...", "channels=[Slices (z)] slices=[Channels (c)] frames=[Frames (t)]")
"""
ij.py.run_macro(macro)

# run BaSiC plugin
plugin = 'BaSiC '
args = {'processing_stack': 'active-1','flat-field': 'None','dark-field': 'None', 'shading_estimation': '[Estimate shading profiles]', 'shading_model': '[Estimate both flat-field and dark-field]', 'setting_regularisationparametes': 'Automatic', 'temporal_drift': '[Ignore]', 'correction_options': '[Compute shading only]', 'lambda_flat': 0.5, 'lambda_dark': 0.5}
ij.py.run_plugin(plugin, args)

# grab flat-field image, convert from java->numpy
macro2 = """
selectWindow("active-1")
run("Close")
selectWindow("Flat-field:active-1")
"""
ij.py.run_macro(macro2)
current_image = WindowManager.getCurrentImage()
flat_field_ij = ij.py.from_java(current_image)
flat_field = flat_field_ij.data

# close flat-field, grab dark-field image, convert from java->numpy
macro3 = """
selectWindow("Flat-field:active-1")
run("Close")
selectWindow("Dark-field:active-1")
"""
ij.py.run_macro(macro3)

current_image = WindowManager.getCurrentImage()
dark_field_ij = ij.py.from_java(current_image)
dark_field = dark_field_ij.data

# close dark-field image
macro4 = """
selectWindow("Dark-field:active-1")
run("Close")
run("Collect Garbage")
"""
ij.py.run_macro(macro4)

del image_iterable

 # shut down pyimagej
ij.getContext().dispose()

You now should have the flatfield and darkfield corrections as Python variables and can calculate the corrected image on your own.

One outstanding issue we have not solved is that our Python code doesn’t correctly exit when we launch ImageJ in interactive mode. We output an diagnostic to the command line when our (very) long image processing code finishes so that we can safely stop the Python process. It would be great to find a solution to that issue. I’m sure we are doing something incorrectly, but it isn’t clear what from the documentation.

Hi Doug, thanks so much for this, it works perfectly! The exiting problem isn’t an issue for me, but I’ll post here if I find a solution. Thanks again, it would have taken me weeks to work all that out!

No problem! Glad it works.