Spaces:
Runtime error
Runtime error
| import os | |
| import matplotlib.pyplot as plt | |
| from monai.losses import DiceCELoss | |
| from monai.inferers import sliding_window_inference | |
| from monai.transforms import ( | |
| EnsureChannelFirstd, | |
| Compose, | |
| LoadImaged, | |
| Orientationd, | |
| ScaleIntensityRanged, | |
| Rotate90d, | |
| ) | |
| from monai.networks.nets import UNETR | |
| from monai.data import ( | |
| SmartCacheDataset, | |
| ) | |
| import numpy as np | |
| import torch | |
| import gradio as gr | |
| import matplotlib.pyplot as plt | |
| import torch | |
| import nibabel as nib | |
| import numpy as np | |
| import SimpleITK as sitk | |
| def dcm2nii(dcms_path, nii_path): | |
| # 1.构建dicom序列文件阅读器,并执行(即将dicom序列文件“打包整合”) | |
| reader = sitk.ImageSeriesReader() | |
| dicom_names = reader.GetGDCMSeriesFileNames(dcms_path) | |
| reader.SetFileNames(dicom_names) | |
| image2 = reader.Execute() | |
| # 2.将整合后的数据转为array,并获取dicom文件基本信息 | |
| image_array = sitk.GetArrayFromImage(image2) # z, y, x | |
| origin = image2.GetOrigin() # x, y, z | |
| print(origin) | |
| spacing = image2.GetSpacing() # x, y, z | |
| print(spacing) | |
| direction = image2.GetDirection() # x, y, z | |
| print(direction) | |
| # 3.将array转为img,并保存为.nii.gz | |
| image3 = sitk.GetImageFromArray(image_array) | |
| image3.SetSpacing(spacing) | |
| image3.SetDirection(direction) | |
| image3.SetOrigin(origin) | |
| sitk.WriteImage(image3, nii_path) | |
| def calculate_volume(mask_image_path): | |
| # 读取分割结果的图像文件 | |
| mask_image = sitk.ReadImage(mask_image_path) | |
| # 获取图像的大小、原点和间距 | |
| size = mask_image.GetSize() | |
| origin = mask_image.GetOrigin() | |
| spacing = mask_image.GetSpacing() | |
| # 将 SimpleITK 图像转换为 NumPy 数组 | |
| mask_array = sitk.GetArrayFromImage(mask_image) | |
| # if len(np.unique(mask_array)) != 5: | |
| # print(mask_image_path[-15:-12]) | |
| # print(np.unique(mask_array)) | |
| # 计算非零像素的数量 | |
| one_voxels = (mask_array == 1).sum() | |
| two_voxels = (mask_array == 2).sum() | |
| three_voxels = (mask_array == 3).sum() | |
| four_voxels = (mask_array == 4).sum() | |
| # print(one_voxels,two_voxels,three_voxels,four_voxels) | |
| # 计算像素的体积(以立方毫米为单位) | |
| voxel_volume_mm3 = spacing[0] * spacing[1] * spacing[2] | |
| # 计算体积(以 mm³ 为单位) | |
| V_Right_ventricular_cistern = one_voxels * voxel_volume_mm3 / 1000.0 | |
| V_Right_cerebral_sulcus = two_voxels * voxel_volume_mm3 / 1000.0 | |
| V_Left_ventricular_cistern = three_voxels * voxel_volume_mm3 / 1000.0 | |
| V_Left_cerebral_sulcus = four_voxels * voxel_volume_mm3 / 1000.0 | |
| # 如果需要以其他单位(例如 cm³)显示,请进行适当的单位转换 | |
| # volume_cm3 = volume_mm3 / 1000.0 | |
| return size,spacing,V_Right_ventricular_cistern, V_Right_cerebral_sulcus, V_Left_ventricular_cistern, V_Left_cerebral_sulcus | |
| def process_nii_file(input_nii_file, slice, mode): | |
| if mode == "Step1:Segment": | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| root_dir = "./" | |
| model = UNETR( | |
| in_channels=1, | |
| out_channels=5, | |
| img_size=(96, 96, 16), | |
| feature_size=16, | |
| hidden_size=768, | |
| mlp_dim=3072, | |
| num_heads=12, | |
| pos_embed="perceptron", | |
| norm_name="instance", | |
| res_block=True, | |
| dropout_rate=0.0, | |
| ).to(device) | |
| model.load_state_dict(torch.load(os.path.join(root_dir, "best_metric_model67v2.pth"), map_location=torch.device('cpu'))) # CPU map | |
| test_transforms = Compose( | |
| [ | |
| LoadImaged(keys=["image"]), | |
| EnsureChannelFirstd(keys=["image"]), | |
| Orientationd(keys=["image"], axcodes="RAS"), | |
| ScaleIntensityRanged( | |
| keys=["image"], | |
| a_min=-50, | |
| a_max=100, | |
| b_min=0.0, | |
| b_max=1.0, | |
| clip=True, | |
| ), | |
| Rotate90d(keys=["image"], k=1) | |
| # ResizeWithPadOrCropd(keys=["image"], spatial_size=(512, 512, 16)), | |
| ] | |
| ) | |
| test_file = [{'image':input_nii_file.name}] | |
| test_image = SmartCacheDataset(data=test_file, transform=test_transforms)[0]['image'] | |
| with torch.no_grad(): | |
| inputs = torch.unsqueeze(test_image, 1).cpu() ################################### .cuda() -> .cpu() | |
| val_outputs = sliding_window_inference(inputs, (96, 96, 16), 8, model, overlap=0.8) | |
| # Display the images | |
| fig1 = plt.figure() | |
| plt.title("image") | |
| plt.axis('off') # Remove axis | |
| plt.imshow(inputs.cpu().numpy()[0, 0, :, :, slice], cmap="gray") | |
| fig2 = plt.figure() | |
| plt.title("output") | |
| plt.axis('off') # Remove axis | |
| plt.imshow(torch.argmax(val_outputs, dim=1).detach().cpu()[0, :, :, slice]) | |
| val_outputs = torch.argmax(val_outputs, dim=1).detach().cpu()[0, :, :, :] | |
| val_outputs = val_outputs.numpy().astype('int16') | |
| # val_outputs = np.transpose(val_outputs, (2, 1, 0)) | |
| val_outputs = np.rot90(val_outputs, k=3) | |
| val_outputs = nib.Nifti1Image(val_outputs, np.eye(4)) | |
| nib.save(val_outputs, f'D:/{input_nii_file.name[-15:-7]}_mask.nii.gz') | |
| return ["指定切片分割结果如下, mask文件已保存至D:/", fig1, fig2] | |
| if mode == "Step2:Volumn": | |
| maskFilePath = input_nii_file.name | |
| size,spacing,V_Right_ventricular_cistern, V_Right_cerebral_sulcus, V_Left_ventricular_cistern, V_Left_cerebral_sulcus = calculate_volume(maskFilePath) | |
| vol = f"""右侧脑室脑池的体积为{V_Right_ventricular_cistern}cm³\n 右侧脑沟的体积为{V_Right_cerebral_sulcus}cm³\n 左侧脑室脑池的体积为{V_Left_ventricular_cistern}cm³\n 左侧脑沟的体积为{V_Left_cerebral_sulcus}cm³""" | |
| fig1 = plt.figure() | |
| fig2 = plt.figure() | |
| return [vol, fig1, fig2] | |
| # Define the Gradio interface | |
| iface = gr.Interface( | |
| fn=process_nii_file, | |
| inputs= | |
| [gr.File(file_count='single', file_types=['.nii.gz']), | |
| gr.Slider(0, 24, value=8, label="Select Slice", step=1), | |
| gr.Radio( | |
| ["Step1:Segment", "Step2:Volumn"], label="mode" | |
| ), | |
| ], | |
| outputs=[gr.Text(label="Output"), gr.Plot(label="image"), gr.Plot(label="mask")], # Display both "image" and "output" | |
| ) | |
| iface.launch() | |