imagej / pyimagej

Use ImageJ from Python
https://pyimagej.readthedocs.io/
Other
473 stars 82 forks source link

Plugins not found on MacOS #22

Closed NoahDolev closed 3 years ago

NoahDolev commented 5 years ago

Hi,

I have successfully setup and used Py ImageJ. However, I am not able to call upon any of the numerous plugins from python.

from skimage import io
import cv2
import os
import imagej
ij = imagej.init('<my-local-path>/Fiji.app')
import imglyb
from PIL import Image

Returns:

Added 375 JARs to the Java classpath.

However, when I attempt to run a Macro:

def improve_raw(impath):
    macro = """open("{}");
               run("Normalize Local Contrast", "block_radius_x=40 block_radius_y=40 standard_deviations=3 center stretch");
               run("Enhance Local Contrast (CLAHE)", "blocksize=127 histogram=256 maximum=3 mask=*None*");
               run("Gaussian Blur 3D...", "x=2 y=2 z=2");
               saveAs("TIFF", "{}");""".format(impath, impath.replace("Tiff_masks", "Tiff_masks_cleaned"))
    ij.script().run('Macro.ijm', macro, True).get()
    return(1)

I receive the following error message:

Unrecognized command: "Normalize Local Contrast"

The macro successfully runs from within ImageJ. Any idea why the same macro doesn't work from within Python?

Thanks.

Best, Noah

ctrueden commented 5 years ago

@NoahDolev Thanks for the report!

I dug into this. Calling ImageJ1-based plugins can present some challenges, depending on the plugin. ImageJ1 was not designed to work outside of the usual ImageJ application. We do our best to enable ImageJ1 code to work in a wider variety of ways, but there are still some limits.

Firstly: I cannot reproduce the "Unrecognized command" errors. This message suggests that maybe your plugins.dir is somehow not set as it should be. What does the following script report?

plugins-dir.py ```python import imagej ij = imagej.init('/path/to/Fiji.app') from jnius import autoclass System = autoclass('java.lang.System') plugins_dir = System.getProperty('plugins.dir') print(plugins_dir) ```

It should print e.g. /Applications/Fiji.app/plugins if your installation is /Applications/Fiji.app.

Secondly: there are several issues with the particular plugins you are trying to use:

CLAHE

This plugin cannot work headless, because of this code. It will throw an exception if you try.

Here is some Python code the reproduces the issue:

clahe-fail.py ```python import imagej ij = imagej.init('/path/to/Fiji.app') import jnius, numpy from scyjava import jclass ImagePlusClass = jclass('ij.ImagePlus') # Define a function for converting image to ImagePlus. def to_imp(image): image = ij.py.to_java(image) if ImagePlusClass.isInstance(image): return image dataset = ij.dataset().create(image) # dataset = ij.py.to_dataset(image) return ij.convert().convert(dataset, ImagePlusClass) # Create a test image. img = numpy.zeros([10, 10]) imp = to_imp(img) # Execute CLAHE on it. IJ = jnius.autoclass("ij.IJ") IJ.run(imp, "Enhance Local Contrast (CLAHE)", "blocksize=127 histogram=256 maximum=3 mask=*None*") # Display the result ij.py.show(imp, cmap='gray') ```

And here is the resulting exception:

java.lang.NullPointerException ``` java.lang.NullPointerException at mpicbg.ij.clahe.PlugIn.setup(PlugIn.java:72) at mpicbg.ij.clahe.PlugIn.run(PlugIn.java:132) at ij.IJ.runUserPlugIn(IJ.java:228) at ij.IJ.runPlugIn(IJ.java:192) at ij.Executer.runCommand(Executer.java:137) at ij.Executer.run(Executer.java:66) at ij.IJ.run(IJ.java:308) at ij.IJ.run(IJ.java:364) ```

Gaussian Blur 3D

This plugin cannot work with virtual images opened from ImageJ2. I filed an issue for it at imglib/imglib2-ij#27.

NoahDolev commented 5 years ago

Hi @ctrueden,

Thanks for your answer. As you suspected, indeed, the result of your script is "None" so for some reason the plugin directory is not found.

How do I fix that?

NoahDolev commented 5 years ago

Hi @ctrueden ,

FYI, I tried:

System.setProperty('plugins.dir', '/Applications/Fiji.app/plugins')

But the plugins still don't seem to be found because I get the same error.

ctrueden commented 5 years ago

indeed, the result of your script is "None" so for some reason the plugin directory is not found.

Ah, this is good news! If it had been set, I would have been pretty stumped on how to troubleshoot further. 😄

How do I fix that?

The plugins.dir system property is always set here. Do you see the message Added 375 JARs to the Java classpath.? (Or however many plugins you have, of course.)

ctrueden commented 5 years ago

I tried:

System.setProperty('plugins.dir', '/Applications/Fiji.app/plugins')

But the plugins still don't seem to be found

Did you set it before creating any net.imagej.ImageJ instances? This is rather tricky since init both initializes the JVM and creates a net.imagej.ImageJ in one swoop. You'd have to work a little harder to load the JVM first.

NBELab commented 5 years ago

Hi,

Thanks for answering!!

I tried this:

import imagej
ij = imagej.init('<my path>/Fiji.app')
from jnius import autoclass
System = autoclass('java.lang.System')
System.setProperty('plugins.dir', '<my path>/Fiji.app/plugins/')
import imglyb

I do see Added 370 JARs to the Java classpath Even though the plugin is in the folder, still the call:

macro = """open("{}");
run("Kalman Stack Filter", "acquisition_noise=0.05 bias=0.80");
saveAs("Tiff", "{}");""".format(inpath, outpath)
ij.script().run('Macro.ijm', macro, True).get()

