Skip to content

Commit e733d94

Browse files
authored
Correct the place to save input image file as well as correct application name (#188)
Signed-off-by: mmelqin <mingmelvinq@nvidia.com>
1 parent c6b9ab1 commit e733d94

File tree

5 files changed

+36
-28
lines changed

5 files changed

+36
-28
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from app import AIUnetrSegApp
1+
from app import AILiverTumorApp
22

33
if __name__ == "__main__":
4-
AIUnetrSegApp(do_run=True)
4+
AILiverTumorApp(do_run=True)

examples/apps/ai_livertumor_seg_app/app.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
@resource(cpu=1, gpu=1, memory="7Gi")
2525
# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
2626
# The MONAI pkg is not required by this class, instead by the included operators.
27-
class AIUnetrSegApp(Application):
27+
class AILiverTumorApp(Application):
2828
def __init__(self, *args, **kwargs):
2929
"""Creates an application instance."""
3030

@@ -63,14 +63,14 @@ def compose(self):
6363
self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
6464
self.add_flow(series_selector_op, series_to_vol_op, {"dicom_series": "dicom_series"})
6565
self.add_flow(series_to_vol_op, unetr_seg_op, {"image": "image"})
66+
# Add the publishing operator to save the input and seg images for Render Server.
67+
# Note the PublisherOperator has temp impl till a proper rendering module is created.
68+
self.add_flow(unetr_seg_op, publisher_op, {"saved_images_folder": "saved_images_folder"})
6669
# Note below the dicom_seg_writer requires two inputs, each coming from a upstream operator.
6770
# Also note that the DICOMSegmentationWriterOperator may throw exception with some inputs.
6871
# Bug has been created to track the issue.
6972
self.add_flow(series_selector_op, dicom_seg_writer, {"dicom_series": "dicom_series"})
7073
self.add_flow(unetr_seg_op, dicom_seg_writer, {"seg_image": "seg_image"})
71-
# Add the publishing operator to save the input and seg images for Render Server.
72-
# Note the PublisherOperator has temp impl till a proper rendering module is created.
73-
self.add_flow(unetr_seg_op, publisher_op, {"saved_images_folder": "saved_images_folder"})
7474

7575
self._logger.debug(f"End {self.compose.__name__}")
7676

@@ -84,5 +84,5 @@ def compose(self):
8484
# python3 app.py -i input -m model/model.ts
8585
#
8686
logging.basicConfig(level=logging.DEBUG)
87-
app_instance = AIUnetrSegApp() # Optional params' defaults are fine.
87+
app_instance = AILiverTumorApp() # Optional params' defaults are fine.
8888
app_instance.run()

examples/apps/ai_livertumor_seg_app/livertumor_seg_operator.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
7676

7777
# This operator gets an in-memory Image object, so a specialized ImageReader is needed.
7878
_reader = InMemImageReader(input_image)
79-
pre_transforms = self.pre_process(_reader)
79+
# In this example, the input image, once loaded at the beginning of the pre-transforms, is
80+
# saved on disk, so is the segmentation prediction image at the end of the post-transform.
81+
# They are both saved in the same subfolder of the application output folder, with names
82+
# distinguished by postfix. They can also be save in different subfolder if need be.
83+
# These images files can then be packaged for rendering.
84+
pre_transforms = self.pre_process(_reader, op_output_folder_path)
8085
post_transforms = self.post_process(pre_transforms, op_output_folder_path)
8186

8287
# Delegates inference and saving output to the built-in operator.
@@ -98,14 +103,20 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
98103
# Now let the built-in operator handles the work with the I/O spec and execution context.
99104
infer_operator.compute(op_input, op_output, context)
100105

101-
def pre_process(self, img_reader) -> Compose:
106+
def pre_process(self, img_reader, out_dir: str = "./input_images") -> Compose:
102107
"""Composes transforms for preprocessing input before predicting on a model."""
103108

104109
my_key = self._input_dataset_key
105110
return Compose(
106111
[
107112
LoadImaged(keys=my_key, reader=img_reader),
108113
EnsureChannelFirstd(keys=my_key),
114+
SaveImaged(
115+
keys=my_key,
116+
output_dir=out_dir,
117+
output_postfix="",
118+
resample=False,
119+
),
109120
Spacingd(keys=my_key, pixdim=(1.0, 1.0, 1.0), mode=("bilinear"), align_corners=True),
110121
ScaleIntensityRanged(my_key, a_min=-21, a_max=189, b_min=0.0, b_max=1.0, clip=True),
111122
CropForegroundd(my_key, source_key=my_key),
@@ -125,12 +136,5 @@ def post_process(self, pre_transforms: Compose, out_dir: str = "./prediction_out
125136
keys=pred_key, transform=pre_transforms, orig_keys=self._input_dataset_key, nearest_interp=True
126137
),
127138
SaveImaged(keys=pred_key, output_dir=out_dir, output_postfix="seg", output_dtype=uint8, resample=False),
128-
SaveImaged(
129-
keys=self._input_dataset_key,
130-
output_dir=out_dir,
131-
output_postfix="",
132-
output_dtype=uint8,
133-
resample=False,
134-
),
135139
]
136140
)

examples/apps/ai_unetr_seg_app/app.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,14 @@ def compose(self):
7373
self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
7474
self.add_flow(series_selector_op, series_to_vol_op, {"dicom_series": "dicom_series"})
7575
self.add_flow(series_to_vol_op, unetr_seg_op, {"image": "image"})
76+
# Add the publishing operator to save the input and seg images for Render Server.
77+
# Note the PublisherOperator has temp impl till a proper rendering module is created.
78+
self.add_flow(unetr_seg_op, publisher_op, {"saved_images_folder": "saved_images_folder"})
7679
# Note below the dicom_seg_writer requires two inputs, each coming from a upstream operator.
7780
# Also note that the DICOMSegmentationWriterOperator may throw exception with some inputs.
7881
# Bug has been created to track the issue.
7982
self.add_flow(series_selector_op, dicom_seg_writer, {"dicom_series": "dicom_series"})
8083
self.add_flow(unetr_seg_op, dicom_seg_writer, {"seg_image": "seg_image"})
81-
# Add the publishing operator to save the input and seg images for Render Server.
82-
# Note the PublisherOperator has temp impl till a proper rendering module is created.
83-
self.add_flow(unetr_seg_op, publisher_op, {"saved_images_folder": "saved_images_folder"})
8484

8585
self._logger.debug(f"End {self.compose.__name__}")
8686

examples/apps/ai_unetr_seg_app/unetr_seg_operator.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
7070

7171
# This operator gets an in-memory Image object, so a specialized ImageReader is needed.
7272
_reader = InMemImageReader(input_image)
73-
pre_transforms = self.pre_process(_reader)
73+
# In this example, the input image, once loaded at the beginning of the pre-transforms, is
74+
# saved on disk, so is the segmentation prediction image at the end of the post-transform.
75+
# They are both saved in the same subfolder of the application output folder, with names
76+
# distinguished by postfix. They can also be save in different subfolder if need be.
77+
# These images files can then be packaged for rendering.
78+
pre_transforms = self.pre_process(_reader, op_output_folder_path)
7479
post_transforms = self.post_process(pre_transforms, op_output_folder_path)
7580

7681
# Delegates inference and saving output to the built-in operator.
@@ -91,14 +96,20 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
9196
# Now let the built-in operator handles the work with the I/O spec and execution context.
9297
infer_operator.compute(op_input, op_output, context)
9398

94-
def pre_process(self, img_reader) -> Compose:
99+
def pre_process(self, img_reader, out_dir: str = "./input_images") -> Compose:
95100
"""Composes transforms for preprocessing input before predicting on a model."""
96101

97102
my_key = self._input_dataset_key
98103
return Compose(
99104
[
100105
LoadImaged(keys=my_key, reader=img_reader),
101106
AddChanneld(keys=my_key),
107+
SaveImaged(
108+
keys=my_key,
109+
output_dir=out_dir,
110+
output_postfix="",
111+
resample=False,
112+
),
102113
Spacingd(keys=my_key, pixdim=(1.5, 1.5, 2.0), mode=("bilinear")),
103114
Orientationd(keys=my_key, axcodes="RAS"),
104115
ScaleIntensityRanged(my_key, a_min=-175, a_max=250, b_min=0.0, b_max=1.0, clip=True),
@@ -119,12 +130,5 @@ def post_process(self, pre_transforms: Compose, out_dir: str = "./prediction_out
119130
keys=pred_key, transform=pre_transforms, orig_keys=self._input_dataset_key, nearest_interp=True
120131
),
121132
SaveImaged(keys=pred_key, output_dir=out_dir, output_postfix="seg", output_dtype=uint8, resample=False),
122-
SaveImaged(
123-
keys=self._input_dataset_key,
124-
output_dir=out_dir,
125-
output_postfix="",
126-
output_dtype=uint8,
127-
resample=False,
128-
),
129133
]
130134
)

0 commit comments

Comments
 (0)