1、创建相同的目录结构:
import os
src_dir = "./CT"
dst_dir = "./nii"
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
for folder in os.listdir(src_dir):
if os.path.isdir(os.path.join(src_dir, folder)):
os.makedirs(os.path.join(dst_dir, folder), exist_ok=True)
2、复制原文件夹,删除非t2序列图像:
import os
import pydicom
def delete_non_t2_files(root_dir):
for subdir, _, files in os.walk(root_dir):
for file in files:
if file.endswith('.dcm'):
file_path = os.path.join(subdir, file)
try:
ds = pydicom.dcmread(file_path)
if 'SeriesDescription' in ds:
series_description = ds.SeriesDescription.lower()
if 't2' not in series_description and 'T2' not in series_description:
os.remove(file_path)
print(f"Deleted: {file_path}")
except Exception as e:
print(f"Error reading {file_path}: {e}")
root_dir = './dcm_bak'
delete_non_t2_files(root_dir)
输出所有dcm图像的唯一序列描述、序列号、图像数:
import os
import pydicom
def get_unique_series_info(folder_path):
unique_series_info = {}
max_uid_length = 0
for root, dirs, files in os.walk(folder_path):
for file in files:
if file.endswith('.dcm'):
dicom_path = os.path.join(root, file)
try:
ds = pydicom.dcmread(dicom_path)
if 'SeriesDescription' in ds and 'SeriesInstanceUID' in ds:
series_description = ds.SeriesDescription
series_instance_uid = ds.SeriesInstanceUID
max_uid_length = max(max_uid_length, len(series_instance_uid))
if series_description not in unique_series_info:
unique_series_info[series_description] = {'SeriesInstanceUID': series_instance_uid, 'ImageCount': 1}
else:
unique_series_info[series_description]['ImageCount'] += 1
except Exception as e:
print(f"Error reading DICOM file: {dicom_path}")
return unique_series_info, max_uid_length
folder_path = './images'
unique_series_info, max_uid_length = get_unique_series_info(folder_path)
max_desc_length = max([len(desc) for desc in unique_series_info.keys()])
for desc, info in unique_series_info.items():
desc_padding = max_desc_length - len(desc)
uid_padding = max_uid_length - len(info['SeriesInstanceUID'])
print(f"{desc}{' ' * desc_padding} | {info['SeriesInstanceUID']}{' ' * uid_padding} | {info['ImageCount']}")
3、dcm转nii:
import os
import pydicom
import shutil
import tempfile
import dicom2nifti
import random
import time
import numpy as np
random.seed(time.time())
random_number = random.randint(1, 100)
def preprocessDicoms(dicom_folder, output_folder):
series_dict = {}
series_instance_dict = {}
study_instance_uid = str(random_number)
for root, dirs, files in os.walk(dicom_folder):
for file in files:
dicom_path = os.path.join(root, file)
try:
ds = pydicom.dcmread(dicom_path, force=True)
if 'StudyInstanceUID' in ds:
study_instance_uid = ds.StudyInstanceUID
if 'SeriesInstanceUID' in ds:
series_uid = ds.SeriesInstanceUID
series_description = ds.SeriesDescription
if series_uid in series_dict:
series_dict[series_uid].append(ds)
else:
series_dict[series_uid] = [ds]
except pydicom.errors.InvalidDicomError:
pass
except Exception as e:
pass
for series_uid, file_list in series_dict.items():
if len(file_list) > 10:
sorted_files = sorted(file_list, key=lambda x: x.InstanceNumber)
instance_numbers = [int(ds.InstanceNumber) for ds in sorted_files]
if instance_numbers != list(range(1, max(instance_numbers) + 1)):
series_instance_dict[series_uid] = "排序不连续"
continue
rows = sorted_files[0].Rows
columns = sorted_files[0].Columns
pixel_spacing = sorted_files[0].PixelSpacing if 'PixelSpacing' in sorted_files[0] else None
slice_thickness_exist = 0
if "SliceThickness" in sorted_files[0]: # 判断SliceThickness属性是否存在,存在就利用
slice_thickness = sorted_files[0].SliceThickness
slice_thickness_exist = 1
else:
slice_thickness = None
for ds in sorted_files:
if slice_thickness_exist == 1:
if ds.Rows != rows or ds.Columns != columns or (pixel_spacing and ds.PixelSpacing != pixel_spacing) or ds.SliceThickness != slice_thickness:
series_instance_dict[series_uid] = "属性不一致"
break
else:
if ds.Rows != rows or ds.Columns != columns or (pixel_spacing and ds.PixelSpacing != pixel_spacing):
series_instance_dict[series_uid] = "属性不一致"
break
else:
with tempfile.TemporaryDirectory() as temp_folder:
for ds in sorted_files:
if 'PixelData' in ds:
shutil.copy2(ds.filename, temp_folder)
else:
series_instance_dict[series_uid] = "缺乏 PixelData 数据"
break
study_instance_uid = sorted_files[0].StudyInstanceUID
series_instance_uid = sorted_files[0].SeriesInstanceUID
sop_instance_uid = sorted_files[0].SOPInstanceUID
series_instance_dict[series_instance_uid] = "转换成功"
if os.listdir(temp_folder):
temp_output_folder = os.path.join(temp_folder, "output")
os.makedirs(temp_output_folder)
dicom2nifti.convert_directory(temp_folder, temp_output_folder)
for file in os.listdir(temp_output_folder):
if file.endswith(".nii.gz"):
src = os.path.join(temp_output_folder, file)
dst = os.path.join(output_folder, f"{series_instance_uid}.nii.gz")
shutil.move(src, dst)
else:
series_instance_dict[series_uid] = "文件数量不足"
return study_instance_uid, series_instance_dict
import os
dicom_folder = "./dcm_bak"
output_folder = "./nii"
dicom_folders = [os.path.join(dicom_folder, d) for d in os.listdir(dicom_folder) if os.path.isdir(os.path.join(dicom_folder, d))]
for folder in dicom_folders:
study_instance_uid, series_instance_dict = preprocessDicoms(folder, os.path.join(output_folder, os.path.basename(folder)))
print(f"处理完成 - Study Instance UID: {study_instance_uid}")
for series_uid, status in series_instance_dict.items():
print(f"Series Instance UID: {series_uid} - 状态: {status}")
4、生成空的mask.nii.gz:
import os
import nibabel as nib
import numpy as np
root_dir = './nii'
for subdir, dirs, files in os.walk(root_dir):
for file in files:
if file.endswith('.nii.gz'):
file_path = os.path.join(subdir, file)
img = nib.load(file_path)
data = img.get_fdata()
affine = img.affine
cyst_mask = np.zeros(data.shape, dtype=np.uint8)
cyst_file = file.replace('.nii.gz', '_cyst.nii.gz')
cyst_path = os.path.join(subdir, cyst_file)
nib.save(nib.Nifti1Image(cyst_mask, affine), cyst_path)
5、验证,统计指定后缀文件数量:
import os
main_dir = "./nii"
total_nii_files = 0
for root, dirs, files in os.walk(main_dir):
for file in files:
if file.endswith(".nii.gz"):
total_nii_files += 1
print(f"总共有 {total_nii_files} 个nii.gz文件")
单张dcm转nii+mask:
import os
import pydicom
import numpy as np
import nibabel as nib
from scipy.ndimage import rotate
input_folder = "./1"
output_folder = "./2"
os.makedirs(output_folder, exist_ok=True)
for file_name in os.listdir(input_folder):
if file_name.endswith(".dcm"):
dcm_data = pydicom.dcmread(os.path.join(input_folder, file_name))
image = dcm_data.pixel_array
# 逆时针旋转90度+镜面翻转
rotated_image = np.rot90(image)
flipped_image = np.fliplr(rotated_image)
file_base_name = os.path.splitext(file_name)[0]
nii_img = nib.Nifti1Image(flipped_image, affine=np.eye(4))
nib.save(nii_img, os.path.join(output_folder, f"{file_base_name}.nii.gz"))
mask_image = np.zeros_like(flipped_image)
mask_nii_img = nib.Nifti1Image(mask_image, affine=np.eye(4))
nib.save(mask_nii_img, os.path.join(output_folder, f"{file_base_name}_mask.nii.gz"))
print("批量转换、旋转和创建空mask文件完成。")
序列多张dcm转nii:
法一:
import os
import pydicom
import shutil
import tempfile
import dicom2nifti
import random
import time
import numpy as np
random.seed(time.time())
random_number = random.randint(1, 100)
def preprocessDicoms(dicom_folder, output_folder):
series_dict = {}
series_instance_dict = {}
study_instance_uid = str(random_number)
for root, dirs, files in os.walk(dicom_folder):
for file in files:
dicom_path = os.path.join(root, file)
try:
ds = pydicom.dcmread(dicom_path, force=True)
if 'StudyInstanceUID' in ds:
study_instance_uid = ds.StudyInstanceUID
if 'SeriesInstanceUID' in ds:
series_uid = ds.SeriesInstanceUID
series_description = ds.SeriesDescription
if series_uid in series_dict:
series_dict[series_uid].append(ds)
else:
series_dict[series_uid] = [ds]
except pydicom.errors.InvalidDicomError:
pass
except Exception as e:
pass
for series_uid, file_list in series_dict.items():
if len(file_list) > 10:
sorted_files = sorted(file_list, key=lambda x: x.InstanceNumber)
instance_numbers = [int(ds.InstanceNumber) for ds in sorted_files]
if instance_numbers != list(range(1, max(instance_numbers) + 1)):
series_instance_dict[series_uid] = "排序不连续"
continue
rows = sorted_files[0].Rows
columns = sorted_files[0].Columns
pixel_spacing = sorted_files[0].PixelSpacing if 'PixelSpacing' in sorted_files[0] else None
slice_thickness_exist = 0
if "SliceThickness" in sorted_files[0]: # 判断SliceThickness属性是否存在,存在就利用
slice_thickness = sorted_files[0].SliceThickness
slice_thickness_exist = 1
else:
slice_thickness = None
for ds in sorted_files:
if slice_thickness_exist == 1:
if ds.Rows != rows or ds.Columns != columns or (pixel_spacing and ds.PixelSpacing != pixel_spacing) or ds.SliceThickness != slice_thickness:
series_instance_dict[series_uid] = "属性不一致"
break
else:
if ds.Rows != rows or ds.Columns != columns or (pixel_spacing and ds.PixelSpacing != pixel_spacing):
series_instance_dict[series_uid] = "属性不一致"
break
else:
with tempfile.TemporaryDirectory() as temp_folder:
for ds in sorted_files:
if 'PixelData' in ds:
shutil.copy2(ds.filename, temp_folder)
else:
series_instance_dict[series_uid] = "缺乏 PixelData 数据"
break
study_instance_uid = sorted_files[0].StudyInstanceUID
series_instance_uid = sorted_files[0].SeriesInstanceUID
sop_instance_uid = sorted_files[0].SOPInstanceUID
series_instance_dict[series_instance_uid] = "转换成功"
if os.listdir(temp_folder):
temp_output_folder = os.path.join(temp_folder, "output")
os.makedirs(temp_output_folder)
dicom2nifti.convert_directory(temp_folder, temp_output_folder)
for file in os.listdir(temp_output_folder):
if file.endswith(".nii.gz"):
src = os.path.join(temp_output_folder, file)
dst = os.path.join(output_folder, f"{series_instance_uid}.nii.gz")
shutil.move(src, dst)
else:
series_instance_dict[series_uid] = "文件数量不足"
return study_instance_uid, series_instance_dict
import os
dicom_folder = "./dcm"
output_folder = "./nii"
dicom_folders = [os.path.join(dicom_folder, d) for d in os.listdir(dicom_folder) if os.path.isdir(os.path.join(dicom_folder, d))]
for folder in dicom_folders:
study_instance_uid, series_instance_dict = preprocessDicoms(folder, os.path.join(output_folder, os.path.basename(folder)))
print(f"处理完成 - Study Instance UID: {study_instance_uid}")
for series_uid, status in series_instance_dict.items():
print(f"Series Instance UID: {series_uid} - 状态: {status}")
法二:(图像命名为SeriesInstanceUID_InstanceNumber.dcm)
import os
import pydicom
import shutil
import tempfile
import dicom2nifti
import random
import time
import numpy as np
import SimpleITK as sitk
random.seed(time.time())
random_number = random.randint(1, 100)
def getSliceLocation(file):
try:
dicom_data = pydicom.dcmread(file)
if 'SliceLocation' in dicom_data:
return float(dicom_data.SliceLocation)
else:
return float('inf')
except Exception as e:
print(f"Error reading {file}: {e}")
return float('inf')
def preprocessDicoms(dicom_folder, output_folder):
series_dict = {}
series_instance_dict = {}
study_instance_uid = str(random_number)
for root, dirs, files in os.walk(dicom_folder):
for file in files:
dicom_path = os.path.join(root, file)
try:
ds = pydicom.dcmread(dicom_path, force=True)
if 'StudyInstanceUID' in ds:
study_instance_uid = ds.StudyInstanceUID
if 'SeriesInstanceUID' in ds:
series_uid = ds.SeriesInstanceUID
series_description = ds.SeriesDescription
if series_uid in series_dict:
series_dict[series_uid].append(dicom_path)
else:
series_dict[series_uid] = [dicom_path]
except pydicom.errors.InvalidDicomError:
pass
except Exception as e:
pass
for series_uid, file_list in series_dict.items():
if len(file_list) > 10:
reader = sitk.ImageSeriesReader()
reader.SetGlobalWarningDisplay(False)
# dicom_names = reader.GetGDCMSeriesFileNames(file_list)
dicom_names = [file for file in file_list]
if all('SliceLocation' in pydicom.dcmread(file) for file in dicom_names):
dicom_names.sort(key = getSliceLocation)
else:
dicom_names.sort(key=lambda x: int(x.split('_')[-1].split('.')[0]))
reader.SetFileNames(dicom_names)
image = reader.Execute()
sitk.WriteImage(image, os.path.join(output_folder, f"{series_uid}.nii.gz"))
series_instance_dict[series_uid] = "转换成功"
return study_instance_uid, series_instance_dict
import os
dicom_folder = "./CT"
output_folder = "/nii"
dicom_folders = [os.path.join(dicom_folder, d) for d in os.listdir(dicom_folder) if os.path.isdir(os.path.join(dicom_folder, d))]
for folder in dicom_folders:
study_instance_uid, series_instance_dict = preprocessDicoms(folder, os.path.join(output_folder, os.path.basename(folder)))
print(f"处理完成 - Study Instance UID: {study_instance_uid}")
for series_uid, status in series_instance_dict.items():
print(f"Series Instance UID: {series_uid} - 状态: {status}")
法三:(批量dicom转nii)
import os
import SimpleITK as sitk
import pydicom
def convert_dicom_to_nifti(dicom_folder, output_folder, image_name):
reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(dicom_folder)
reader.SetFileNames(dicom_names)
image = reader.Execute()
output_path = os.path.join(output_folder, f"{image_name}.nii.gz")
sitk.WriteImage(image,output_path)
def find_dcm_convert_file(root_dir,output_dir):
dcm_dirs = []
dcm_files = []
for root, dirs, files in os.walk(root_dir):
for file in files:
if file.endswith(".dcm"):
dcm_dirs.append(root)
dcm_files.append(os.path.join(root,file))
break
for i,dcm_dir in enumerate(dcm_dirs) :
print(f"{i+1}/{len(dcm_dirs)},sample:{dcm_dir} ")
try:
ds = pydicom.dcmread(dcm_files[i])
if 'SeriesInstanceUID' in ds:
image_name = ds.SeriesInstanceUID
else:
image_name = "image"
except:
image_name = "image"
path = dcm_dir.split(f"{os.path.basename(root_dir)}")[1][1:]
out = os.path.join(output_dir,path)
os.makedirs(out,exist_ok=True)
try:
convert_dicom_to_nifti(dcm_dir, out,image_name)
except:
print(f"{dcm_dir} 文件夹下的DICOM文件转换不成功!")
find_dcm_convert_file("./dicom", "./nii")
nii调窗:(这里选用的是腹部的窗位40窗宽400)
import os
import nibabel as nib
import numpy as np
def adjust_window(file_path, window_center, window_width):
try:
img = nib.load(file_path)
data = img.get_fdata()
min_value = window_center - window_width / 2
max_value = window_center + window_width / 2
data_adjusted = np.clip(data, min_value, max_value)
img_adjusted = nib.Nifti1Image(data_adjusted, img.affine, img.header)
output_file = file_path.replace(".nii.gz", ".nii.gz")
nib.save(img_adjusted, output_file)
print(f"窗宽窗位调整完成: {output_file}")
except Exception as e:
print(f"处理文件 {file_path} 时出错: {str(e)}")
main_dir = "./nii"
for root, dirs, files in os.walk(main_dir):
for file in files:
if file.endswith(".nii.gz"):
file_path = os.path.join(root, file)
adjust_window(file_path, 40, 400)