Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export to Qupath does not work in headless mode from a script #9

Open
GuillaumeLeGoc opened this issue Jul 25, 2023 · 12 comments
Open
Labels
bug Something isn't working

Comments

@GuillaumeLeGoc
Copy link
Contributor

  • ABBA Python version: 0.3.0
  • Python version: 3.7.16
  • Operating System: Windows 10

Description

I want to export registration to the Qupath project programmatically from python.
To do this, I launch an ABBA instance in headless mode, I load a state file and run the export registration command :

aligner = abba.Abba('Adult Mouse Brain - Allen Brain Atlas V3p1', headless=True)
aligner.state_load(os.path.join(inputdir, inputfile))
aligner.select_all_slices()
aligner.export_registration_to_qupath(erase_previous_file=True)

The following line is printed :
Exporting slice img_001.ome.tiff registration to QuPath
But there is nothing written in the Qupath project.

There is an error raised during the loading of the state file (see below), but this error did not prevent me from doing things with abba_python previously (eg. converting coordinates).

Doing the same thing not in headless mode (eg. aligner = abba.Abba('Adult Mouse Brain - Allen Brain Atlas V3p1')), the output is more talkative, those lines are also printed :

Multipositioner : Save slice ROI to quPath project path\to\qproj\data\1\ABBA-RoiSet-Adult Mouse Brain - Allen Brain Atlas V3p1.zip
Multipositioner : Save transformation to quPath project path\to\qproj\data\1\ABBA-Transform-Adult Mouse Brain - Allen Brain Atlas V3p1.json

And the files are indeed exported.

So it seems the multipositionner does not really exist in headless mode and Qupath export relies on it (but converting coordinates does not so that is why the latter works) ?

Output

[java.lang.Enum.toString] [ERROR] Multipositioner : null
[ERROR] Command errored: ABBA - Load State
java.awt.HeadlessException
        at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)
        at java.awt.Window.<init>(Window.java:536)
        at java.awt.Frame.<init>(Frame.java:420)
        at java.awt.Frame.<init>(Frame.java:385)
        at javax.swing.JFrame.<init>(JFrame.java:189)
        at ch.epfl.biop.atlas.aligner.MultiSlicePositioner.lambda$new$2(MultiSlicePositioner.java:134)
        at ch.epfl.biop.atlas.aligner.MultiSlicePositioner.lambda$new$4(MultiSlicePositioner.java:144)
        at ch.epfl.biop.atlas.aligner.MultiSlicePositioner.loadState(MultiSlicePositioner.java:1181)
        at ch.epfl.biop.atlas.aligner.command.ABBAStateLoadCommand.run(ABBAStateLoadCommand.java:27)
        at org.scijava.command.CommandModule.run(CommandModule.java:196)
        at org.scijava.module.ModuleRunner.run(ModuleRunner.java:165)
        at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
        at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
        at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
[java.lang.Enum.toString] [ERROR] Command errored: ABBA - Load State
java.awt.HeadlessException
        at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)
        at java.awt.Window.<init>(Window.java:536)
        at java.awt.Frame.<init>(Frame.java:420)
        at java.awt.Frame.<init>(Frame.java:385)
        at javax.swing.JFrame.<init>(JFrame.java:189)
        at ch.epfl.biop.atlas.aligner.MultiSlicePositioner.lambda$new$2(MultiSlicePositioner.java:134)
        at ch.epfl.biop.atlas.aligner.MultiSlicePositioner.lambda$new$4(MultiSlicePositioner.java:144)
        at ch.epfl.biop.atlas.aligner.MultiSlicePositioner.loadState(MultiSlicePositioner.java:1181)
        at ch.epfl.biop.atlas.aligner.command.ABBAStateLoadCommand.run(ABBAStateLoadCommand.java:27)
        at org.scijava.command.CommandModule.run(CommandModule.java:196)
        at org.scijava.module.ModuleRunner.run(ModuleRunner.java:165)
        at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
        at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
        at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
@GuillaumeLeGoc
Copy link
Contributor Author

GuillaumeLeGoc commented Jul 25, 2023 via email

@NicoKiaru
Copy link
Member

NicoKiaru commented Jul 25, 2023

Yeah, I read more carefully your message and got it, that's why I deleted my message sorry !

I'll need a bit of time, debugging java in python is not sure super straightforward

@NicoKiaru
Copy link
Member

I've looked quickly and there's no clear dependency on the user interface.
I'll have to dig more carefully

@NicoKiaru
Copy link
Member

NicoKiaru commented Jul 26, 2023

Regarding the first error: I had a bunch of graphical classes for logging even in the one that's suppose to work headless. So I'll remove them.

@NicoKiaru
Copy link
Member

