t2序列dicom转nii、nii调窗

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)

### CHAOS T2 数据集的相关资源与信息 CHAOS (Combined Healthy Abdominal Organ Segmentation) 是一个多模态医学图像分割挑战的数据集,提供了CT和MRI两种成像方式下的腹部器官分割数据。其中,T2加权MRI序列(T2 SPIR)是该数据集中的一部分[^1]。 #### 数据集下载 CHAOS数据集可以通过官方竞赛网站获取。通常情况下,访问者需要注册并同意使用协议才能下载数据。以下是具体步骤: - 访问官方网站:https://chaos.grand-challenge.org/ - 注册账户并通过电子邮件验证身份。 - 登录后进入“Downloads”页面,找到对应于T2加权MRI的部分进行下载。 需要注意的是,由于医疗影像涉及隐私保护问题,因此可能还需要签署一份数据使用协议书。 #### 使用说明 关于如何利用这些数据开展实验或者训练模型,可以参考一些开源项目作为指导材料。例如,在GitHub上有这样一个仓库专门针对肝脏分割任务实现了U-net算法,并且提到正在补充详细的Readme文件以及依赖环境配置指南[^2]: ```plaintext https://github.com/BUAAXZzz/Unet_liver_seg ``` 尽管上述链接并非专门为CHAOS设计,但它提供了一个良好的起点用于处理类似的医学图像分类或定位工作流。 #### 文件格式 CHAOS中的每种扫描类型都存储为DICOM格式(.dcm),这是一种广泛应用于放射学领域的标准交换形式。对于编程爱好者来说,Python库`pydicom`可以帮助读取解析这类二进制结构;而如果希望快速可视化,则推荐采用3D Slicer软件加载整个系列查看断层效果。 另外值得注意的一点在于标签(mask)部分是以NIfTI (.nii.gz)压缩包的形式给出的,这种三维体素表示非常适合神经网络框架直接消费。换过程中务必确认空间方向一致以免引入人为误差影响最终评估指标得分情况比如Dice系数计算准确性等方面考量因素存在差异时需格外小心对待。 --- ### 实验对比分析 当考虑不同架构在有限标注样本条件下表现优劣程度的时候,可以从以下几个角度切入讨论: 1. **Siamese 架构优势** 表格数据显示所有测试版本均超越基础线DeepLabV3+, 这证明双胞胎网络设计理念确实有助于解决当前场景面临的主要难题即缺乏足够的正负样例配对支持传统监督机制正常运作的需求.[^3] 2. **代理监督作用** 对比单纯依靠交叉熵损失函数引导优化过程的传统做法,C2FCN通过额外增加约束条件使得整体泛化能力得到明显改善, 特别是在小型训练集合上的适应性强很多. 3. **融合策略有效性** 当把两个独立工作的子模块结合起来形成更大规模的整体解决方案之后(C2FCN+), 虽然绝对数值增长幅度不大但是依然体现出正面效应的存在价值不可忽视. 4. **多分支联合训练的好处** 设计含有多个特定目标导向路径(如这里提及到的同时关注前景区域界定精确度之外还兼顾背景类别划分合理性等问题) 的复杂体系往往可以获得更佳的结果呈现出来.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值