Creating Operator classes

Operator Class

Each Operator class inherits Operator class.

An Operator class definition example
 1from typing import Any, Dict
 2
 3import monai.deploy.core as md  # 'md' stands for MONAI Deploy (or can use 'core' instead)
 4from monai.deploy.core import (DataPath, ExecutionContext, Image, InputContext,
 5                               IOType, Operator, OutputContext)
 6
 7
 8@md.input("image", DataPath, IOType.DISK)
 9@md.input("mask", Image, IOType.IN_MEMORY)
10@md.output("image", Image, IOType.IN_MEMORY)
11@md.output("metadata", Dict[str, Any], IOType.IN_MEMORY)
12@md.env(pip_packages=["scikit-image>=0.17.2"])
13class MyOperator(Operator):
14    """Sample Operator implementation."""
15
16    def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
17        from skimage import filters, io
18
19        # Get input image
20        image_path = op_input.get("image").path
21        if image_path.is_dir():
22            image_path = next(image_path.glob("*.*"))  # take the first file
23        input_image = io.imread(image_path)
24
25        # Get mask image
26        mask = op_input.get("mask").asnumpy()
27
28        # Apply filter
29        output_image = filters.sobel(input_image, mask)
30
31        # Prepare output metadata
32        metadata = {"shape": input_image.shape, "dtype": input_image.dtype}
33
34        # Set output
35        op_output.set(Image(output_image), "image")
36        op_output.set(metadata, "metadata")

Decorators

The input and output properties of the operator are specified by using @input and @output decorators.

@input and @output decorators accept (<Label>, <Data Type>, <Storage Type>) as parameters.

If no @input or @output decorator is specified, the following properties are used by default:

@md.input("", DataPath, IOType.DISK)  # if no @input decorator is specified.
@md.output("", DataPath, IOType.DISK)  # if no @output decorator is specified.

@env accepts pip_packages parameter as a string that is a path to requirements.txt file or a list of packages to install. If pip_packages is specified, the definition will be aggregated with the package dependency list of other operators and the application. The aggregated requirement definitions are stored as a “requirements.txt” file and it would be installed in packaging time.

compute() method

compute() method in Operator class is an abstract method that needs to be implemented by the Operator developer.

Please check the description of compute() method to find a way to access

  1. Operator’s input/output

  2. Application’s input/output

  3. Model’s name/path/predictor

Note that, if the operator is a leaf operator in the workflow graph and the operator output’s (<data type>, <storage type>) == (DataPath, DISK), you cannot call op_output.set() method. Instead, you can use the destination path available by op_output.get().path to store output data and the following logic is expected:

output_folder = op_output.get().path                 # get the output folder path
output_path = output_folder / "final_output.png"     # get the output file path
imsave(output_path, data_out)                        # save the output data

Creating a Reusable Operator

You can create a common Operator class so that other Operator classes can just inherit the common Operator and implement only part of the compute() method to handle specific cases.

Please refer to the following examples: