diff --git a/examples/apps/ct_bone_seg_app/__init__.py b/examples/apps/ct_bone_seg_app/__init__.py new file mode 100644 index 00000000..c8f6f0d1 --- /dev/null +++ b/examples/apps/ct_bone_seg_app/__init__.py @@ -0,0 +1,8 @@ +import os +import sys + +_current_dir = os.path.abspath(os.path.dirname(__file__)) +if sys.path and os.path.abspath(sys.path[0]) != _current_dir: + sys.path.insert(0, _current_dir) + +del _current_dir diff --git a/examples/apps/ct_bone_seg_app/__main__.py b/examples/apps/ct_bone_seg_app/__main__.py new file mode 100644 index 00000000..412a8ca1 --- /dev/null +++ b/examples/apps/ct_bone_seg_app/__main__.py @@ -0,0 +1,4 @@ +from app import App + +if __name__ == "__main__": + App(do_run=True) diff --git a/examples/apps/ct_bone_seg_app/app.py b/examples/apps/ct_bone_seg_app/app.py new file mode 100644 index 00000000..fe63bfa1 --- /dev/null +++ b/examples/apps/ct_bone_seg_app/app.py @@ -0,0 +1,36 @@ +# Copyright 2022 MONAI Consortium +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ct_bone_operator import CtBoneOperator +from dicom_to_mhd import DicomToMhd + +from monai.deploy.core import Application, resource + + +@resource(cpu=1, gpu=1) +class App(Application): + """This is a CT Bone application.""" + + name = "ct_bone_app" + description = "CT Bone segmentation app." + version = "0.1.0" + + def compose(self): + """This application has two operators.""" + + dcm_to_mhd = DicomToMhd() + bone_op = CtBoneOperator() + + self.add_flow(dcm_to_mhd, bone_op) + + +if __name__ == "__main__": + App(do_run=True) diff --git a/examples/apps/ct_bone_seg_app/ct_bone_operator.py b/examples/apps/ct_bone_seg_app/ct_bone_operator.py new file mode 100644 index 00000000..62b168d2 --- /dev/null +++ b/examples/apps/ct_bone_seg_app/ct_bone_operator.py @@ -0,0 +1,50 @@ +# Copyright 2022 MONAI Consortium +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import monai.deploy.core as md +from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext + + +@md.input("image", DataPath, IOType.DISK) +@md.output("image", DataPath, IOType.DISK) +@md.env(pip_packages=["patchelf", "clcat"]) +class CtBoneOperator(Operator): + """This Operator implements CT Bone segmentation""" + + def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext): + + input_path = op_input.get().path + inputfile = "" + + if input_path.is_dir(): + inputfile = os.path.join(input_path, "intermediate_mhd_data.mhd") + elif input_path.is_file(): + inputfile = str(input_path) + else: + raise IOError("Input path invalid from input context") + + output_path = op_output.get().path + output_path.mkdir(parents=True, exist_ok=True) + outputfile = os.path.join(output_path, "bone_mask.mhd") + + import clcat.ct_algos as cact + + status = cact.ct_bone(inputfile, outputfile) + + if input_path.is_dir(): + os.remove(inputfile) + inputrawfile = os.path.join(input_path, "intermediate_mhd_data.raw") + os.remove(inputrawfile) + + if status != 0: + raise Exception("Bone segmentation failed") diff --git a/examples/apps/ct_bone_seg_app/dicom_to_mhd.py b/examples/apps/ct_bone_seg_app/dicom_to_mhd.py new file mode 100644 index 00000000..1f38143f --- /dev/null +++ b/examples/apps/ct_bone_seg_app/dicom_to_mhd.py @@ -0,0 +1,55 @@ +# Copyright 2022 MONAI Consortium +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import monai.deploy.core as md +from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext + + +@md.input("image", DataPath, IOType.DISK) +@md.output("image", DataPath, IOType.DISK) +@md.env(pip_packages=["SimpleITK==1.2.4"]) +class DicomToMhd(Operator): + """ + If input is DICOM: This operator converts a dicom image to a mhd image + If input is MHD: This operator sets the output path to input path + """ + + def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext): + + input_path = op_input.get().path + if input_path.is_dir(): + import SimpleITK as SITK + + current_file_dir = os.path.abspath(os.path.dirname(__file__)) + op_output.set(DataPath(current_file_dir)) + output_path = op_output.get().path + + output_file_path = os.path.join(output_path, "intermediate_mhd_data.mhd") + + reader = SITK.ImageSeriesReader() + dicom_names = reader.GetGDCMSeriesFileNames(str(input_path)) + reader.SetFileNames(dicom_names) + + fixed = reader.Execute() + SITK.WriteImage(fixed, output_file_path) + else: + if os.path.isfile(input_path): + extension = os.path.splitext(input_path)[1] + if extension == ".mhd": + # Input path is a MHD file + # Setting output folder as input folder + op_output.set(DataPath(input_path)) + else: + raise IOError("Unsupported extension") + else: + raise IOError("Invalid input path")