@@ -3761,9 +3761,31 @@ def setUp(self):
37613761 )
37623762 self ._seg_pix [5 :15 , 3 :8 ] = 1
37633763
3764+ self ._seg_pix_multisegment = np .zeros (
3765+ (1 , * tpm_size , 3 ),
3766+ dtype = np .uint8 ,
3767+ )
3768+ self ._seg_pix_multisegment [0 , 5 :15 , 3 :8 , 0 ] = 1
3769+ self ._seg_pix_multisegment [0 , 23 :42 , 13 :18 , 1 ] = 1
3770+ self ._seg_pix_multisegment [0 , 45 :48 , 25 :30 , 1 ] = 1
3771+
3772+ self ._seg_pix_fractional = np .zeros (
3773+ tpm_size ,
3774+ dtype = np .float32 ,
3775+ )
3776+ self ._seg_pix_fractional [5 :15 , 3 :8 ] = 0.5
3777+ self ._seg_pix_fractional [3 :5 , 10 :12 ] = 1.0
3778+
37643779 self ._n_downsamples = 3
37653780 self ._downsampled_pix_arrays = [self ._seg_pix ]
3781+ self ._downsampled_pix_arrays_multisegment = [self ._seg_pix_multisegment ]
3782+ self ._downsampled_pix_arrays_fractional = [self ._seg_pix_fractional ]
37663783 seg_pil = Image .fromarray (self ._seg_pix )
3784+ seg_pil_fractional = Image .fromarray (self ._seg_pix_fractional )
3785+ seg_pil_multisegment = [
3786+ Image .fromarray (self ._seg_pix_multisegment [0 , :, :, i ])
3787+ for i in range (self ._seg_pix_multisegment .shape [3 ])
3788+ ]
37673789 pyramid_uid = UID ()
37683790 self ._source_pyramid = [deepcopy (self ._sm_image )]
37693791 self ._source_pyramid [0 ].PyramidUID = pyramid_uid
@@ -3780,6 +3802,19 @@ def setUp(self):
37803802 )
37813803 self ._downsampled_pix_arrays .append (resized )
37823804
3805+ resized_fractional = np .array (
3806+ seg_pil_fractional .resize (out_size , Image .Resampling .BILINEAR )
3807+ )
3808+ self ._downsampled_pix_arrays_fractional .append (resized_fractional )
3809+
3810+ resized_multisegment = np .stack (
3811+ [
3812+ im .resize (out_size , Image .Resampling .NEAREST ) for im in seg_pil_multisegment
3813+ ],
3814+ axis = - 1
3815+ )[None ]
3816+ self ._downsampled_pix_arrays_multisegment .append (resized_multisegment )
3817+
37833818 # Mock lower-resolution source images. No need to have their pixel
37843819 # data correctly set as it isn't used. Just update the relevant
37853820 # metadata
@@ -3820,6 +3855,21 @@ def setUp(self):
38203855 )
38213856 ),
38223857 ]
3858+ self ._segment_descriptions_multi = [
3859+ SegmentDescription (
3860+ segment_number = i ,
3861+ segment_label = f'Segment #{ i } ' ,
3862+ segmented_property_category = self ._segmented_property_category ,
3863+ segmented_property_type = self ._segmented_property_type ,
3864+ algorithm_type = SegmentAlgorithmTypeValues .AUTOMATIC .value ,
3865+ algorithm_identification = AlgorithmIdentificationSequence (
3866+ name = 'bla' ,
3867+ family = codes .DCM .ArtificialIntelligence ,
3868+ version = 'v1'
3869+ )
3870+ )
3871+ for i in range (1 , 4 )
3872+ ]
38233873
38243874 def test_pyramid_factors (self ):
38253875 downsample_factors = [2.0 , 5.0 ]
@@ -3925,6 +3975,83 @@ def test_multiple_source_single_pixel_array(self):
39253975 pix
39263976 )
39273977
3978+ def test_multiple_source_single_pixel_array_multisegment (self ):
3979+ # Test construction when given multiple source images and a single
3980+ # segmentation image
3981+ segs = create_segmentation_pyramid (
3982+ source_images = self ._source_pyramid ,
3983+ pixel_arrays = [self ._seg_pix_multisegment ],
3984+ segmentation_type = SegmentationTypeValues .BINARY ,
3985+ segment_descriptions = self ._segment_descriptions_multi ,
3986+ series_instance_uid = UID (),
3987+ series_number = 1 ,
3988+ manufacturer = 'Foo' ,
3989+ manufacturer_model_name = 'Bar' ,
3990+ software_versions = '1' ,
3991+ device_serial_number = '123' ,
3992+ )
3993+
3994+ assert len (segs ) == len (self ._source_pyramid )
3995+ for pix , seg in zip (self ._downsampled_pix_arrays_multisegment , segs ):
3996+ assert hasattr (seg , 'PyramidUID' )
3997+ seg_pix = seg .get_total_pixel_matrix ()
3998+ print ("pixel array" , pix .shape , seg_pix .shape )
3999+ print ("pixel array" , pix .max (), seg_pix .max ())
4000+ assert np .array_equal (
4001+ seg .get_total_pixel_matrix (),
4002+ pix [0 ]
4003+ )
4004+
4005+ def test_multiple_source_single_pixel_array_float (self ):
4006+ # Test construction when given multiple source images and a single
4007+ # segmentation image
4008+ segs = create_segmentation_pyramid (
4009+ source_images = self ._source_pyramid ,
4010+ pixel_arrays = [self ._seg_pix .astype (np .float32 )],
4011+ segmentation_type = SegmentationTypeValues .BINARY ,
4012+ segment_descriptions = self ._segment_descriptions ,
4013+ series_instance_uid = UID (),
4014+ series_number = 1 ,
4015+ manufacturer = 'Foo' ,
4016+ manufacturer_model_name = 'Bar' ,
4017+ software_versions = '1' ,
4018+ device_serial_number = '123' ,
4019+ )
4020+
4021+ assert len (segs ) == len (self ._source_pyramid )
4022+ for pix , seg in zip (self ._downsampled_pix_arrays , segs ):
4023+ assert hasattr (seg , 'PyramidUID' )
4024+ assert np .array_equal (
4025+ seg .get_total_pixel_matrix (combine_segments = True ),
4026+ pix
4027+ )
4028+
4029+ def test_multiple_source_single_pixel_array_fractional (self ):
4030+ # Test construction when given multiple source images and a single
4031+ # segmentation image
4032+ segs = create_segmentation_pyramid (
4033+ source_images = self ._source_pyramid ,
4034+ pixel_arrays = [self ._seg_pix_fractional ],
4035+ segmentation_type = SegmentationTypeValues .FRACTIONAL ,
4036+ segment_descriptions = self ._segment_descriptions ,
4037+ series_instance_uid = UID (),
4038+ series_number = 1 ,
4039+ manufacturer = 'Foo' ,
4040+ manufacturer_model_name = 'Bar' ,
4041+ software_versions = '1' ,
4042+ device_serial_number = '123' ,
4043+ max_fractional_value = 200 ,
4044+ )
4045+
4046+ assert len (segs ) == len (self ._source_pyramid )
4047+ for pix , seg in zip (self ._downsampled_pix_arrays_fractional , segs ):
4048+ assert hasattr (seg , 'PyramidUID' )
4049+ assert np .allclose (
4050+ seg .get_total_pixel_matrix (combine_segments = False )[:, :, 0 ],
4051+ pix ,
4052+ atol = 0.005 , # 1/200
4053+ )
4054+
39284055 def test_multiple_source_multiple_pixel_arrays (self ):
39294056 # Test construction when given multiple source images and multiple
39304057 # segmentation images
@@ -3948,3 +4075,53 @@ def test_multiple_source_multiple_pixel_arrays(self):
39484075 seg .get_total_pixel_matrix (combine_segments = True ),
39494076 pix
39504077 )
4078+
4079+ def test_multiple_source_multiple_pixel_arrays_multisegment (self ):
4080+ # Test construction when given multiple source images and multiple
4081+ # segmentation images
4082+ segs = create_segmentation_pyramid (
4083+ source_images = self ._source_pyramid ,
4084+ pixel_arrays = self ._downsampled_pix_arrays_multisegment ,
4085+ segmentation_type = SegmentationTypeValues .BINARY ,
4086+ segment_descriptions = self ._segment_descriptions_multi ,
4087+ series_instance_uid = UID (),
4088+ series_number = 1 ,
4089+ manufacturer = 'Foo' ,
4090+ manufacturer_model_name = 'Bar' ,
4091+ software_versions = '1' ,
4092+ device_serial_number = '123' ,
4093+ )
4094+
4095+ assert len (segs ) == len (self ._source_pyramid )
4096+ for pix , seg in zip (self ._downsampled_pix_arrays_multisegment , segs ):
4097+ assert hasattr (seg , 'PyramidUID' )
4098+ assert np .array_equal (
4099+ seg .get_total_pixel_matrix (),
4100+ pix [0 ]
4101+ )
4102+
4103+ def test_multiple_source_multiple_pixel_arrays_multisegment_labelmap (self ):
4104+ # Test construction when given multiple source images and multiple
4105+ # segmentation images
4106+ mask = np .argmax (self ._seg_pix_multisegment , axis = 3 ).astype (np .uint8 )
4107+ segs = create_segmentation_pyramid (
4108+ source_images = self ._source_pyramid ,
4109+ pixel_arrays = mask ,
4110+ segmentation_type = SegmentationTypeValues .BINARY ,
4111+ segment_descriptions = self ._segment_descriptions_multi ,
4112+ series_instance_uid = UID (),
4113+ series_number = 1 ,
4114+ manufacturer = 'Foo' ,
4115+ manufacturer_model_name = 'Bar' ,
4116+ software_versions = '1' ,
4117+ device_serial_number = '123' ,
4118+ )
4119+
4120+ assert len (segs ) == len (self ._source_pyramid )
4121+ for pix , seg in zip (self ._downsampled_pix_arrays_multisegment , segs ):
4122+ mask = np .argmax (pix , axis = 3 ).astype (np .uint8 )
4123+ assert hasattr (seg , 'PyramidUID' )
4124+ assert np .array_equal (
4125+ seg .get_total_pixel_matrix (combine_segments = True ),
4126+ mask [0 ]
4127+ )
0 commit comments