3131ImageReader : Any = ImageReader_
3232if not image_reader_ok_ :
3333 ImageReader = object # for 'class InMemImageReader(ImageReader):' to work
34+ is_no_channel , _ = optional_import ("monai.data.utils" , name = "is_no_channel" )
3435decollate_batch , _ = optional_import ("monai.data" , name = "decollate_batch" )
3536sliding_window_inference , _ = optional_import ("monai.inferers" , name = "sliding_window_inference" )
3637simple_inference , _ = optional_import ("monai.inferers" , name = "SimpleInferer" )
3738ensure_tuple , _ = optional_import (MONAI_UTILS , name = "ensure_tuple" )
3839MetaKeys , _ = optional_import (MONAI_UTILS , name = "MetaKeys" )
3940SpaceKeys , _ = optional_import (MONAI_UTILS , name = "SpaceKeys" )
41+ TraceKeys , _ = optional_import (MONAI_UTILS , name = "TraceKeys" )
4042Compose_ , _ = optional_import ("monai.transforms" , name = "Compose" )
4143# Dynamic class is not handled so make it Any for now: https://github.com/python/mypy/issues/2477
4244Compose : Any = Compose_
4345
46+ cp , has_cp = optional_import ("cupy" )
47+
4448from monai .deploy .core import AppContext , Condition , ConditionType , Fragment , Image , OperatorSpec , Resource
4549
4650from .inference_operator import InferenceOperator
@@ -362,6 +366,7 @@ def compute(self, op_input, op_output, context):
362366 self ._executing = True
363367 try :
364368 input_image = op_input .receive (self ._input_name_image )
369+
365370 if not input_image :
366371 raise ValueError ("Input is None." )
367372 op_output .emit (self .compute_impl (input_image , context ), self ._output_name_seg )
@@ -592,7 +597,7 @@ def _get_meta_dict(self, img: Image) -> Dict:
592597 return meta_dict
593598
594599
595- # Reuse MONAI code for the derived ImageReader
600+ # Reuse MONAI code for the derived ImageReader as it is not exposed
596601def _copy_compatible_dict (from_dict : Dict , to_dict : Dict ):
597602 if not isinstance (to_dict , dict ):
598603 raise ValueError (f"to_dict must be a Dict, got { type (to_dict )} ." )
@@ -601,7 +606,7 @@ def _copy_compatible_dict(from_dict: Dict, to_dict: Dict):
601606 datum = from_dict [key ]
602607 if isinstance (datum , np .ndarray ) and np_str_obj_array_pattern .search (datum .dtype .str ) is not None :
603608 continue
604- to_dict [key ] = datum
609+ to_dict [key ] = str ( TraceKeys . NONE ) if datum is None else datum # NoneType to string for default_collate
605610 else :
606611 affine_key , shape_key = MetaKeys .AFFINE , MetaKeys .SPATIAL_SHAPE
607612 if affine_key in from_dict and not np .allclose (from_dict [affine_key ], to_dict [affine_key ]):
@@ -616,12 +621,16 @@ def _copy_compatible_dict(from_dict: Dict, to_dict: Dict):
616621 )
617622
618623
619- def _stack_images (image_list : List , meta_dict : Dict ):
624+ def _stack_images (image_list : list , meta_dict : dict , to_cupy : bool = False ):
620625 if len (image_list ) <= 1 :
621626 return image_list [0 ]
622- if meta_dict .get (MetaKeys .ORIGINAL_CHANNEL_DIM , None ) not in ( "no_channel" , None ):
627+ if not is_no_channel ( meta_dict .get (MetaKeys .ORIGINAL_CHANNEL_DIM , None )):
623628 channel_dim = int (meta_dict [MetaKeys .ORIGINAL_CHANNEL_DIM ])
629+ if to_cupy and has_cp :
630+ return cp .concatenate (image_list , axis = channel_dim )
624631 return np .concatenate (image_list , axis = channel_dim )
625632 # stack at a new first dim as the channel dim, if `'original_channel_dim'` is unspecified
626633 meta_dict [MetaKeys .ORIGINAL_CHANNEL_DIM ] = 0
634+ if to_cupy and has_cp :
635+ return cp .stack (image_list , axis = 0 )
627636 return np .stack (image_list , axis = 0 )
0 commit comments