Skip to content

Commit 874151a

Browse files
Add nnUNet segmentation application and dependencies
Signed-off-by: Simone Bendazzoli <[email protected]>
1 parent f1e8dcd commit 874151a

File tree

5 files changed

+140
-0
lines changed

5 files changed

+140
-0
lines changed

examples/apps/ai_spleen_nnunet_seg_app/app.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,49 @@
2222
from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription
2323
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
2424
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
25+
<<<<<<< HEAD
2526
from monai.deploy.operators.monai_bundle_inference_operator import BundleConfigNames, IOMapping
2627
from monai.deploy.operators.monet_bundle_inference_operator import MONetBundleInferenceOperator
28+
=======
29+
from monai.deploy.operators.monai_bundle_inference_operator import (
30+
BundleConfigNames,
31+
IOMapping,
32+
33+
)
34+
from monai.deploy.operators.monai_nnunet_bundle_inference_operator import MonainnUNetBundleInferenceOperator
35+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
2736
from monai.deploy.operators.stl_conversion_operator import STLConversionOperator
2837

2938

3039
# @resource(cpu=1, gpu=1, memory="7Gi")
3140
# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
3241
# The monai pkg is not required by this class, instead by the included operators.
3342
class AISpleennnUNetSegApp(Application):
43+
<<<<<<< HEAD
3444
"""Demonstrates inference with built-in MONet Bundle inference operator with DICOM files as input/output
3545
3646
This application loads a set of DICOM instances, select the appropriate series, converts the series to
3747
3D volume image, performs inference with the built-in MONet Bundle inference operator, including nnUNet resampling, pre-processing
48+
=======
49+
"""Demonstrates inference with built-in MONAI nnUNet Bundle inference operator with DICOM files as input/output
50+
51+
This application loads a set of DICOM instances, select the appropriate series, converts the series to
52+
3D volume image, performs inference with the built-in MONAI nnUNet Bundle inference operator, including pre-processing
53+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
3854
and post-processing, save the segmentation image in a DICOM Seg OID in an instance file, and optionally the
3955
surface mesh in STL format.
4056

4157
Pertinent nnUNet MONAI Bundle:
4258
<Upload to the MONAI Model Zoo>
4359

4460
Execution Time Estimate:
61+
<<<<<<< HEAD
4562
With a Nvidia RTXA600 48GB GPU, for an input DICOM Series of size 106x415x415 and patches of size 64x192x160, the execution time is around
4663
50 seconds with saving both DICOM Seg and surface mesh STL file.
64+
=======
65+
With a Nvidia RTXA600 48GB GPU, for an input DICOM Series of 139 instances, the execution time is around
66+
75 seconds with saving both DICOM Seg and surface mesh STL file.
67+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
4768
"""
4869
4970
def __init__(self, *args, **kwargs):
@@ -83,7 +104,11 @@ def compose(self):
83104
84105
config_names = BundleConfigNames(config_names=["inference"]) # Same as the default
85106
107+
<<<<<<< HEAD
86108
bundle_spleen_seg_op = MONetBundleInferenceOperator(
109+
=======
110+
bundle_spleen_seg_op = MonainnUNetBundleInferenceOperator(
111+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
87112
self,
88113
input_mapping=[IOMapping("image", Image, IOType.IN_MEMORY)],
89114
output_mapping=[IOMapping("pred", Image, IOType.IN_MEMORY)],
@@ -158,6 +183,19 @@ def compose(self):
158183
"""
159184

160185
if __name__ == "__main__":
186+
<<<<<<< HEAD
187+
=======
188+
# Creates the app and test it standalone. When running is this mode, please note the following:
189+
# -m <model file>, for model file path
190+
# -i <DICOM folder>, for input DICOM CT series folder
191+
# -o <output folder>, for the output folder, default $PWD/output
192+
# e.g.
193+
# monai-deploy exec app.py -i input -m model/model.ts
194+
#
195+
# export HOLOSCAN_INPUT_PATH=dcm
196+
# export HOLOSCAN_MODEL_PATH=spleen_model/model.ts
197+
# export HOLOSCAN_OUTPUT_PATH="output"
198+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
161199
logging.info(f"Begin {__name__}")
162200
AISpleennnUNetSegApp().run()
163201
logging.info(f"End {__name__}")

examples/apps/ai_spleen_nnunet_seg_app/app.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
# limitations under the License.
1616
---
1717
application:
18+
<<<<<<< HEAD
1819
title: MONAI Deploy App Package - Spleen MONet Seg Inference
20+
=======
21+
title: MONAI Deploy App Package - Spleen nnUNet Seg Inference
22+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
1923
version: 1.0
2024
inputFormats: ["file"]
2125
outputFormats: ["file"]

examples/apps/ai_spleen_nnunet_seg_app/requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ numpy-stl>=2.12.0
77
trimesh>=3.8.11
88
nibabel>=3.2.1
99
torch>=1.12.0
10+
<<<<<<< HEAD
1011
nvflare
1112
git+https://github.com/SimoneBendazzoli93/dynamic-network-architectures.git
1213
git+https://github.com/SimoneBendazzoli93/MONAI.git@dev
1314
git+https://github.com/SimoneBendazzoli93/nnUNet.git
15+
=======
16+
monai>=1.0.0
17+
nnunetv2>=2.5.1
18+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)

