The ApplicationController
Interactions between Python and an application, like the ImFusionSuite, can be facilitated by
ApplicationController
, which, among other things, manages loaded data, can visualize data,
and records executed algorithms.
If you are using the embedded Python interpreter of the ImFusionSuite, an ApplicationController
is already instantiated.
Otherwise, we create a ConsoleController
which is a special controller that does not provide or require a GUI:
>>> if not imfusion.app:
... imfusion.app = imfusion.ConsoleController()
All the previously introduced functions are independent of the ApplicationController
but some can also be called on the ApplicationController
instance with some additional side effects:
>>> imfusion.app.open('ct_image.png')
[imfusion.SharedImageSet(size: 1, [imfusion.SharedImage(USHORT width: 512 height: 512 spacing: 0.661813x0.661813x1 mm)])]
If you executed the previous code in the ImFusionSuite, you might have noted that the image is directly displayed in the main view area.
This is because the data gets automatically added to the DataModel
.
This is not the case if you load data with load()
.
Note
When writing simple scripts, most likely the added complexity of the ApplicationController
is not needed, since many functions don’t require it (see execute_algorithm()
for example).
Note
When writing custom algorithms, you should not rely on app
being available, because app
could be None when a custom algorithm is run outside of the ImFusionSuite. If, on the other hand, you are using Python in combination with the ImFusionSuite application, the ApplicationController
interface for algorithms can become much more convenient.
Workspaces (.iws files)
Workspaces can be loaded and saved with the functions load_workspace()
and save_workspace()
respectively.
Please, check the ImFusionSuite documentation for more details about workspaces.
Interacting with the Display
Warning
Displays and annotations are currently only available when using the imfusion
module inside the ImFusion Suite.
The Display
is the central widget in the ImFusion Suite that visualizes the loaded datasets.
It consists of several View
that show the datasets in different perspectives or in different ways.
The Display
instance can be accessed through the display
.
The following example makes all views visible, switches to a different layout, and shows the 3D view as the prominent view.
>>> display = imfusion.app.display
>>> for view in display.views():
... view.visible = True
>>> display.layout_mode = imfusion.LayoutMode.LAYOUT_FOCUS_PLUS_STACK
>>> display.focus_view = display.views3d()[0]
DataModel
The DataModel
stores all data that is managed by the ApplicationController
and
you can retrieve, add or delete data from it:
>>> dm = imfusion.app.data_model
>>> len(dm)
1
>>> img = dm[0]
>>> img
imfusion.SharedImageSet(size: 1, [imfusion.SharedImage(USHORT width: 512 height: 512 spacing: 0.661813x0.661813x1 mm)])
When adding data created in Python to the DataModel
it will get copied.
The reference to the copy is returned:
>>> new_img = imfusion.SharedImageSet(np.zeros([1, 8, 8, 8, 1], dtype=np.uint8))
>>> new_img = dm.add(new_img)
>>> dm.remove(new_img)
Running algorithms
We can also execute algorithms directly on the ApplicationController
.
Any output data will then be added automatically to the DataModel
:
>>> imfusion.app.execute_algorithm('Base.MorphologicalOperations', [img])
[imfusion.SharedImageSet(size: 1, [imfusion.SharedImage(USHORT width: 512 height: 512 spacing: 0.661813x0.661813x1 mm)])]
>>> len(dm)
2
The ApplicationController
will also keep track of all executed algorithms.
You can save the algorithm history in the ImFusionSuite as a workspace (.iws), see also Workspaces (.iws files), and replay the algorithms with the same settings.
Instead of executing the algorithm right away, we can also just open it:
>>> imfusion.app.add_algorithm('Base.MorphologicalOperations', [img])
<imfusion.BaseAlgorithm object at...>
This returns a reference to the algorithm instance and will open the corresponding UI element (which we call “Algorithm Controller”) in the ImFusionSuite.
AnnotationModel
The Display
enables adding annotations such as lines or circles to a dataset.
This functionality is facilitated by the AnnotationModel
, which holds all annotations similar to how the DataModel
manages data.
Unlike Data
, Annotation
instances can only be created through a factory method, create_annotation
.
To create a line Annotation
:
>>> am = imfusion.app.annotation_model
>>> annotation = am.create_annotation(imfusion.Annotation.AnnotationType.LINE)
>>> annotation.color = (1.0, 0.0, 0.0) # make it red
>>> annotation.points = [(0.0, 0.0, 0.0), (100.0, 100.0, 0.0)]
The last command assigns the line’s points in world coordinates.
Each type of Annotation
requires a specific number of points, which can be queried via the max_points
property.
The Python interface currently provides the following types:
It is also possible to set the points of an annotation interactively on the display:
>>> annotation = am.create_annotation(imfusion.Annotation.AnnotationType.LINE)
>>> annotation.start_editing()
You can register a callback which will be called once the user finishes editing the annotation (i.e., when it’s completely defined):
>>> def callback():
... print("All points are defined")
>>> a1 = am.create_annotation(imfusion.Annotation.AnnotationType.LINE)
>>> a1.on_editing_finished(callback)
>>> a1.start_editing()
Ideally, you would add the callback before calling start_editing()
.
Alternatively, you can also listen for all changes to points
:
>>> def callback():
... print("Points changed")
>>> a2 = am.create_annotation(imfusion.Annotation.AnnotationType.LINE)
>>> a2.on_points_changed(callback)
>>> a2.start_editing()
Annotations can be queried through the annotations
attribute:
>>> all_annotations = am.annotations()