imagej / pyimagej

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

Pairwise stitching plugin error #119

Closed fanweiya closed 3 years ago

fanweiya commented 3 years ago

I'm using the 'Pairwise stitching' plugin and want to get the parameters of the transformation out. They are printed when the plugin is run in the following way:

You need at least two open images. in line 1:
var ; initializeSciJavaParameters ( ) ; run ( "Pairwise stitching" , " first_image=[1.jpg] second_image=[2.jpg] fusion_...
Traceback (most recent call last):
  File "F:/algorithmDEV/Sitiching/imagj.py", line 51, in <module>
    imp = ij.py.active_image_plus()
  File "F:\Anaconda\envs\tf2\lib\site-packages\imagej\__init__.py", line 719, in active_image_plus
    self.synchronize_ij1_to_ij2(imp)
  File "F:\Anaconda\envs\tf2\lib\site-packages\imagej\__init__.py", line 735, in synchronize_ij1_to_ij2
    stack = imp.getStack()
AttributeError: 'NoneType' object has no attribute 'getStack'

my code:

ij = imagej.init(ij_dir_or_version_or_endpoint=os.path.join(os.getcwd(),"Fiji.app"),headless=False)
image1 = ij.io().open(r"F:\algorithmDEV\1.jpg")
image2 = ij.io().open(r"F:\algorithmDEV\2.jpg")
plugin = 'Pairwise stitching'
args = {'first_image':image1,
        'second_image':image2,
        "fusion_method":"[Linear Blending]",
        "fused_image":"fusion.jpg",
        "check_peaks":5,
        "compute_overlap":True,
        "x":31.0000,
        "y":2365.0000,
        "registration_channel_image_1":"[Average all channels]",
        "registration_channel_image_2":"[Average all channels]",
}
ij.py.run_plugin(plugin, args)
stitched_img= ij.py.active_image_plus()
stitched_img_python = ij.py.from_java(stitched_img)
cv2.imwrite("test2.jpg", stitched_img_python.astype('uint16'))
ctrueden commented 3 years ago

@fanweiya Hmm, might be an issue with the ImageJ1 :left_right_arrow: ImageJ2 synchronization—maybe the same issue as #51; I'm not sure. The ImageJ team at LOCI has our hands full right now preparing to launch the new ImageJ wiki, so I can't dig deeply immediately, but maybe @elevans has time? Otherwise, we will be doing another push on PyImageJ this summer, and will investigate more then.

ctrueden commented 3 years ago

I fixed a related bug (imagej/pyimagej@d59014139f202e004cf488fb3c9e3b31e325807d) resulting in this specific error message. However, the fact is that the active ImagePlus should not be null here in the first place, and my fix won't make this script work: it'll just push the NoneType error later down the line. Sorry I don't have more time to dig at the moment.

elevans commented 3 years ago

Hi @fanweiya as @ctrueden noted this is related to ongoing issue with ImageJ1 <-> ImageJ2 synchronization. In brief part of the issue is that the older ImageJ1 plugins expect an open window/image -- which in a headless mode doesn't exist. It's not ideal, but if your computing conditions allow it you can simply display the images prior to stitching:

import imagej

# start imagej
ij = imagej.init('sc.fiji:fiji:2.1.1', headless=False)

# open images
img1 = ij.io().open('path/to/img1')
img2 = ij.io().open('path/to/img2')

# setup plugin args
plugin = "Pairwise stitching"

args = {"first_image":img1,
        "second_image":img2,
        "fusion_method":"[Linear Blending]",
        "fused_image":"fusion.jpg",
        "check_peaks":5,
        "compute_overlap":True,
        "x":31.0000,
        "y":2365.0000,
        "registration_channel_image_1":"[Average all channels]",
        "registration_channel_image_2":"[Average all channels]",
       }

# trick is to show the UI to register the images as currently open
ij.ui().show(img1)
ij.ui().show(img2)

# run plugin
ij.py.run_plugin(plugin, args)

There is also another related bug in this issue that breaks some of the plugins as well. For more details check out #120.

ctrueden commented 3 years ago

@elevans Is calling ij.ui().showUI() also necessary to make ImageJ1 do the right things with the WindowManager?

elevans commented 3 years ago

Nope! Just opening the images with ij.ui().show() is good enough to play nice with the WindowManager for the Pairwise stitching plugin.

elevans commented 3 years ago

@fanweiya

I just pushed a commit that fixes image name handling when running plugins. If you grab the latest copy of the pyimagej repo you can quickly open and hide images prior to running the Pairwise stitching plugin. One thing you'll need to do first is convert the ImgPlus that ij.io().open() gives you into ImagePlus. Assuming you've already initialized imagej:

import scyjava as sj

# get ConvertService and ImagePlus class
ConvertService = ij.get('org.scijava.convert.ConvertService')
ImagePlus = sj.jimport('ij.ImagePlus')

# convert Img to ImagePlus
imp1 = ConvertService.convert(img1, ImagePlus)
imp2 = ConvertService.convert(img2, ImagePlus)

# now you can show and hide an image
imp1.show()
imp1.getWindow().setVisible(False)
imp2.show()
imp2.getWindow().setVisible(False)
fanweiya commented 3 years ago

@elevans Thank you,This method is very effective. What should I do to save plugin’s stitched image and how to hide result view window and Log window? run save code in the following way get error:

stitched_img= ij.py.active_image_plus()
stitched_img_python = ij.py.from_java(stitched_img)
cv2.imwrite("test2.jpg", stitched_img_python.astype('uint16'))

cv2.imwrite("test2.jpg", stitched_img_python.astype('uint16')) TypeError: Expected Ptr for argument 'img'

elevans commented 3 years ago

@fanweiya It looks like cv2.imwrite is looking for an InputArray which I'm assuming isn't just a generic numpy array (I tried passing one to it and it didn't like it). I'm not well versed on opencv but if that is true then the ImagePlus image you get from ij.py.active_image_plus isn't going to work with opencv. If you are just interested in just saving the image do something like this:

# get stitched image
stitched_imp = ij.py.active_image_plus()

# get ConvertService and Dataset class
ConvertService = ij.get('org.scijava.convert.ConvertService')
Dataset = sj.jimport('net.imagej.Dataset'')

# convert imp
stitched_img = ConvertService.convert(stitched_imp, Dataset)

# save image
filename = "fusion.jpg"
ij.io().save(stitched_img, filename)

If you want to use opencv then I imagine getting the image in a numpy array would get you there. If you want that you can access it easily after you convert the image to a Dataset from ImagePlus:

>>> stitched_numpy = ij.py.from_java(stitched_img) # returns an xarray
>>> type(stitched_numpy.data)
numpy.ndarray

As for hiding the result window and log window -- this is more tricky/hacky as the Pairwise stitching plugin was not designed to work in a headless mode. The following code will do the stitching and close the windows after the stitched image has been saved. Note that this does not kill pyimagej, so it should work in a for loop although I did not test that.

# run plugin
ij.py.run_plugin(plugin, args)

# get stitched result, convert to Dataset and save
filename = "fusion.jpg"
stitched_imp = ij.py.active_image_plus()
stitched_img = ConvertService.convert(stitched_img, Dataset)
ij.io().save(stitched_img, filename)

# close all windows
ij.py.window_manager().closeAllWindows()

Also as a quick side note, if you know you want a Dataset specifically (when working in ImageJ land this is my preferred data type) you can replace calling the ConvertService and net.imagej.Dataset class and pass the ImagePlus to ij.py.to_dataset() instead!

fanweiya commented 3 years ago

@elevans thank you,I use the following code to save image,but prompt me for this error when closing the window?

# run plugin
stitched_imp = ij.py.active_image_plus()

# get stitched result, convert to Dataset and save

filename = "fusion.jpg"
stitched_img_python=ij.py.to_dataset(stitched_imp)
ij.io().save(stitched_img_python, filename)

# close all windows
ij.py.window_manager().closeAllWindows()

Traceback (most recent call last): File "test_imagej.py", line 69, in ij.py.window_manager().closeAllWindows() File "F:\Anaconda\envs\tf2\lib\site-packages\imagej__init__.py", line 685, in window_manager if not ij.legacy_enabled: AttributeError: 'net.imagej.ImageJ' object has no attribute 'legacy_enabled'

imagejan commented 3 years ago

AttributeError: 'net.imagej.ImageJ' object has no attribute 'legacy_enabled'

I think this was fixed with https://github.com/imagej/pyimagej/commit/3a3524c4844e4bc93715b0efdfbb7ad3ac415f17, right?

fanweiya commented 3 years ago

@imagejan The method you provide hints at this error. AttributeError: 'net.imagej.ImageJ' object has no attribute 'isActive'

I have found an effective method here https://github.com/imagej/pyimagej/issues/105. The problem seems being fixed by changing line 685 in imagej.init from "if not ij.legacy_enabled:" to "if not ij.legacy.isLegacyMode():"

imagejan commented 3 years ago

Indeed, I pointed to the wrong commit. The error you reported is fixed by https://github.com/imagej/pyimagej/commit/ec608e64b66dc913732d35f0951d1d245b4a517f.

None of these fixes is contained in a release version yet, though.

elevans commented 3 years ago

@fanweiya @imagejan Actually the correct fix is 50868ed69abebd0c900d27cb6d86c3d5d53f4d58. ij.legacy.isLegacyMode() is for something else and is slated to be deprecated. You want ij.legacy.isActive().