# import nibabel as nib # import matplotlib.pyplot as plt # import numpy as np # import os # from typing import Tuple, Set, Dict, Optional # def load_nifti(file_path: str) -> np.ndarray: # """Load a NIfTI file and return its data array.""" # return nib.load(file_path).get_fdata() # def create_colored_mask(data: np.ndarray) -> np.ndarray: # """Create a colored mask for segmentation visualization. # Args: # data: Input segmentation array # Returns: # RGB mask array # """ # color_dict = { # 1: [144/255, 238/255, 144/255], # Brainstem - Light green # 2: [255/255, 218/255, 150/255], # Right_Eye - Light yellow # 3: [205/255, 170/255, 125/255], # Left_Eye - Brown # 4: [135/255, 206/255, 235/255], # Optic_Chiasm - Sky blue # 5: [255/255, 99/255, 71/255], # Right_Optic_Nerve - Bright coral # 6: [255/255, 160/255, 122/255], # Left_Optic_Nerve - Light coral # 7: [147/255, 112/255, 219/255] # TV - Medium purple # } # mask = np.zeros((*data.shape, 3)) # for label, color in color_dict.items(): # mask_3d = np.dstack([data == label] * 3) # mask = np.where(mask_3d, color, mask) # return mask # def get_brain_bounds(image: np.ndarray, padding_factor: float = 0.15) -> Tuple[int, int, int, int]: # """Get the boundaries of the brain region with adjustable padding. # Args: # image: Input image array # padding_factor: Factor to determine padding around the region of interest # Returns: # Tuple of (rmin, rmax, cmin, cmax) coordinates # """ # mask = image > np.percentile(image, 1) # rows = np.any(mask, axis=1) # cols = np.any(mask, axis=0) # rmin, rmax = np.where(rows)[0][[0, -1]] # cmin, cmax = np.where(cols)[0][[0, -1]] # center_r = (rmin + rmax) // 2 # center_c = (cmin + cmax) // 2 # radius = int(max(rmax - rmin, cmax - cmin) * 0.55) # margin = int(radius * padding_factor) # return ( # max(center_r - radius - margin, 0), # min(center_r + radius + margin, image.shape[0]), # max(center_c - radius - margin, 0), # min(center_c + radius + margin, image.shape[1]) # ) # def check_organs_in_slice(slice_data: np.ndarray) -> Set[str]: # """Check which organs are present in a given slice. # Args: # slice_data: 2D array of the slice # Returns: # Set of organ names present in the slice # """ # organ_dict = { # 1: "Brainstem", # 2: "Right_Eye", # 3: "Left_Eye", # 4: "Optic_Chiasm", # 5: "Right_Optic_Nerve", # 6: "Left_Optic_Nerve", # 7: "TV" # } # unique_labels = set(np.unique(slice_data)) - {0} # return {organ_dict[label] for label in unique_labels if label in organ_dict} # def save_slice(image: np.ndarray, ground_truth: np.ndarray, # prediction: np.ndarray, slice_num: int, # save_path: str) -> None: # """Save comparison visualization of a specific slice. # Args: # image: MRI volume # ground_truth: Ground truth segmentation volume # prediction: Predicted segmentation volume # slice_num: Slice number to visualize # save_path: Path to save the visualization # """ # plt.clf() # fig, axes = plt.subplots(1, 2, figsize=(25, 11)) # plt.subplots_adjust(wspace=0.01) # # Process image # img_slice = np.rot90(image[:, :, slice_num]) # # Get bounds # rmin, rmax, cmin, cmax = get_brain_bounds(img_slice) # # Normalize image for display # img_norm = (img_slice - np.min(img_slice)) / (np.max(img_slice) - np.min(img_slice)) # # Ground Truth # gt_slice = np.rot90(ground_truth[:, :, slice_num]) # gt_mask = create_colored_mask(gt_slice) # axes[0].imshow(img_norm[rmin:rmax, cmin:cmax], cmap='gray') # axes[0].imshow(gt_mask[rmin:rmax, cmin:cmax], alpha=0.5) # axes[0].set_title('Ground Truth', fontsize=32, pad=20, weight='bold') # axes[0].axis('off') # # Prediction # pred_slice = np.rot90(prediction[:, :, slice_num]) # pred_mask = create_colored_mask(pred_slice) # axes[1].imshow(img_norm[rmin:rmax, cmin:cmax], cmap='gray') # axes[1].imshow(pred_mask[rmin:rmax, cmin:cmax], alpha=0.5) # axes[1].set_title('Prediction', fontsize=32, pad=20, weight='bold') # axes[1].axis('off') # plt.savefig(save_path, bbox_inches='tight', dpi=300, pad_inches=0.05) # plt.close() # print(f"Saved slice {slice_num} to: {save_path}") # def main(): # """Main function to run the visualization pipeline.""" # # Load images # base_path = '/mnt/1248/onlylian/nnUNet/nnUNet_raw/Dataset999' # image_mri = load_nifti(os.path.join(base_path, 'imagesTs/T1C_043_0000.nii.gz')) # ground_truth = load_nifti(os.path.join(base_path, 'labelsTs/T1C_043.nii.gz')) # prediction = load_nifti('/mnt/1248/onlylian/T1C/output_predictions/2d/fold_2/T1C_043.nii.gz') # save_dir = '/mnt/1248/onlylian/T1C' # # Analyze slices # total_slices = image_mri.shape[2] # for slice_num in range(total_slices): # gt_organs = check_organs_in_slice(ground_truth[:, :, slice_num]) # pred_organs = check_organs_in_slice(prediction[:, :, slice_num]) # if gt_organs or pred_organs: # print(f"\nSlice {slice_num}:") # print(f"Ground Truth contains: {', '.join(sorted(gt_organs))}") # print(f"Prediction contains: {', '.join(sorted(pred_organs))}") # # Interactive slice selection # while True: # try: # slice_num = int(input("\nEnter slice number to save (-1 to exit): ")) # if slice_num == -1: # break # if 0 <= slice_num < total_slices: # save_path = os.path.join(save_dir, f'comparison_{slice_num:03d}.png') # save_slice(image_mri, ground_truth, prediction, # slice_num, save_path) # else: # print(f"Slice number must be between 0 and {total_slices-1}") # except ValueError: # print("Please enter a valid number") # except Exception as e: # print(f"Error occurred: {str(e)}") # if __name__ == "__main__": # main() import nibabel as nib import matplotlib.pyplot as plt import numpy as np import os from PIL import Image from typing import Tuple, Set, Dict, Optional import io def load_nifti(file_path: str) -> np.ndarray: """Load a NIfTI file and return its data array.""" return nib.load(file_path).get_fdata() def create_colored_mask(data: np.ndarray) -> np.ndarray: """Create a colored mask for segmentation visualization.""" color_dict = { 1: [144/255, 238/255, 144/255], # Brainstem - Light green 2: [255/255, 218/255, 150/255], # Right_Eye - Light yellow 3: [205/255, 170/255, 125/255], # Left_Eye - Brown 4: [135/255, 206/255, 235/255], # Optic_Chiasm - Sky blue 5: [255/255, 99/255, 71/255], # Right_Optic_Nerve - Bright coral 6: [255/255, 160/255, 122/255], # Left_Optic_Nerve - Light coral 7: [147/255, 112/255, 219/255] # TV - Medium purple } mask = np.zeros((*data.shape, 3)) for label, color in color_dict.items(): mask_3d = np.dstack([data == label] * 3) mask = np.where(mask_3d, color, mask) return mask def get_brain_bounds(image: np.ndarray, padding_factor: float = 0.15) -> Tuple[int, int, int, int]: """Get the boundaries of the brain region with adjustable padding.""" mask = image > np.percentile(image, 1) rows = np.any(mask, axis=1) cols = np.any(mask, axis=0) rmin, rmax = np.where(rows)[0][[0, -1]] cmin, cmax = np.where(cols)[0][[0, -1]] center_r = (rmin + rmax) // 2 center_c = (cmin + cmax) // 2 radius = int(max(rmax - rmin, cmax - cmin) * 0.55) margin = int(radius * padding_factor) return ( max(center_r - radius - margin, 0), min(center_r + radius + margin, image.shape[0]), max(center_c - radius - margin, 0), min(center_c + radius + margin, image.shape[1]) ) def create_slice_image(image: np.ndarray, ground_truth: np.ndarray, prediction: np.ndarray, slice_num: int) -> Image.Image: """Create image for a specific slice.""" plt.clf() fig, axes = plt.subplots(1, 2, figsize=(25, 11)) plt.subplots_adjust(wspace=0.01) img_slice = np.rot90(image[:, :, slice_num]) rmin, rmax, cmin, cmax = get_brain_bounds(img_slice) img_norm = (img_slice - np.min(img_slice)) / (np.max(img_slice) - np.min(img_slice)) # Ground Truth gt_slice = np.rot90(ground_truth[:, :, slice_num]) gt_mask = create_colored_mask(gt_slice) axes[0].imshow(img_norm[rmin:rmax, cmin:cmax], cmap='gray') axes[0].imshow(gt_mask[rmin:rmax, cmin:cmax], alpha=0.5) axes[0].set_title('Ground Truth', fontsize=32, pad=20, weight='bold') axes[0].axis('off') # Prediction pred_slice = np.rot90(prediction[:, :, slice_num]) pred_mask = create_colored_mask(pred_slice) axes[1].imshow(img_norm[rmin:rmax, cmin:cmax], cmap='gray') axes[1].imshow(pred_mask[rmin:rmax, cmin:cmax], alpha=0.5) axes[1].set_title('Prediction', fontsize=32, pad=20, weight='bold') axes[1].axis('off') # Convert plot to PIL Image buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', dpi=300, pad_inches=0.05) plt.close() buf.seek(0) return Image.open(buf) def create_animated_gif(image: np.ndarray, ground_truth: np.ndarray, prediction: np.ndarray, start_slice: int, end_slice: int, output_path: str, duration: int = 500) -> None: """Create an animated GIF from a range of slices.""" frames = [] for slice_num in range(start_slice, end_slice + 1): print(f"Processing slice {slice_num}...") frame = create_slice_image(image, ground_truth, prediction, slice_num) frames.append(frame) # Save the animated GIF frames[0].save( output_path, save_all=True, append_images=frames[1:], duration=duration, loop=0 ) print(f"Saved animated GIF to: {output_path}") def main(): """Main function to create the animated visualization.""" # Load images with new paths base_path = '/mnt/1248/onlylian/nnUNet/nnUNet_raw/Dataset999' image_mri = load_nifti(os.path.join(base_path, 'imagesTs/T1C_043_0000.nii.gz')) ground_truth = load_nifti(os.path.join(base_path, 'labelsTs/T1C_043.nii.gz')) prediction = load_nifti('/mnt/1248/onlylian/T1C/output_predictions/2d/fold_2/T1C_043.nii.gz') # Create animated GIF for slices 111-121 output_path = '/mnt/1248/onlylian/T1C/slice_animation.gif' create_animated_gif( image_mri, ground_truth, prediction, start_slice=111, end_slice=121, output_path=output_path, duration=500 # 500ms per frame ) if __name__ == "__main__": main()