monai/deploy/operators/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
IOMapping
2626
ModelInfo
2727
MonaiBundleInferenceOperator
28+
<<<<<<< HEAD
2829
MONetBundleInferenceOperator
30+
=======
31+
MonainnUNetBundleInferenceOperator
32+
>>>>>>> dacfaa9 (Add nnUNet segmentation application and dependencies)
2933
MonaiSegInferenceOperator
3034
PNGConverterOperator
3135
PublisherOperator
@@ -48,6 +52,7 @@
4852
from .dicom_utils import EquipmentInfo, ModelInfo, random_with_n_digits, save_dcm_file, write_common_modules
4953
from .inference_operator import InferenceOperator
5054
from .monai_bundle_inference_operator import BundleConfigNames, IOMapping, MonaiBundleInferenceOperator
55+
from .monai_nnunet_bundle_inference_operator import MonainnUNetBundleInferenceOperator
5156
from .monai_seg_inference_operator import MonaiSegInferenceOperator
5257
from .monet_bundle_inference_operator import MONetBundleInferenceOperator
5358
from .nii_data_loader_operator import NiftiDataLoader
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copyright 2002 MONAI Consortium
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
from monai.deploy.operators.monai_bundle_inference_operator import MonaiBundleInferenceOperator, get_bundle_config
13+
from monai.deploy.utils.importutil import optional_import
14+
from typing import Any, Dict, Tuple, Union
15+
from monai.deploy.core import Image
16+
from pathlib import Path
17+
MONAI_UTILS = "monai.utils"
18+
nibabel, _ = optional_import("nibabel", "3.2.1")
19+
torch, _ = optional_import("torch", "1.10.2")
20+
21+
NdarrayOrTensor, _ = optional_import("monai.config", name="NdarrayOrTensor")
22+
MetaTensor, _ = optional_import("monai.data.meta_tensor", name="MetaTensor")
23+
PostFix, _ = optional_import("monai.utils.enums", name="PostFix") # For the default meta_key_postfix
24+
first, _ = optional_import("monai.utils.misc", name="first")
25+
ensure_tuple, _ = optional_import(MONAI_UTILS, name="ensure_tuple")
26+
convert_to_dst_type, _ = optional_import(MONAI_UTILS, name="convert_to_dst_type")
27+
Key, _ = optional_import(MONAI_UTILS, name="ImageMetaKey")
28+
MetaKeys, _ = optional_import(MONAI_UTILS, name="MetaKeys")
29+
SpaceKeys, _ = optional_import(MONAI_UTILS, name="SpaceKeys")
30+
Compose_, _ = optional_import("monai.transforms", name="Compose")
31+
ConfigParser_, _ = optional_import("monai.bundle", name="ConfigParser")
32+
MapTransform_, _ = optional_import("monai.transforms", name="MapTransform")
33+
SimpleInferer, _ = optional_import("monai.inferers", name="SimpleInferer")
34+
35+
Compose: Any = Compose_
36+
MapTransform: Any = MapTransform_
37+
ConfigParser: Any = ConfigParser_
38+
__all__ = ["MonainnUNetBundleInferenceOperator"]
39+
40+
41+
class MonainnUNetBundleInferenceOperator(MonaiBundleInferenceOperator):
42+
"""
43+
A specialized operator for performing inference using the MONAI nnUNet bundle.
44+
This operator extends the `MonaiBundleInferenceOperator` to support nnUNet-specific
45+
configurations and prediction logic. It initializes the nnUNet predictor and provides
46+
a method for performing inference on input data.
47+
48+
Attributes
49+
----------
50+
_nnunet_predictor : torch.nn.Module
51+
The nnUNet predictor module used for inference.
52+
53+
Methods
54+
-------
55+
_init_config(config_names)
56+
Initializes the configuration for the nnUNet bundle, including parsing the bundle
57+
configuration and setting up the nnUNet predictor.
58+
predict(data, *args, **kwargs)
59+
Performs inference on the input data using the nnUNet predictor.
60+
"""
61+
62+
def __init__(
63+
self,
64+
*args,
65+
**kwargs,
66+
):
67+
68+
69+
super().__init__(*args, **kwargs)
70+
71+
self._nnunet_predictor : torch.nn.Module = None
72+
73+
74+
def _init_config(self, config_names):
75+
76+
super()._init_config(config_names)
77+
parser = get_bundle_config(str(self._bundle_path), config_names)
78+
parser['bundle_root'] = str(Path(self._bundle_path).parent.parent.parent)
79+
self._parser = parser
80+
81+
self._nnunet_predictor = parser.get_parsed_content("network_def")
82+
83+
def predict(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]:
84+
"""Predicts output using the inferer."""
85+
86+
self._nnunet_predictor.predictor.network = self._model_network
87+
#os.environ['nnUNet_def_n_proc'] = "1"
88+
return self._nnunet_predictor(torch.unsqueeze(data, 0))

0 commit comments

Comments
 (0)