@@ -86,14 +86,6 @@ def aorta_seg(
8686 nora_tag = "None" ,
8787 preview = False ,
8888 task = "total" ,
89- # roi_subset = [
90- # "vertebrae_T12",
91- # "vertebrae_L1",
92- # "vertebrae_L2",
93- # "vertebrae_L3",
94- # "vertebrae_L4",
95- # "vertebrae_L5",
96- # ],
9789 roi_subset = None ,
9890 statistics = False ,
9991 radiomics = False ,
@@ -150,6 +142,36 @@ class AorticCalciumSegmentation(InferenceClass):
150142
151143 def __init__ (self ):
152144 super ().__init__ ()
145+ # Label number for each vertebra
146+ self .vertebrae_num = {
147+ 26 : "vertebrae_S1" ,
148+ 27 : "vertebrae_L5" ,
149+ 28 : "vertebrae_L4" ,
150+ 29 : "vertebrae_L3" ,
151+ 30 : "vertebrae_L2" ,
152+ 31 : "vertebrae_L1" ,
153+ 32 : "vertebrae_T12" ,
154+ 33 : "vertebrae_T11" ,
155+ 34 : "vertebrae_T10" ,
156+ 35 : "vertebrae_T9" ,
157+ 36 : "vertebrae_T8" ,
158+ 37 : "vertebrae_T7" ,
159+ 38 : "vertebrae_T6" ,
160+ 39 : "vertebrae_T5" ,
161+ 40 : "vertebrae_T4" ,
162+ 41 : "vertebrae_T3" ,
163+ 42 : "vertebrae_T2" ,
164+ 43 : "vertebrae_T1" ,
165+ 44 : "vertebrae_C7" ,
166+ 45 : "vertebrae_C6" ,
167+ 46 : "vertebrae_C5" ,
168+ 47 : "vertebrae_C4" ,
169+ 48 : "vertebrae_C3" ,
170+ 49 : "vertebrae_C2" ,
171+ 50 : "vertebrae_C1" }
172+
173+ self .vertebrae_name = {v : k for k , v in self .vertebrae_num .items ()}
174+
153175
154176 def __call__ (self , inference_pipeline ):
155177
@@ -171,9 +193,17 @@ def __call__(self, inference_pipeline):
171193 if not os .path .exists (os .path .join (self .output_dir , "metrics/" )):
172194 os .makedirs (os .path .join (self .output_dir , "metrics/" ))
173195
174- ct = inference_pipeline .medical_volume .get_fdata ()
175- aorta_mask = inference_pipeline .segmentation .get_fdata ().astype (np .int8 ) == 52
176- spine_mask = inference_pipeline .spine_segmentation .get_fdata () > 0
196+ inference_pipeline .ct = inference_pipeline .medical_volume .get_fdata ()
197+ inference_pipeline .aorta_mask = (inference_pipeline .segmentation .get_fdata ().round ().astype (np .int8 ) == 52 )
198+ inference_pipeline .spine_mask = inference_pipeline .spine_segmentation .get_fdata ().round ().astype (np .uint8 )
199+
200+ # convert to the index of TotalSegmentator
201+ if inference_pipeline .spine_model_name == 'stanford_spine_v0.0.1' :
202+ tmp_mask = inference_pipeline .spine_mask > 0
203+ inference_pipeline .spine_mask [tmp_mask ] = inference_pipeline .spine_mask [tmp_mask ] + 11
204+ del tmp_mask
205+
206+ spine_mask_bin = inference_pipeline .spine_mask > 0
177207
178208 # Determine the target number of pixels
179209 pix_size = np .array (inference_pipeline .medical_volume .header .get_zooms ())
@@ -186,11 +216,11 @@ def __call__(self, inference_pipeline):
186216
187217 # Run calcification detection pipeline
188218 calcification_results = self .detectCalcifications (
189- ct ,
190- aorta_mask ,
191- exclude_mask = spine_mask ,
219+ inference_pipeline . ct ,
220+ inference_pipeline . aorta_mask ,
221+ exclude_mask = spine_mask_bin ,
192222 remove_size = 3 ,
193- return_dilated_mask = True ,
223+ return_dilated_mask = True ,
194224 return_eroded_aorta = True ,
195225 threshold = inference_pipeline .args .threshold ,
196226 dilation_iteration = target_aorta_dil ,
@@ -200,6 +230,7 @@ def __call__(self, inference_pipeline):
200230
201231 inference_pipeline .calc_mask = calcification_results ["calc_mask" ]
202232 inference_pipeline .calcium_threshold = calcification_results ["threshold" ]
233+ inference_pipeline .dilated_aorta_mask = calcification_results ["dilated_mask" ]
203234
204235 # save masks
205236 inference_pipeline .saveArrToNifti (
@@ -227,21 +258,21 @@ def __call__(self, inference_pipeline):
227258 )
228259
229260 inference_pipeline .saveArrToNifti (
230- spine_mask ,
261+ inference_pipeline . spine_mask ,
231262 os .path .join (
232263 inference_pipeline .output_dir_segmentation_masks , "spine_mask.nii.gz"
233264 ),
234265 )
235266
236267 inference_pipeline .saveArrToNifti (
237- aorta_mask ,
268+ inference_pipeline . aorta_mask ,
238269 os .path .join (
239270 inference_pipeline .output_dir_segmentation_masks , "aorta_mask.nii.gz"
240271 ),
241272 )
242273
243274 inference_pipeline .saveArrToNifti (
244- ct ,
275+ inference_pipeline . ct ,
245276 os .path .join (inference_pipeline .output_dir_segmentation_masks , "ct.nii.gz" ),
246277 )
247278
@@ -393,7 +424,6 @@ def detectCalcifications(
393424 """
394425 Choose threshold
395426 """
396-
397427 if threshold == "adaptive" :
398428 # calc_thres = eroded_ct_points.max()
399429
@@ -450,7 +480,7 @@ def detectCalcifications(
450480 struct = struct ,
451481 num_iteration = dilation_iteration ,
452482 operation = "dilate" ,
453- )
483+ ). astype ( np . int8 )
454484
455485 if show_time :
456486 print ("dilation mask time: {:.2f}" .format (time .time () - t0 ))
@@ -627,33 +657,9 @@ def __init__(self):
627657
628658 def __call__ (self , inference_pipeline ):
629659 calc_mask = inference_pipeline .calc_mask
630- spine_mask = inference_pipeline .spine_segmentation .get_fdata ().astype (np .int8 )
631- """ 26: "vertebrae_S1",
632- 27: "vertebrae_L5",
633- 28: "vertebrae_L4",
634- 29: "vertebrae_L3",
635- 30: "vertebrae_L2",
636- 31: "vertebrae_L1",
637- 32: "vertebrae_T12",
638- 33: "vertebrae_T11",
639- 34: "vertebrae_T10",
640- 35: "vertebrae_T9",
641- 36: "vertebrae_T8",
642- 37: "vertebrae_T7",
643- 38: "vertebrae_T6",
644- 39: "vertebrae_T5",
645- 40: "vertebrae_T4",
646- 41: "vertebrae_T3",
647- 42: "vertebrae_T2",
648- 43: "vertebrae_T1",
649- 44: "vertebrae_C7",
650- 45: "vertebrae_C6",
651- 46: "vertebrae_C5",
652- 47: "vertebrae_C4",
653- 48: "vertebrae_C3",
654- 49: "vertebrae_C2",
655- 50: "vertebrae_C1","""
656-
660+ spine_mask = inference_pipeline .spine_mask
661+ aorta_mask = inference_pipeline .aorta_mask
662+
657663 t12_level = np .where ((spine_mask == 32 ).sum (axis = (0 , 1 )))[0 ]
658664 l1_level = np .where ((spine_mask == 31 ).sum (axis = (0 , 1 )))[0 ]
659665
@@ -666,7 +672,7 @@ def __call__(self, inference_pipeline):
666672 print ("WARNNG: could not locate L1, using T12 only.." )
667673 sep_plane = t12_level [0 ]
668674 else :
669- raise ValueError ("Could not locate either T12 or L1, aborting.." )
675+ raise ValueError ("Could not locate T12 and L1, aborting.." )
670676
671677 planes = np .zeros_like (spine_mask , dtype = np .int8 )
672678 planes [:, :, sep_plane ] = 1
@@ -679,7 +685,8 @@ def __call__(self, inference_pipeline):
679685 inference_pipeline .output_dir_segmentation_masks , "t12_plane.nii.gz"
680686 ),
681687 )
682-
688+ inference_pipeline .t12_plane = planes
689+
683690 inference_pipeline .pix_dims = inference_pipeline .medical_volume .header [
684691 "pixdim"
685692 ][1 :4 ]
@@ -696,9 +703,11 @@ def __call__(self, inference_pipeline):
696703 if i == 0 :
697704 calc_mask_region = calc_mask [:, :, :sep_plane ]
698705 ct = ct_full [:, :, :sep_plane ]
706+ aorta_mask_region = aorta_mask [:, :, :sep_plane ]
699707 elif i == 1 :
700708 calc_mask_region = calc_mask [:, :, sep_plane :]
701709 ct = ct_full [:, :, sep_plane :]
710+ aorta_mask_region = aorta_mask [:, :, sep_plane :]
702711
703712 labelled_calc , num_lesions = ndimage .label (calc_mask_region )
704713
@@ -732,6 +741,10 @@ def __call__(self, inference_pipeline):
732741 metrics ["volume_total" ] = calc_vol
733742
734743 metrics ["num_calc" ] = num_lesions
744+
745+ # percent of the aorta calcificed
746+ metrics ['perc_calcified' ] = (calc_mask_region .sum () / aorta_mask_region .sum ()) * 100
747+
735748
736749 if inference_pipeline .args .threshold == "agatston" :
737750 if num_lesions == 0 :
0 commit comments