Creating Operator classes¶
Operator Class¶
Each Operator class inherits Operator class.
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
Operator’s input/output
Application’s input/output
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: