【深度学习】肺结节分割项目实战一:处理数据集

主要参考此教程完成的实验

一、LIDC-IDRI数据集简介

官方网站

肺图像数据库协会的图像收集(LIDC-IDRI)包括诊断带有病变注释标记的肺癌筛查胸部CT。这是一个网络公开的国际资源,用于肺癌检测和诊断的计算机辅助诊断(CAD)方法的开发、培训和评估。

数据集包含1018个病例,每个病例包括来自临床胸部CT扫描的图像和一个相关的XML文件,该文件记录了由四名经验丰富的胸部放射科医生进行的两阶段图像注释过程的结果。在最初的盲读阶段,每个放射科医生独立审查每个CT扫描,并标记出属于三种类型之一的病变(“结节>= 3mm”,“结节<3mm”,“非结节>= 3mm”)。在随后的非盲读阶段,每个放射科医生独立地回顾自己的评分以及其他三位放射科医生的匿名评分,以给出最终意见。

二、参数配置lung.conf

病例中有的有结节注释,有的没有结节注释,没有的保存在Clean文件夹:

[prepare_dataset]
lidc_dicom_path = ./LIDC-IDRI
mask_path = ./data/Mask
image_path = ./data/Image
clean_path_image = ./data/Clean/Image
clean_path_mask = ./data/Clean/Mask
meta_path = ./data/Meta/
mask_threshold = 8

[pylidc]
confidence_level = 0.5
padding_size = 512

三、创建数据集prepare_dataset.py:

通过MakeDataSet类的prepare_dataset方法创建数据集和标注信息文件,MakeDataSet实例的属性包括:

  • LIRI_list:遍历保存LIDC_IDRI数据的文件夹,得到包含所有病例文件夹名字的列表:
  • img_path,mask_path:包含结节的肺部图像和掩码的保存路径
  • clean_path_img,clean_path_mask:不包含结节的肺部图像和掩码的保存路径
  • meta_path:结节信息保存路径
  • mask_threshold:最小的结节阈值
  • c_level和padding:生成结节掩码时的输入参数
  • meta:结节信息属性名
patient_idnodule_noslice_nooriginal_imagemask_imagemaliganancyis_canceris_clean
病例id结节编号切片编号图像编号掩码编号恶性程度是否为癌症是否包含结节
class MakeDataSet:
    def __init__(self, LIDC_Patients_list, IMAGE_DIR, MASK_DIR,CLEAN_DIR_IMAGE,CLEAN_DIR_MASK,META_DIR, mask_threshold, padding, confidence_level=0.5):
        self.IDRI_list = LIDC_Patients_list
        self.img_path = IMAGE_DIR
        self.mask_path = MASK_DIR
        self.clean_path_img = CLEAN_DIR_IMAGE
        self.clean_path_mask = CLEAN_DIR_MASK
        self.meta_path = META_DIR
        self.mask_threshold = mask_threshold
        self.c_level = confidence_level
        self.padding = [(padding,padding),(padding,padding),(0,0)]
        self.meta = pd.DataFrame(index=[],columns=['patient_id','nodule_no','slice_no','original_image','mask_image','malignancy','is_cancer','is_clean'])
	def calculate_malignancy(self,nodule):
        # 计算结节恶性程度
    def save_meta(self,meta_list):
        # 保存结节信息到csv文件
    def prepare_dataset(self):
        # 创建数据集
if __name__ == '__main__':
    LIDC_IDRI_list= [f for f in os.listdir(DICOM_DIR) if not f.startswith('.')]
    LIDC_IDRI_list.sort()

    test= MakeDataSet(LIDC_IDRI_list,IMAGE_DIR,MASK_DIR,CLEAN_DIR_IMAGE,CLEAN_DIR_MASK,META_DIR,mask_threshold,padding,confidence_level)
    test.prepare_dataset()

1、使用到的库

  • pylidc:pylidc不仅可用于分析和查询注释数据(不需要访问DICOM图像数据),也能用于处理与LIDC数据集相关联的DICOM文件。
  • pathlib:这个模块提供了用适合不同操作系统的语义表示文件系统路径的类。路径类分为纯路径(提供没有I/O的纯计算操作)和具体路径(继承自纯路径,但也提供I/O操作)。
  • Tqdm 是一个快速,可扩展的Python进度条,可以在 Python 长循环中添加一个进度提示信息,用户只需要封装任意的迭代器 tqdm(iterator)。
  • median_high:高中位数始终是数据集的成员。当数据点的数量为奇数时,将返回中间值。当它是偶数时,将返回两个中间值中较大的一个。

2、生成数据集函数

def prepare_dataset(self):
    # 为image和mask命名
    # 0000,0001,0002,...,0999
    prefix = [str(x).zfill(3) for x in range(1000)]

    # 创建文件夹
    if not os.path.exists(self.img_path):
        os.makedirs(self.img_path)
    if not os.path.exists(self.mask_path):
        os.makedirs(self.mask_path)
    if not os.path.exists(self.clean_path_img):
        os.makedirs(self.clean_path_img)
    if not os.path.exists(self.clean_path_mask):
        os.makedirs(self.clean_path_mask)
    if not os.path.exists(self.meta_path):
        os.makedirs(self.meta_path)

    IMAGE_DIR = Path(self.img_path)
    MASK_DIR = Path(self.mask_path)
    CLEAN_DIR_IMAGE = Path(self.clean_path_img)
    CLEAN_DIR_MASK = Path(self.clean_path_mask)
    
    for patient in tqdm(self.IDRI_list):
        # 处理每个病例
    print("Saved Meta data")
    self.meta.to_csv(self.meta_path+'meta_info.csv',index=False) # 保存数据信息

3、处理每个病例

首先获得当前病例名字:

pid = patient #LIDC-IDRI-0001~

查找到一个名字相符的scan对象:

import pylidc as pl
scan = pl.query(pl.Scan).filter(pl.Scan.patient_id == pid).first()

scan对象中一个结节可能包含多个注释,可以使用pylidc.Scan.cluster_annotations()方法来确定哪些注释是指同一个结节,它使用距离函数来创建一个邻接图,以确定哪些注释在一次扫描中引用了同一个结节:

nodules_annotation = scan.cluster_annotations()

将扫描图像值转换为NumPy数组,便于进行图像处理:

vol = scan.to_volume()
print("Patient ID: {} Dicom Shape: {} Number of Annotated Nodules: {}".format(pid,vol.shape,len(nodules_annotation)))

输出示例:

Patient ID: LIDC-IDRI-0003 Dicom Shape: (512, 512, 140) Number of Annotated Nodules: 4

表示编号LIDC-IDRL-0003的病例的成像尺寸为512*512*140,有4个标注结节。

对注释进行可视化可以得到:

scan.visualize(annotation_groups=nodules_annotation)

在这里插入图片描述

从图中可以看出编号为LIDC-IDRI-0003的病例有四个标注的结节,分别包含不同数量的注释,最多为4个(因为一共有四位医师)。

有的病例中不包含结节注释,应区别处理:

if len(nodules_annotation) > 0:
	# 处理包含结节注释的病例
else:
	# 处理不包含结节注释的病例

4、处理包含结节注释的病例

使用pylidc.utils.consensus()方法获得结节掩码。

输入参数:

  • nodule:聚类后一个结节的注释列表,长度最大为4,例如:

    nodule 1 : [Annotation(id=90,scan_id=14), Annotation(id=93,scan_id=14), Annotation(id=98,scan_id=14), 
    
  • clevel:例如clevel=0.5,那么当各位医师注释的结节分割中有超过50%的结果包含该体素时,体素返回值为1,否则为0。

  • padding:如果提供了整数,则边界框将按此整数数量均匀填充。其他形式的参数可以参考文档。

返回值:

  • mask[ndarray]:是根据clevel生成的注释掩码的布尔值数组。
  • cbbox[tumple]:是一个3元组,可用于在相应位置对图像进行索引,根据不同的padding值,cddox的大小也不同。
  • masks[,list]:是对应于每个Annotation对象的布尔值掩码的列表。掩码列表中的每个掩码具有相同的形状,并在cbbox提供的边界框中进行采样。
for nodule_idx, nodule in enumerate(nodules_annotation): # 遍历每个结节
               
    mask, cbbox, masks = consensus(nodule,self.c_level,self.padding)

    lung_np_array = vol[cbbox]

    malignancy, cancer_label = self.calculate_malignancy(nodule) # 计算恶性程度
    
    for nodule_slice in range(mask.shape[2]):
        # 处理每个CT切片
计算恶性程度

选取所有注释的中高位数:

def calculate_malignancy(self,nodule):
list_of_malignancy =[]
for annotation in nodule:
	list_of_malignancy.append(annotation.malignancy)

malignancy = median_high(list_of_malignancy)
if  malignancy > 3:
	return malignancy,True
elif malignancy < 3:
	return malignancy, False
else:
	return malignancy, 'Ambiguous'
处理每个CT切片

结节像素太小的跳过,有些遮罩尺寸太小。这些可能会阻碍训练:

if np.sum(mask[:,:,nodule_slice]) <= self.mask_threshold:
	continue

对肺实质进行分割(segment_lung函数会在下一篇中单独介绍):

lung_segmented_np_array = segment_lung(lung_np_array[:,:,nodule_slice])

一些值被存储为-0,这可能导致pytorch训练中的数据类型错误:

lung_segmented_np_array[lung_segmented_np_array==-0] =0

每个文件的命名:NI=结节图像,MA=掩码原始:

nodule_name = "{}_NI{}_slice{}".format(pid[-4:],prefix[nodule_idx],prefix[nodule_slice])
mask_name = "{}_MA{}_slice{}".format(pid[-4:],prefix[nodule_idx],prefix[nodule_slice])
meta_list = [pid[-4:],nodule_idx,prefix[nodule_slice],nodule_name,mask_name,malignancy,cancer_label,False]

保存结节信息文件和图像:

 self.save_meta(meta_list)
 np.save(patient_image_dir / nodule_name,lung_segmented_np_array)
 np.save(patient_mask_dir / mask_name,mask[:,:,nodule_slice])

save_meta()函数将结节信息添加到meta列表:

def save_meta(self,meta_list):
    # 将结节信息保存在csv文件中
    tmp = pd.Series(meta_list,index=['patient_id','nodule_no','slice_no','original_image','mask_image','malignancy','is_cancer','is_clean'])
    self.meta = self.meta.append(tmp,ignore_index=True)

5、处理不包含注释的病例

patient_clean_dir_image = CLEAN_DIR_IMAGE / pid
patient_clean_dir_mask = CLEAN_DIR_MASK / pid
Path(patient_clean_dir_image).mkdir(parents=True, exist_ok=True)
Path(patient_clean_dir_mask).mkdir(parents=True, exist_ok=True)

 for slice in range(vol.shape[2]):
        if slice >50:
            break
        # 处理每一个切片

没有结节的切片对应的mask为全是黑色:

lung_segmented_np_array = segment_lung(vol[:,:,slice])
lung_segmented_np_array[lung_segmented_np_array==-0] =0
lung_mask = np.zeros_like(lung_segmented_np_array)

保存图像和对应掩码,将信息添加到meta数组:

nodule_name = "{}_CN001_slice{}".format(pid[-4:],prefix[slice])
mask_name = "{}_CM001_slice{}".format(pid[-4:],prefix[slice])

meta_list = [pid[-4:],slice,prefix[slice],nodule_name,mask_name,0,False,True]
self.save_meta(meta_list)
np.save(patient_clean_dir_image / nodule_name, lung_segmented_np_array)
np.save(patient_clean_dir_mask / mask_name, lung_mask)

将信息保存到meta.csv文件:

print("Saved Meta data")
self.meta.to_csv(self.meta_path+'meta_info.csv',index=False)
  • 14
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 31
    评论
随着深度学习技术的不断发展,数据集已成为深度学习模型训练的关键因素之一。Python作为深度学习和机器学习领域中最常用的语言之一,提供了许多方便的工具和库,可帮助用户更便捷地处理和访问数据集。以下是Python深度学习项目实战数据集方面的详细介绍: 1. MNIST数据集:这是一个经典问题,包含由手写数字组成的70000个样本。这个数据集图像分类任务的基础,由于其规模较小,训练速度较快,因此也成为深度学习模型入门者的首选。 2. CIFAR-10/100数据集:这是另一个图像分类数据集,其中包含10或100个类别的图像。这些图像具有更高的分辨率和更复杂的结构,因此更具挑战性。这些数据集经常用于卷积神经网络的训练。 3. ImageNet数据集:这个数据集包含大量的图像,通常用于图像分类、目标检测和图像分割等任务。由于其规模巨大,需要大量计算资源和时间才能训练深度学习模型。 4. COCO数据集:这个数据集被广泛用于目标检测、图像分割和姿势估计等计算机视觉任务中。它包含许多标记的图像,以及标注的对象的边界框和密集性分割。 5. IMDb数据集:这个数据集用于情感分析任务,它包含来自影评网站的50000条影评。每个影评都有一个情感标签,以指示它是积极的还是消极的。 总之,Python提供了许多方便的工具和库,可以帮助用户更轻松地处理和访问深度学习和机器学习的各种数据集。不同的数据集适用于不同的任务,需要根据具体的应用场景来进行选择。在实际应用中,深入了解每个数据集的特点和含义,对于正确使用它们和开发出更加精确和高效的深度学习算法都非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值