使用np.load加载DICOM图像失败及维度异常问题求助
图像处理DICOM数据加载问题排查
问题1:IMAGE_SPATIAL_DIMS输出为3而非预期三维形状
运行以下代码时:
import numpy as np ... file_name = "/content/drive/MyDrive/.../1-01.dcm" IMAGE_SPATIAL_DIMS = np.load(file_name)[...,0].shape
预期得到类似(128, 128, 16)的三维形状,实际输出结果为3。
问题2:加载预处理图像时的Pickle错误
- 初始报错:
ValueError: Cannot load file containing pickled data when allow_pickle=False - 设置
allow_pickle=True后仍报错:UnpicklingError: Failed to interpret file '1-01.dcm' as a pickle
预处理代码
import os import sys import shutil import numpy as np import pandas as pd import pydicom as dicom from os.path import join import SimpleITK as sitk from spire.xls import * from spire.xls.common import * import openpyxl as op import time ### Read TrainFold0 Excel Sheet CODE_BASE = os.path.abspath('/content/drive/MyDrive/MasterThesis') TRAIN_XLSX = '/content/drive/MyDrive/MasterThesis/.../Datasets/TrainFold0.xlsx' ### Make DataFrame of 3D Data dataFrame = pd.read_excel(TRAIN_XLSX) ### Create First Row of DataFrame3D dataFrame3D = pd.DataFrame() ### Make 3D Train Data Directory Data3D_path = '/content/drive/MyDrive/MasterThesis/.../Datasets/3DPROSTATEx' if not(os.path.exists(Data3D_path)): os.mkdir(Data3D_path) ### Load an TrainFold Excel File wb = op.load_workbook(filename=TRAIN_XLSX) ws = wb.active ### Read DataFrame of TrainFold Excel File dataFrame = pd.read_excel(TRAIN_XLSX) col_imagePath = dataFrame['image_path'] ### Get the Number of Rows row_num = len(col_imagePath) ### Read the image_path of Every Row last_indx = 0 for row_count in range(row_num): print('row_count: '+str(row_count)) path = col_imagePath[row_count] path_3D = "/".join(path.split('/')[2:-1]) #print(path) #print(path_3D) ### Make Directory for Image3D for i in range(1, len(path_3D.split('/'))+1): if not(os.path.exists(Data3D_path + '/' + "/".join(path_3D.split('/')[:i]))): os.mkdir(Data3D_path + '/' + "/".join(path_3D.split('/')[:i])) ### Make a New Name for 3D Image #e.g : path_3D = 'ProstateX-0030/10-30-2011-NA-MC prostaat kliniek detectie-mc MCPROSKL30-54485/3.000000-t2tsesag-6352' part1 = path_3D.split('/')[0] #e.g: ProstateX-0030 part11 = part1.split('-')[1] #e.g: 0030 part2 = path.split('/')[-1] #e.g: 3.000000-t2tsesag-6352 part21 = part2.split('-')[0] #e.g: 3.000000 part22 = part21.split('.')[0] #e.g: 3 image3D_Name = part11+ '-' + str(part22).rjust(2, '0')+'.dcm' #e.g: 0030-03.dcm #time.sleep(5) ### If Related 3D Image Doesn't Exist Create it if (os.path.exists(Data3D_path +'/'+ path_3D+'/'+image3D_Name)): print(str(image3D_Name)+'Image Does not Exist') ### Get Images in Directory os.chdir('/content/drive/MyDrive/MasterThesis/.../Datasets'+path) entries = os.listdir('/content/drive/MyDrive/MasterThesis/.../Datasets'+path) image3D = [] for entry in entries: ### Check if Entry doesn't Image ,pass away this loop and go to the next entry if not(os.path.isfile(entry)): continue ### Read DICOM Image as a Slice #new_slice = dicom.dcmread(entry).pixel_array ### Read DICOM Image with numpy.load new_slice = np.load(entry) ### Expand Dimension of Slice Image from [Height, Width] to [Height, Width, 1] new_slice3D = np.expand_dims(new_slice, axis=2) if len(image3D)!=0 : ### Append New Slice to 3D Image image3D = np.append(image3D, new_slice3D, axis=2) else: ### Create Frist Slice image3D = new_slice3D ### Save Image3D in Related Directory os.chdir(Data3D_path +'/'+ path_3D) iMAGE_TRAIN_3D = sitk.GetImageFromArray(image3D) sitk.WriteImage(iMAGE_TRAIN_3D, Data3D_path +'/'+ path_3D +'/'+ image3D_Name) ### Export Path of Image3D in DataFrame3D new_row = dataFrame.iloc[[row_count]].copy() ### Concatenate New Row to dataFrame3D dataFrame3D = pd.concat([dataFrame3D, dataFrame.iloc[[row_count]].copy()] , axis=0, ignore_index=True) ### Change Old Path to New Path dataFrame3D.loc[dataFrame3D.index[-1],'image_path'] = Data3D_path+'/'+ path_3D+'/'+ image3D_Name ### Convert DataFrame3D to TrainFold3D Excel File dataFrame3D.to_csv(join(TRAIN_XLSX_PREFIX+'3D.csv'))
问题分析与解决
核心错误根源
你全程误用了np.load()读取DICOM文件:np.load()仅支持读取numpy专属的.npy/.npz格式文件,而DICOM是医学影像专用格式,两者完全不兼容,这是所有问题的起点。
1. 解决shape输出为3的问题
改用DICOM专用库读取文件,再转换为numpy数组获取形状:
方法1:用SimpleITK读取(匹配你预处理时的保存方式)
import SimpleITK as sitk file_name = "/content/drive/MyDrive/.../1-01.dcm" # 读取DICOM文件 sitk_image = sitk.ReadImage(file_name) # 转换为numpy数组(注意顺序为(z, y, x)) image_array = sitk.GetArrayFromImage(sitk_image) # 若需要(y, x, z)的顺序,可转置 IMAGE_SPATIAL_DIMS = image_array.transpose(1, 2, 0).shape
方法2:用pydicom读取
import pydicom file_name = "/content/drive/MyDrive/.../1-01.dcm" ds = pydicom.dcmread(file_name) # 多帧DICOM的pixel_array为(z, y, x)形状 IMAGE_SPATIAL_DIMS = ds.pixel_array.shape
2. 解决Pickle错误问题
直接弃用np.load()读取DICOM文件,改用上述两种DICOM专用读取方式即可,无需调整allow_pickle参数。
预处理代码的关键修正
- 修正切片读取逻辑:把错误的
new_slice = np.load(entry)替换为正确的DICOM读取代码:# 替换原错误代码 ds = dicom.dcmread(entry) new_slice = ds.pixel_array - 修正文件存在判断逻辑:原代码中
if (os.path.exists(...)):逻辑颠倒,应改为:if not os.path.exists(Data3D_path +'/'+ path_3D+'/'+image3D_Name): - 避免工作目录切换:用绝对路径拼接代替
os.chdir,防止路径混乱:slice_dir = '/content/drive/MyDrive/MasterThesis/.../Datasets'+path entries = os.listdir(slice_dir) for entry in entries: entry_path = os.path.join(slice_dir, entry) if not os.path.isfile(entry_path): continue # 后续读取操作使用entry_path - 优化DataFrame保存:把
dataFrame3D.to_csv()移到循环结束后,避免重复写入浪费资源。
内容的提问来源于stack exchange,提问作者zahra mrtz
相关产品推荐
相关产品推荐

