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

您所在的位置:网站首页 肺部结节如何处理好 【深度学习】肺结节分割项目实战一:处理数据集

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

2024-07-02 17:46| 来源: 网络整理| 查看: 265

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

一、LIDC-IDRI数据集简介

官方网站

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

数据集包含1018个病例,每个病例包括来自临床胸部CT扫描的图像和一个相关的XML文件,该文件记录了由四名经验丰富的胸部放射科医生进行的两阶段图像注释过程的结果。在最初的盲读阶段,每个放射科医生独立审查每个CT扫描,并标记出属于三种类型之一的病变(“结节>= 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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3