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()