Skip to content

Editorial changes to correct typos, rename parameters, and add comments #526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ blockquote p {
}

/* Mermaid
to avoid the lable text being cut off
to avoid the label text being cut off
*/
.edgeTerminals {
font-size: 9px !important;
Expand Down
2 changes: 1 addition & 1 deletion docs/source/developing_with_sdk/packaging_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ It is required that the application configuration yaml file as well as the depen
### Basic Usage of MONAI Application Packager

```bash
monai-deploy package <APP_PATH> --config <COMFIG> --tag <TAG> --platform <x64-workstation> [--models <MODEL_PATH>] [--log-level <LEVEL>] [-h]
monai-deploy package <APP_PATH> --config <CONFIG> --tag <TAG> --platform <x64-workstation> [--models <MODEL_PATH>] [--log-level <LEVEL>] [-h]
```

#### Required Arguments
Expand Down
2 changes: 1 addition & 1 deletion docs/source/getting_started/tutorials/mednist_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jupyter-lab
<div style="text-align: center;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/WwjilJFHuU4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>Video may show the use of previous SDK verson.</p>
<p>Video may show the use of previous SDK version.</p>
</div>
```

Expand Down
2 changes: 1 addition & 1 deletion docs/source/getting_started/tutorials/monai_bundle_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jupyter-lab
<div style="text-align: center;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/nivgfD4pwWE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>Video may show the use of previous SDK verson.</p>
<p>Video may show the use of previous SDK version.</p>
</div>
```

Expand Down
2 changes: 1 addition & 1 deletion docs/source/release_notes/v0.3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This operator uses [Clara Viz](https://pypi.org/project/clara-viz/) to provide i

### STL Surface Mesh Conversion Operator

This operator converts a volume image to surface mesh, in [STL file format](https://en.wikipedia.org/wiki/STL_(file_format)). Its API allows the client to control if smoothing needs to be applied, and if only keeping the largest connected component; the latter is useful when muliple disjoint segments are in a volume image, and the application needs to control if all or only the largest to be included in the output.
This operator converts a volume image to surface mesh, in [STL file format](https://en.wikipedia.org/wiki/STL_(file_format)). Its API allows the client to control if smoothing needs to be applied, and if only keeping the largest connected component; the latter is useful when multiple disjoint segments are in a volume image, and the application needs to control if all or only the largest to be included in the output.

## What's fixed/updated

Expand Down
2 changes: 1 addition & 1 deletion docs/source/release_notes/v0.4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

The new operator, `MONAI Bundle Inference Operator`, is intended to automate the inference with a MONAI Bundle in TorchScript with the following functionalities:
- Parse the model metadata and extra configuration data in the TorchScript file
- Instanciate MONAI transforms and inferer objects per bundle configuration data
- Instantiate MONAI transforms and inferer objects per bundle configuration data
- Convert input/output of the operator to and from model network input
- Support named model and can be used in a multi-model application

Expand Down
2 changes: 1 addition & 1 deletion docs/source/release_notes/v0.5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- Generated DICOM instances as AI evidence now have the attribute <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.12.html#table_C.12-1">(0008,0201) Timezone Offset From UTC</a>, in addition to the DICOM date and time which are set with values from the underlying operating system. The OS is expected to be synchronized with a known good timing source and have the correct timezone setting
- Generated DICOM instance file names are now based on the SOP instance UID
- Support DICOM instance level attribute matching in the DICOM Series Selection Operator
- Operators and example applications are verified to be re-runable without needing to reinitialize the application object or re-load the AI model network. This will allow a main function or an external script to instantiate the application object once and use it to process multiple discreet inputs, either in a batch processing mode or in a long running service
- Operators and example applications are verified to be re-runable without needing to reinitialize the application object or re-load the AI model network. This will allow a main function or an external script to instantiate the application object once and use it to process multiple discrete inputs, either in a batch processing mode or in a long running service
- Tutorials, in Jupyter notebooks, are re-organized and updated
- Reference added for <a href="https://github.com/Project-MONAI/monai-deploy/releases">MONAI Deploy Express</a> for hosting MAPs in development environments
- Removed is the reference to the deprecated MONAI Inference Service
Expand Down
2 changes: 1 addition & 1 deletion docs/srs.md
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ The SDK shall allow the packaging of the application in a standardized format so

### Background

Please refer to [MONAI Application Packge Spec](https://github.com/Project-MONAI/monai-deploy-experimental/blob/main/guidelines/monai-application-package.md)for details.
Please refer to [MONAI Application Package Spec](https://github.com/Project-MONAI/monai-deploy-experimental/blob/main/guidelines/monai-application-package.md)for details.

### Verification Strategy

Expand Down
2 changes: 1 addition & 1 deletion examples/apps/ai_unetr_seg_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def compose(self):
_algorithm_family = codes.DCM.ArtificialIntelligence
_algorithm_version = "0.1.0"

# List of (Segment name, [Code menaing str]), not including background which is value of 0.
# List of (Segment name, [Code meaning str]), not including background which is value of 0.
# User must provide correct codes, which can be looked at, e.g.
# https://bioportal.bioontology.org/ontologies/SNOMEDCT
# Alternatively, consult the concept and code dictionaries in PyDicom
Expand Down
8 changes: 4 additions & 4 deletions examples/apps/ai_unetr_seg_app/unetr_seg_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class UnetrSegOperator(Operator):

def __init__(
self,
frament: Fragment,
fragment: Fragment,
*args,
app_context: AppContext,
model_path: Path,
Expand All @@ -71,13 +71,13 @@ def __init__(
self.model_path = model_path
self.output_folder = output_folder
self.output_folder.mkdir(parents=True, exist_ok=True)
self.fragement = frament # Cache and later pass the Fragment/Application to contained operator(s)
self.app_fragment = fragment # Cache and later pass the Fragment/Application to contained operator(s)
self.app_context = app_context
self.input_name_image = "image"
self.output_name_seg = "seg_image"
self.output_name_saved_images_folder = "saved_images_folder"

super().__init__(frament, *args, **kwargs)
super().__init__(fragment, *args, **kwargs)

def setup(self, spec: OperatorSpec):
spec.input(self.input_name_image)
Expand All @@ -102,7 +102,7 @@ def compute(self, op_input, op_output, context):

# Delegates inference and saving output to the built-in operator.
infer_operator = MonaiSegInferenceOperator(
self.fragement,
self.app_fragment,
roi_size=(
96,
96,
Expand Down
4 changes: 2 additions & 2 deletions examples/apps/breast_density_classifier_app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Sample data and a torchscript model can be downloaded from https://drive.google.
python app.py -i <input_dir> -o <out_dir> -m <breast_density_model>
```

## Package the application as a MONAI Application Package (contianer image)
## Package the application as a MONAI Application Package (container image)
In order to build the MONAI App Package, go a level up and execute the following command.
```
monai-deploy package breast_density_classification_app -m <breast_density_model> -c breast_density_classifer_app/app.yaml --tag breast_density:0.1.0 --platform x64-workstation -l DEBUG
Expand All @@ -20,4 +20,4 @@ monai-deploy package breast_density_classification_app -m <breast_density_model>
monai-deploy run breast_density-x64-workstation-dgpu-linux-amd64:0.1.0 -i <input_dir> -o <output_dir>
```

Once the container exits successfully, check the results in the output directory. There should be a newly creeated DICOM instance file and a `output.json` file containing the classification results.
Once the container exits successfully, check the results in the output directory. There should be a newly created DICOM instance file and a `output.json` file containing the classification results.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ClassifierOperator(Operator):

def __init__(
self,
frament: Fragment,
fragment: Fragment,
*args,
model_name: Optional[str] = "",
app_context: AppContext,
Expand All @@ -67,7 +67,7 @@ def __init__(
# The name of the optional input port for passing data to override the output folder path.
self.input_name_output_folder = "output_folder"

# The output folder set on the object can be overriden at each compute by data in the optional named input
# The output folder set on the object can be overridden at each compute by data in the optional named input
self.output_folder = output_folder

# Need the name when there are multiple models loaded
Expand All @@ -80,7 +80,7 @@ def __init__(

self.model = self._get_model(self.app_context, self.model_path, self._model_name)

super().__init__(frament, *args, **kwargs)
super().__init__(fragment, *args, **kwargs)

def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):
"""Load the model with the given name from context or model path
Expand Down Expand Up @@ -116,7 +116,7 @@ def _convert_dicom_metadata_datatype(self, metadata: Dict):
if not metadata:
return metadata

# Try to convert data type for the well knowned attributes. Add more as needed.
# Try to convert data type for the well known attributes. Add more as needed.
if metadata.get("SeriesInstanceUID", None):
try:
metadata["SeriesInstanceUID"] = str(metadata["SeriesInstanceUID"])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
import logging
from pathlib import Path
import torch
from diffusers import StableDiffusionPipeline
from monai.deploy.core import AppContext, Application
from PIL import Image
import numpy as np
import argparse
import logging

import torch
from diffusers import StableDiffusionPipeline

from monai.deploy.core import Application


class App(Application):
name = "Diffusion Image App"
description = "Simple application showing diffusion to generate Images"
def compose(self):
model_id = "Nihirc/Prompt2MedImage"
device = "cuda"
parser = argparse.ArgumentParser()
parser.add_argument("--input_prompt", type=str, default="Generate a X-ray")
parser.add_argument("--output", type=str, default="./out.jpg")
args = parser.parse_args()

input_prompt = args.input_prompt
output_path = args.output
print("Input Prompt: ", input_prompt)
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipe = pipe.to(device)
prompt = "Show me an X ray pevic fracture"
image = pipe(prompt).images[0]
image.save(output_path)
name = "Diffusion Image App"
description = "Simple application showing diffusion to generate Images"

def compose(self):
model_id = "Nihirc/Prompt2MedImage"
device = "cuda"
parser = argparse.ArgumentParser()
parser.add_argument("--input_prompt", type=str, default="Generate a X-ray")
parser.add_argument("--output", type=str, default="./out.jpg")
args = parser.parse_args()

input_prompt = args.input_prompt
output_path = args.output
print("Input Prompt: ", input_prompt)
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipe = pipe.to(device)
prompt = "Show me an X ray pevic fracture"
image = pipe(prompt).images[0]
image.save(output_path)


if __name__ == "__main__":
logging.info(f"Begin {__name__}")
App().run()
logging.info(f"End {__name__}")



logging.info(f"Begin {__name__}")
App().run()
logging.info(f"End {__name__}")
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class MedNISTClassifierOperator(Operator):

def __init__(
self,
frament: Fragment,
fragment: Fragment,
*args,
app_context: AppContext,
model_name: Optional[str] = "",
Expand All @@ -127,7 +127,7 @@ def __init__(
# The name of the optional input port for passing data to override the output folder path.
self.input_name_output_folder = "output_folder"

# The output folder set on the object can be overriden at each compute by data in the optional named input
# The output folder set on the object can be overridden at each compute by data in the optional named input
self.output_folder = output_folder

# Need the name when there are multiple models loaded
Expand All @@ -138,7 +138,7 @@ def __init__(
self.model = self._get_model(self.app_context, self.model_path, self._model_name)

# This needs to be at the end of the constructor.
super().__init__(frament, *args, **kwargs)
super().__init__(fragment, *args, **kwargs)

def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):
"""Load the model with the given name from context or model path
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/simple_imaging_app/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
# TAG-NUM-gHEX
mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
if not mo:
# unparseable. Maybe git-describe is misbehaving?
# unparsable. Maybe git-describe is misbehaving?
pieces["error"] = ("unable to parse git-describe output: '%s'"
% describe_out)
return pieces
Expand Down
4 changes: 2 additions & 2 deletions examples/apps/simple_imaging_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ def compose(self):
output_data_path = Path(app_context.output_path)
logging.info(f"sample_data_path: {sample_data_path}")

# Please note that the Application object, self, is passed as the first positonal argument
# Please note that the Application object, self, is passed as the first positional argument
# and the others as kwargs.
# Also note the CountCondition of 1 on the first operator, indicating to the application executor
# to invoke this operator, hence the pipleline, only once.
# to invoke this operator, hence the pipeline, only once.
sobel_op = SobelOperator(self, CountCondition(self, 1), input_path=sample_data_path, name="sobel_op")
median_op = MedianOperator(self, name="median_op")
gaussian_op = GaussianOperator(self, output_folder=output_data_path, name="gaussian_op")
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/simple_imaging_app/gaussian_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class GaussianOperator(Operator):
single input:
an image array object
single output:
an image arrary object, without enforcing a downsteam receiver
an image array object, without enforcing a downstream receiver

Besides, this operator also saves the image file in the given output folder.
"""
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/core/domain/dicom_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def get_sop_instances(self):
return self._sop_instances

# Properties named after DICOM Series module attribute keywords
# There are two required (Type 1) attrbutes for a series:
# There are two required (Type 1) attributes for a series:
# Keyword: SeriesInstanceUID, Tag: (0020,000E)
# Keyword: Modality, Tag: (0008,0060)
#
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/core/domain/dicom_sop_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@


class DICOMSOPInstance(Domain):
"""This class representes a SOP Instance.
"""This class represents a SOP Instance.

An attribute can be looked up with a slice ([group_number, element number]).
"""
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/core/domain/dicom_study.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_all_series(self):
return list(self._series_dict.values())

# Properties named after DICOM Study module attribute keywords
# There is only one required (Type 1) attrbute for a study:
# There is only one required (Type 1) attribute for a study:
# Keyword: StudyInstanceUID, Tag: (0020,000D)
#
@property
Expand Down
4 changes: 2 additions & 2 deletions monai/deploy/operators/clara_viz_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ClaraVizOperator(Operator):
seg_image: Image object of the segmentation image derived from the input image.
"""

def __init__(self, fragement: Fragment, *args, **kwargs):
def __init__(self, fragment: Fragment, *args, **kwargs):
"""Constructor of the operator.

Args:
Expand All @@ -43,7 +43,7 @@ def __init__(self, fragement: Fragment, *args, **kwargs):
self.input_name_image = "image"
self.input_name_seg_image = "seg_image"

super().__init__(fragement, *args, **kwargs)
super().__init__(fragment, *args, **kwargs)

def setup(self, spec: OperatorSpec):
spec.input(self.input_name_image)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ class DICOMEncapsulatedPDFWriterOperator(Operator):
None

File output:
Generaed DICOM instance file in the provided output folder.
Generated DICOM instance file in the provided output folder.
"""

# File extension for the generated DICOM Part 10 file.
DCM_EXTENSION = ".dcm"
# The default output folder for saveing the generated DICOM instance file.
# The default output folder for saving the generated DICOM instance file.
DEFAULT_OUTPUT_FOLDER = Path(os.getcwd()) / "output"

def __init__(
Expand Down Expand Up @@ -249,7 +249,7 @@ def _is_pdf_bytes(self, content: bytes):
return True


# Commenting out the following as pttype complains about the contructor for no reason
# Commenting out the following as pttype complains about the constructor for no reason
# def test(test_copy_tags: bool = True):
# from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
# from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/operators/dicom_seg_writer_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def __init__(
Object encapsulating the description of each segment present in the segmentation.
output_folder: Folder for file output, overridden by named input on compute.
Defaults to current working dir's child folder, output.
custom_tags: Optonal[Dict[str, str]], optional
custom_tags: Optional[Dict[str, str]], optional
Dictionary for setting custom DICOM tags using Keywords and str values only
omit_empty_frames: bool, optional
Whether to omit frames that contain no segmented pixels from the output segmentation.
Expand Down
6 changes: 3 additions & 3 deletions monai/deploy/operators/dicom_text_sr_writer_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class DICOMTextSRWriterOperator(Operator):
None

File output:
Generaed DICOM instance file in the provided output folder.
Generated DICOM instance file in the provided output folder.
"""

# File extension for the generated DICOM Part 10 file.
DCM_EXTENSION = ".dcm"
# The default output folder for saveing the generated DICOM instance file.
# The default output folder for saving the generated DICOM instance file.
# DEFAULT_OUTPUT_FOLDER = Path(os.path.join(os.path.dirname(__file__))) / "output"
DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output"

Expand Down Expand Up @@ -259,7 +259,7 @@ def write(self, content_text, dicom_series: Optional[DICOMSeries], output_dir: P
self._logger.info(f"DICOM SOP instance saved in {file_path}")


# Commenting out the following as pttype complains about the contructor for no reason
# Commenting out the following as pttype complains about the constructor for no reason
# def test(test_copy_tags: bool = True):
# from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
# from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
Expand Down
Loading