Gives me the unrecognized command message.

NBELab commented 5 years ago

P.S. I don't see any warnings.

ctrueden commented 5 years ago

What does ij.getVersion() return? As of this writing, it should say 2.0.0-rc-69/1.51i. If it instead says 2.0.0-rc-69/Inactive or simply 2.0.0-rc-69 then your ImageJ1 is not active.

The following code should also say 1.51i currently:

legacy = ij.get('net.imagej.legacy.LegacyService')
legacy.getVersion()

As for calling ImageJ1 plugins from Jupyter in general, I think there are still some kinks to iron out. For example, the following code crashes the kernel on my macOS system:

built-in-plugin-fail.py ```python import imagej ij = imagej.init('/path/to/Fiji.app') import jnius, numpy from scyjava import jclass ImagePlusClass = jclass('ij.ImagePlus') # Define a function for converting image to ImagePlus. def to_imp(image): image = ij.py.to_java(image) if ImagePlusClass.isInstance(image): return image dataset = ij.dataset().create(image) # dataset = ij.py.to_dataset(image) return ij.convert().convert(dataset, ImagePlusClass) # Create a test image. img = numpy.zeros([10, 10]) imp = to_imp(img) script = """ #@ ImagePlus imp #@output ImagePlus blurred import ij.IJ IJ.run(imp, "Gaussian Blur...", "sigma=20") blurred = IJ.getImage() """ blurred = ij.py.run_script('groovy', script, {"imp": imp}).getOutput("blurred") ij.py.show(imp) ij.py.show(blurred) ```

Reports from others welcome. Sorry I don't have better news. Will certainly keep developing this fucntionality, though!

jluethi commented 5 years ago

I was also looking into local contrast enhancements, so here is what worked for me for anyone else coming across this:

  1. The Normalize Local Contrast is not the same as CLAHE. While CLAHE is a well documented algorithm, Normalize Local Contrast seems very useful as well, but is basically undocumented. The best I could find was this announcement that it exists and its source code.
  2. It's possible to call both of them by using jnius to get the Java classes and directly calling their run function found in the source code. Below are my examples for this.

For CLAHE:

ij = imagej.init('/Applications/Fiji.app')
from jnius import autoclass
IJ = autoclass('ij.IJ')
image_plus_img = IJ.openImage(str(img_path))
Flat = autoclass('mpicbg.ij.clahe.Flat')
blockRadius = 63
bins = 255
slope = 3
mask = None
composite = False
Flat.getFastInstance().run(image_plus_img, blockRadius, bins, slope, mask, composite)
IJ.run(image_plus_img, "8-bit", "")
IJ.saveAsTiff(image_plus_img, output_filename)

For Normalize Local Contrast:

ij = imagej.init('/Applications/Fiji.app')
from jnius import autoclass
IJ = autoclass('ij.IJ')
image_plus_img = IJ.openImage(str(img_path))
NormLocalContrast = autoclass('mpicbg.ij.plugin.NormalizeLocalContrast')
brx = 300
bry = 300
stds = 4
cent = True
stret = True
NormLocalContrast.run(image_plus_img.getChannelProcessor(), brx, bry, stds, cent, stret)
IJ.run(image_plus_img, "8-bit", "")
IJ.saveAsTiff(image_plus_img, output_filename)

PS: @NoahDolev I don't know why you'd run NormalizeLocalContrast and CLAHE in a row, they perform very similar tasks.

ctrueden commented 4 years ago

@NoahDolev Just an update that as of imagej/imagej-legacy#228, the plugins.dir variable no longer needs to be set. So that may eliminate the "Unrecognized command" in your environment. I'll try to make a new release of imagej soon that includes this fix.

imagesc-bot commented 4 years ago

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/neubias-academy-home-webinar-interactive-bioimage-analysis-with-python-and-jupyter-questions-answers/37596/1

ctrueden commented 3 years ago

I'm closing this due to inactivity. But @NoahDolev please reopen if you are still stuck and the newly released pyimagej 1.0.0 doesn't solve it for you!

chaichontat commented 3 years ago

Hi, I'm having a similar issue as well. The Bio-Formats plug-in did not work with pyimagej-1.0.0 installed through conda.

import imagej

ij = imagej.init("sc.fiji:fiji:2.1.1")
image_url = "https://samples.fiji.sc/new-lenna.jpg"

ij.py.run_macro(
    f"""
run("Bio-Formats Importer", "open=https://samples.fiji.sc/new-lenna.jpg autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT");
"""
)

plugin = "Bio-Formats Importer"
args = dict(open=image_url, rois_import="[ROI manager]", view="Hyperstack", stack_order="XYCZT")

ij.py.run_plugin(plugin, args)

Returns

[java.lang.Enum.toString] Macro Error: Unrecognized command: "Bio-Formats Importer" in line 2

run ( "Bio-Formats Importer" , "open=https://samples.fiji.sc/new-lenna.jpg autoscale color_mode=Default rois_import=[RO...[java.lang.Enum.toString] 
[java.lang.Enum.toString] Macro Error: Unrecognized command: "Bio-Formats Importer" in line 1

var ; initializeSciJavaParameters ( ) ; run ( "Bio-Formats Importer" , " open=[https://samples.fiji.sc/new-lenna.jpg] r...[java.lang.Enum.toString] 
<java object 'org.scijava.script.ScriptModule'>

Thanks!

chadhat commented 3 years ago

I am also having this issue on Windows 10. I installed pyimagej via conda. Anyone has a fix yet?