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

这篇具有很好参考价值的文章主要介绍了【深度学习】肺结节分割项目实战一:处理数据集。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

一、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_id nodule_no slice_no original_image mask_image maliganancy is_cancer is_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文件:文章来源地址https://www.toymoban.com/news/detail-454447.html

print("Saved Meta data")
self.meta.to_csv(self.meta_path+'meta_info.csv',index=False)

到了这里,关于【深度学习】肺结节分割项目实战一:处理数据集的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深度学习图像分类、目标检测、图像分割源码小项目

    ​demo仓库和视频演示: 到此一游7758258的个人空间_哔哩哔哩_bilibili 卷积网路CNN分类的模型一般使用包括alexnet、DenseNet、DLA、GoogleNet、Mobilenet、ResNet、ResNeXt、ShuffleNet、VGG、EfficientNet和Swin transformer等10多种模型 目标检测包括yolov3、yolov4、yolov5、yolox、faster rcnn、SDD等 图像分割包

    2024年02月09日
    浏览(36)
  • 深度学习实战23(进阶版)-语义分割实战,实现人物图像抠图的效果(计算机视觉)

    大家好,我是微学AI,今天给大家带来深度学习实战23(进阶版)-语义分割实战,实现人物图像抠图的效果。语义分割是计算机视觉中的一项重要任务,其目标是将图像中的每个像素都分配一个语义类别标签。与传统的目标检测或分类任务不同,语义分割不仅需要识别图像中存在

    2024年02月13日
    浏览(39)
  • OpenCV与AI深度学习 | 实战 | 基于YOLOv9+SAM实现动态目标检测和分割(步骤 + 代码)

    本文来源公众号 “OpenCV与AI深度学习” ,仅用于学术分享,侵权删,干货满满。 原文链接:实战 | 基于YOLOv9+SAM实现动态目标检测和分割(步骤 + 代码)     本文主要介绍基于YOLOv9+SAM实现动态目标检测和分割,并给出详细步骤和代码。     在本文中,我们使用YOLOv9+SAM在

    2024年04月22日
    浏览(61)
  • 深度学习——制作自己的VOC图像分割数据集

    1、数据集介绍 COCO数据集有80个类别,VOC数据集有20个类别。当这些数据集类别中没有自己需要的时候,就需要自己动手做自己的数据集了。 我自己在做数据集的时候主要使用到了labelme和labelImg两个工具。labelme主要是制作语义分割数据集(ImageSets,JPEGImages,SegmentationClass,Segmenta

    2024年02月04日
    浏览(34)
  • 机器学习实战 | 股票价格预测项目(深度学习初级)

    准备写个系列博客介绍机器学习实战中的部分公开项目。首先从初级项目开始。 本文为初级项目第三篇:利用NSE-TATA数据集预测股票价格。 项目原网址为:Stock Price Prediction – Machine Learning Project in Python。 第一篇为:机器学习实战 | emojify 使用Python创建自己的表情符号(深度

    2024年02月16日
    浏览(28)
  • OpenCV实战:从图像处理到深度学习的全面指南

    本文深入浅出地探讨了OpenCV库在图像处理和深度学习中的应用。从基本概念和操作,到复杂的图像变换和深度学习模型的使用,文章以详尽的代码和解释,带领大家步入OpenCV的实战世界。 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它由一

    2024年02月14日
    浏览(29)
  • 机器学习实战 | MNIST手写数字分类项目(深度学习初级)

    准备写个系列博客介绍机器学习实战中的部分公开项目。首先从初级项目开始。 本文为初级项目第二篇:利用MNIST数据集训练手写数字分类。 项目原网址为:Deep Learning Project – Handwritten Digit Recognition using Python。 第一篇为:机器学习实战 | emojify 使用Python创建自己的表情符号

    2024年02月15日
    浏览(35)
  • 深度学习:使用UNet做图像语义分割,训练自己制作的数据集,详细教程

    语义分割(Semantic Segmentation)是图像处理和机器视觉一个重要分支。与分类任务不同,语义分割需要判断图像每个像素点的类别,进行精确分割。语义分割目前在自动驾驶、自动抠图、医疗影像等领域有着比较广泛的应用。我总结了使用UNet网络做图像语义分割的方法,教程很详

    2024年02月03日
    浏览(36)
  • 【深度学习】YOLOv5实例分割 数据集制作、模型训练以及TensorRT部署

    yolov5-seg:官方地址:https://github.com/ultralytics/yolov5/tree/v6.2 TensorRT:8.x.x 语言:C++ 系统:ubuntu18.04 前言:由于yolo仓中提供了标准coco的json文件转txt代码,因此需要将labelme的json文件转为coco json. labelme JSON 转COCO JSON 使用labelme的CreatePolygons按钮开始绘制多边形,然后保存为json格式。

    2024年02月06日
    浏览(40)
  • 深度学习图像处理基础工具——opencv 实战信用卡数字识别

    任务 信用卡数字识别 穿插之前学的知识点  形态学操作 模板匹配 等 总体流程与方法 1.有一个模板 2 用轮廓检测把模板中数字拿出来 外接矩形(模板和输入图像的大小要一致 )3 一系列预处理操作 问题的解决思路 1.分析准备:准备模板,读取文件——转化为灰度图——转化

    2024年04月15日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包