1515
1616from . import ModificationMode
1717from .segmentation_effect import SegmentationEffect
18+ from .segmentation_undo_command import SegmentationLabelMapUndoCommand
1819
1920
2021class SegmentationEffectIslands (SegmentationEffect ):
@@ -26,62 +27,86 @@ def _create_pipeline(self, _view_node: vtkMRMLAbstractViewNode, _parameter: vtkM
2627 # Islands effect does not require a pipeline
2728 return None
2829
29- def apply (
30- self , segment_id : str , max_number_of_segments : int | None = None , minimum_size : int = 0 , split : bool = True
31- ):
30+ def _remove_small_islands (self , minimum_size : int ) -> None :
3231 if not self .is_active :
3332 return
3433
35- island_image = self .get_island_labelmap (segment_id , minimum_size )
34+ island_image = self .get_island_labelmap (minimum_size )
35+ self .modifier .apply_labelmap (island_image )
3636
37+ def _keep_n_biggest_islands (self , number_of_islands : int ):
38+ if not self .is_active :
39+ return
40+
41+ modifier_image = self .modifier .create_modifier_labelmap ()
42+ if number_of_islands <= 0 :
43+ self .modifier .apply_labelmap (modifier_image )
44+ return
45+
46+ island_image = self .get_island_labelmap ()
3747 label_values = vtkIntArray ()
3848 vtkSlicerSegmentationsModuleLogic .GetAllLabelValues (label_values , island_image )
3949 max_label_value = label_values .GetNumberOfTuples ()
40- if max_number_of_segments is not None :
41- max_label_value = min (max_label_value , max_number_of_segments )
42- if not split and max_number_of_segments is None :
43- # Overwrite selected segment's labelmap with filtered labelmap
44- self .modifier .apply_labelmap (island_image )
45- else :
46- modifier_image = self .modifier .create_modifier_labelmap ()
47- threshold = vtkImageThreshold ()
48- threshold .SetInputData (island_image )
49-
50- kept_labels = [int (label_values .GetTuple1 (i )) for i in range (1 , max_label_value )]
51-
52- for i in range (max_label_value ):
53- label_value = int (label_values .GetTuple1 (i ))
54- if i == 0 :
55- # Replace selected segment's labelmap by first island
56- threshold .ThresholdBetween (label_value , label_value )
57- threshold .SetInValue (1 )
58- threshold .SetOutValue (0 )
59- threshold .Update ()
60- modifier_image .DeepCopy (threshold .GetOutput ())
61- # Remove non-kept labels
62- if label_value in kept_labels :
63- continue
64- threshold .ReplaceOutOff ()
65- threshold .ThresholdBetween (label_value , label_value )
66- threshold .SetInValue (0 )
67- threshold .Update ()
68- threshold .SetInputData (threshold .GetOutput ())
50+ if number_of_islands >= max_label_value :
51+ return
6952
70- self .modifier .apply_labelmap (modifier_image )
53+ modifier_image = self .modifier .create_modifier_labelmap ()
54+ threshold = vtkImageThreshold ()
55+ threshold .SetInputData (island_image )
56+ threshold .ReplaceOutOff ()
57+
58+ for i in range (number_of_islands , max_label_value ):
59+ label_value = int (label_values .GetTuple1 (i ))
60+ threshold .ThresholdBetween (label_value , label_value )
61+ threshold .SetInValue (0 )
62+ threshold .Update ()
63+ threshold .SetInputData (threshold .GetOutput ())
64+
65+ modifier_image .DeepCopy (threshold .GetOutput ())
66+ self .modifier .apply_labelmap (modifier_image )
67+
68+ def _split_islands_to_segments (self ): # TODO: Make it undoable
69+ if not self .is_active :
70+ return
71+
72+ island_image = self .get_island_labelmap ()
73+ label_values = vtkIntArray ()
74+ vtkSlicerSegmentationsModuleLogic .GetAllLabelValues (label_values , island_image )
75+
76+ modifier_image = self .modifier .create_modifier_labelmap ()
77+
78+ threshold = vtkImageThreshold ()
79+ threshold .SetInputData (island_image )
7180
72- if max_label_value > 1 :
81+ # Replace selected segment's labelmap by first island
82+ initial_label_value = int (label_values .GetTuple1 (0 ))
83+ threshold .ThresholdBetween (initial_label_value , initial_label_value )
84+ threshold .SetInValue (initial_label_value )
85+ threshold .SetOutValue (0 )
86+ threshold .Update ()
87+ modifier_image .DeepCopy (threshold .GetOutput ())
88+
89+ # Create labelmap without first segment
90+ threshold .SetInValue (0 )
91+ threshold .ReplaceOutOff ()
92+ threshold .ThresholdBetween (initial_label_value , initial_label_value )
93+ threshold .Update ()
94+
95+ with self .modifier .group_undo_commands (f"{ __class__ } - Split { self .modifier .active_segment_id } " ):
96+ self .modifier .apply_labelmap (modifier_image )
97+ with SegmentationLabelMapUndoCommand .push_state_change (self .modifier .segmentation ):
7398 modifier_image .DeepCopy (threshold .GetOutput ())
7499 vtkSlicerSegmentationsModuleLogic .ImportLabelmapToSegmentationNode (
75100 modifier_image ,
76101 self .modifier .segmentation .segmentation_node ,
77- self .modifier .segmentation .get_segment (segment_id ).GetName (),
102+ self .modifier .segmentation .get_segment (self . modifier . active_segment_id ).GetName (),
78103 )
79- self .modifier .segmentation .segmentation_modified .emit ()
104+ self .modifier .segmentation .segmentation_modified .emit ()
80105
81- def get_island_labelmap (self , segment_id : str , minimum_size : int = 0 ) -> vtkOrientedImageData :
106+ def get_island_labelmap (self , minimum_size : int = 0 ) -> vtkOrientedImageData :
82107 source_image_data = self .modifier .get_source_image_data ()
83108
84- segment_labelmap = self .modifier .get_segment_labelmap (segment_id )
109+ segment_labelmap = self .modifier .get_segment_labelmap (self . modifier . active_segment_id )
85110 cast_in = vtkImageCast ()
86111 cast_in .SetInputData (segment_labelmap )
87112 cast_in .SetOutputScalarTypeToUnsignedInt ()
@@ -100,3 +125,12 @@ def get_island_labelmap(self, segment_id: str, minimum_size: int = 0) -> vtkOrie
100125 island_image .SetImageToWorldMatrix (image_to_world_matrix )
101126
102127 return island_image
128+
129+ def keep_largest_island (self ) -> None :
130+ self ._keep_n_biggest_islands (1 ) # TODO: test, pass to 1
131+
132+ def remove_small_islands (self , min_voxel_size : int ) -> None :
133+ self ._remove_small_islands (min_voxel_size )
134+
135+ def split_islands_to_segments (self ) -> None :
136+ self ._split_islands_to_segments ()
0 commit comments