Hum, I can't reproduce the issue. Have you waited enough time ? Maybe the issue is that it's not a blocking command ?

Can you try on one slice:

mp = aligner.mp
aligner.deselect_all_slices()
mp.selectSlice(mp.getSlices().get(0))
aligner.export_registration_to_qupath(erase_previous_file=True)

Wait ~30s and check if the expected file is written on the entry folder of this slice ?

Maybe double check that you are targetting the right QuPath project ?

If it's something else that can be tricky. Maybe there's an error which is swallowed because of the error log.

If none of this works, I can make a special jar that logs a bunch of other things to see where the problem

@GuillaumeLeGoc
Copy link
Contributor Author

Hi, sorry for the late reply, I was away for a while.
Thanks for looking into it.
So I tried again directly from an IPython console, and it works fine, with the original commands provided in OP :

aligner.select_all_slices()
aligner.export_registration_to_qupath(erase_previous_file=True)

It also works from a regular python console, but does not work (eg. files are not exported) executing the python script (python script.py). I have no idea what's happening. I can just notice that the regular python prompt is not released after aligner.export_registration_to_qupath(erase_previous_file=True).
Unfortunately I have no knowledge about the differences of execution between python prompt and from a script...

@NicoKiaru
Copy link
Member

Ah! Then I think the issue comes from the asynchronous nature of the method.

Please try to add at the end of your script:

# all tasks/registrations/exports are enqueued and executed asynchronously
# if you want to wait that all tasks are finished, then add:
aligner.wait_for_end_of_tasks()

If that's the issue, then I need to change the method or improve the documentation. Probably I'll add an extra parameter async that would be false by default.

@GuillaumeLeGoc
Copy link
Contributor Author

GuillaumeLeGoc commented Jul 31, 2023

Yay, you nailed it ! It works fine from a script now.
I think it's fine to just add this to the documentation. I saw it in the notebooks but is it useful from a notebook (since it works fine from an IPython console, I assume it works from a notebook) ?
It would be good to remind this in the readme, something like "tasks are enqueued so a script needs to wait for the command to finish before terminating it, with aligner.wait_for_end_of_tasks()".

Cheers !

@GuillaumeLeGoc GuillaumeLeGoc changed the title Export to Qupath does not work in headless mode Export to Qupath does not work in headless mode from a script Jul 31, 2023
@NicoKiaru
Copy link
Member

Reopening the issue to keep track of the documentation modification

@NicoKiaru NicoKiaru reopened this Jul 31, 2023
@NicoKiaru NicoKiaru added the documentation Improvements or additions to documentation label Jul 31, 2023
@GuillaumeLeGoc
Copy link
Contributor Author

GuillaumeLeGoc commented Jul 31, 2023

Hey,
Sorry, I feel like I'm always bringing bad news...
I just noticed that exporting to Qupath from abba_python does not yield the same results as with the export from Fiji. It's as if some transformations are not applied during the python export.

I checked, indeed it seems transformations done through "Interactive Transform" are not applied before exporting (I rotated a slice by a large angle, it shows when exporting from the UI but not from python). (*)

Exporting from the UI launched from Python yields the same result as in regular Fiji UI.

I can open a new issue to help you track this if you prefer.

Cheers !

And again, sorry... Do you have echoes from other users of abba_python ? It feels like I'm either the only one to use it, the only one to complain or the only for who it does not work as expected :'(

[EDIT] (*)
Launching ABBA from Python not in headless mode, without even showing the bdv UI, and exporting from the python prompt (aligner.export_registration_to_qupath(erase_previous_file=True)) seems to yield the good result.

@NicoKiaru
Copy link
Member

Hi @GuillaumeLeGoc and thanks for the report!

It feels like I'm either the only one to use it, the only one to complain or the only for who it does not work as expected :'(

:-) Yes, there's much less users in python than within the regular Fiji. You may be the only one or not far from it.

I'm not sure about this new issue. I'll try to contact you by email

@GuillaumeLeGoc
Copy link
Contributor Author

The python script used to export to QuPath.

# --- Imports
import os
from abba_python import abba

# --- Parameters
abba_file = os.path.abspath("path/to/state.abba")

# --- Processing

# Get ABBA
aligner = abba.Abba('Adult Mouse Brain - Allen Brain Atlas V3p1', headless=True)    # does not work in headless mode

# Load state
try:
    aligner.state_load(abba_file)
except:
    pass

# get multipos
mp = aligner.mp
aligner.deselect_all_slices()
mp.selectSlice(mp.getSlices().get(0))

# Export to Qupath project
aligner.export_registration_to_qupath(erase_previous_file=True)
aligner.wait_for_end_of_tasks()

@NicoKiaru NicoKiaru added bug Something isn't working and removed documentation Improvements or additions to documentation labels Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants