Advertisement

基于LIDC-IDRI肺结节肺癌数据集的放射组学机器学习分类良性和恶性肺癌(Python 全代码)全流程解析 (一)(2)

阅读量:

在完成PyLIDC库的安装后,在系统用户的指定位置应放置于系统用户的指定位置并新建pylidc.conf文件用于指定PyLIDC库运行所需的配置参数。随后将当前路径更换至数据集存放的位置以实现对数据集路径的有效设置。以下即为此处的测试用例代码:

复制代码
    import pylidc as pl
    from pylidc.utils import consensus
    import os
    
    dataset_path = r'G:\dataset\_zhang\LIDC-IDRI\ '#修改路径哦
    dicom_name   = 'LIDC-IDRI-0001'
    PathDicom = os.path.join(example)  # 构建当前病例文件夹的完整路径
    # 查询当前病例的扫描数据,并将第一个扫描结果存储到scan变量中
    scan = pl.query(pl.Scan).filter(pl.Scan.patient_id == example).first()
    print(scan)
    
    
    
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
1.1.2图像读取-(读取CT图像的patch和分割标注)

我们选取了LIDC-IDRI-0001病例的数据样本作为研究对象,并通过pylidc库提供的按文件夹名称自动查找功能将该案例的所有相关数据存储在变量scan中。随后提取了所有专家对图像分割标记的具体坐标信息以及肺结节对应的素立方体数据。对于包含多个肺结节的情况,默认仅提取第一个进行分析,并利用matplotlib模块中的绘图功能展示了结果。代码实现如下:

复制代码
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as manim
    from skimage.measure import find_contours
    import cv2
    import pylidc as pl
    from pylidc.utils import consensus
    import os
    
    dataset_path = r'G:\dataset\_zhang\LIDC-IDRI\ '
    dicom_name   = 'LIDC-IDRI-0001'
    print(dicom_name)  # 打印当前DICOM文件夹的名称
    PathDicom = os.path.join(dataset_path, dicom_name)  # 构建当前DICOM文件夹的完整路径
    # 查询当前病例的扫描数据,并将第一个扫描结果存储到scan变量中
    scan = pl.query(pl.Scan).filter(pl.Scan.patient_id == dicom_name).first()
    vol = scan.to_volume()# 将该扫描数据转换成数组形式的体积(volume)
    # 聚类注释(nodule annotations)以获取一组注释
    nods = scan.cluster_annotations()
    try:
       anns = nods[0]   # 尝试获取第一个注释(annotation)
       Malignancy = anns[0].Malignancy   # 获取注释中的恶性程度(Malignancy)信息
    except IndexError:
       # 如果没有注释,或者无法获取第一个注释,则继续下一个DICOM文件夹
       continue
    # 执行共识合并(consensus consolidation)和50%的一致性水平(agreement level)。
    # 我们在切片周围添加填充以提供上下文以进行查看。
    cmask, cbbox, masks = consensus(anns, clevel=0.5, pad=[(0,0), (7,7), (20,20)])
    # 提取相应的切片进行可视化
    image = vol[cbbox]
    k = int(0.5 \* (cbbox[2].stop - cbbox[2].start))
    fig, ax = plt.subplots(1, 1, figsize=(5, 5))
    ax.imshow(vol[cbbox][:, :, k], cmap=plt.cm.gray, alpha=1)
    # 标记不同注释的边界
    colors = ['r', 'g', 'b', 'y']
    for j in range(len(masks)):
       for c in find_contours(masks[j][:, :, k].astype(float), 0.5):
       label = "Annotation %d" % (j+1)
       plt.plot(c[:, 1], c[:, 0], colors[j], label=label)
    # 绘制50%共识轮廓线
    for c in find_contours(cmask[:, :, k].astype(float), 0.5):
       plt.plot(c[:, 1], c[:, 0], '--k', label='50% Consensus')
    ax.axis('off')  # 关闭坐标轴
    ax.legend()  # 显示图例
    plt.tight_layout()  # 调整布局以适应图像
    plt.show()  # 显示图像
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

实验结果表明
在图像中,共有4位专家完成了图像分割的任务。此外,在所有参与图像分割的专业人员中计算得到的一个统一评价指标(即所有参与者的评分均值),通常情况下我们将其作为本研究的基础数据源进行分析。

请添加图片描述
1.1.3图像归一化-(读取CT图像的patch和分割标注)

其本质是一种将图像像素值标准化至特定范围的技术手段。其通常会将其像素值映射至[0,1]区间内

在区间[−1, 1]之间。选择这样的数据范围有助于提升模型的稳定性以及加快收敛速度。同时,这将促进不同图像样本在数据分布上趋于一致,并有利于深度学习模型的有效训练和性能提升。代码如下

复制代码
    #归一化
    def normalize\_hu(image):
    	#将输入图像的像素值(-4000 ~ 4000)归一化到0~1之间
        MIN_BOUND = -1000.0
        MAX_BOUND = 400.0
        image = (image - MIN_BOUND) / (MAX_BOUND - MIN_BOUND)
        image[image > 1] = 1.
        image[image < 0] = 0.
        return image
    
    
    
      
      
      
      
      
      
      
      
      
      
    
    代码解读

1.2 图像标注信息预处理-(读取肺结节是良性还是恶性)

这段代码基于变量Malignancy的不同取值(如'Highly Unlikely'和'Moderately Unlikely'等),为label1设定相应的标签(1至5)。在这一过程中,将文本形式的标签转换为数字形式的标签以便于后续机器学习模型进行处理与训练。

复制代码
    if Malignancy == 'Highly Unlikely':
        label1 = 1
    elif Malignancy == 'Moderately Unlikely':
        label1 = 2
    elif Malignancy == 'Indeterminate':
        label1 = 3
    elif Malignancy == 'Moderately Suspicious':
        label1 = 4
    elif Malignancy == 'Highly Suspicious':
        label1 = 5
    print(label1)
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

1.2 肺结节图像切片处理处理-(切片并保存)

随后基于image和cmask构建了ArrayDicom与ArrayDicom_mask两个矩阵。接着通过确定x_、y_、z_坐标的中心点来进行图像切片。随后将切片后的图像及其对应的掩膜图像均以50×50像素的JPEG格式保存下来。与此同时,在label.txt文件中记录了每个图像对应的标签信息及其文件名。在整个流程的最后一阶段完成计数器ii值的递增,并输出当前计数值作为记录。
对处理后的图像进行切片并保存的同时生成相应的标签信息也是必要的操作步骤之一。其中ArrayDicom表示用于存储原始医学影像数据的空间矩阵;而ArrayDicom_mask则代表与其相对应的空间位置关系信息。
在完成上述步骤后系统会自动生成一个名为result.txt的结果报告文档。
在这个result.txt文档中每行由两个部分组成:
第一部分为对应测试样本编号;
第二部分则包含了该样本的所有分类预测结果。

首先是一组图像文件名:例如:0.jpg;1.jpg等。
第二部分是对应于这些图像的标签:每个标签都是一个整数,并且表示相应的图像类别或属性。
在该文件中:标签的具体含义可能是:
(Highly Suspicious)高度可疑;
(Indeterminate)不确定;
(Moderately Suspicious)中度可疑。

在这里插入图片描述

1.3 总结

通过这一阶段的工作我们成功地获得了所需训练的医学图像数据这些数据集包含两类典型病例:良性与恶性肺结节的二维切片图象以及每个病变区域对应的标签信息。基于三个不同的视角对这些医学影像进行分析与处理这一做法在医学影像领域具有普遍性。在当前代码模块中实现这一功能时对每个切片区域进行尺寸标准化处理使其符合统一的空间分辨率要求即大小为 (50, 50) 的二维数组结构。随后采用插值算法重构影像细节以确保输出图片的质量不受影响;并将处理后的结果以JPEG格式存储以便后续使用;

在这里插入图片描述

如果您有任何医学图像处理或机器学习项目需要协助完成,请随时私信我哦。

复制代码
    import numpy as np
    import matplotlib.pyplot as plt
    from skimage.measure import find_contours
    import cv2
    import pylidc as pl
    from pylidc.utils import consensus
    import os
    
    dataset_path = r'G:\dataset\_zhang\LIDC-IDRI\ '
    dicom_name   = 'LIDC-IDRI-0001'
    
    #归一化
    def normalize\_hu(image):
    	#将输入图像的像素值(-4000 ~ 4000)归一化到0~1之间
    MIN_BOUND = -1000.0
    MAX_BOUND = 400.0
    image = (image - MIN_BOUND) / (MAX_BOUND - MIN_BOUND)
    image[image > 1] = 1.
    image[image < 0] = 0.
    return image
      
    ii = 0
    # Query for a scan, and convert it to an array volume.
    for dicom_name in os.listdir(dataset_path):
    print(dicom_name)
    PathDicom = os.path.join(dicom_name)  
    scan = pl.query(pl.Scan).filter(pl.Scan.patient_id == dicom_name).first()
    vol = scan.to_volume()
    # Cluster the annotations for the scan, and grab one.
    nods = scan.cluster_annotations()
    try :
        anns = nods[0]
        Malignancy = anns[0]
        Malignancy = Malignancy.Malignancy
    except :
        pass
    # Perform a consensus consolidation and 50% agreement level.
    # We pad the slices to add context for viewing.
    cmask,cbbox,masks = consensus(anns, clevel=0.5,
                          pad=[(0,0), (7,7), (20,20)])
    image = vol[cbbox]
    image = normalize_hu(image)
    k = int(0.5\*(cbbox[2].stop - cbbox[2].start))
    
    if Malignancy == 'Highly Unlikely':
        label1 = 1
    elif Malignancy == 'Moderately Unlikely':
        label1 = 2
    elif Malignancy == 'Indeterminate':
        label1 = 3
    elif Malignancy == 'Moderately Suspicious':
        label1 = 4
    elif Malignancy == 'Highly Suspicious':
        label1 = 5
    print(label1)
     
    # 矩阵增广和传参
    ArrayDicom = image
    ArrayDicom_mask = cmask
    
    # 中心点定位
    x_, y_, z_ = np.shape(image)
    **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!** **因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img]()
![img]()
![img]()
![img]()
![img]()
![img]()
    
     
    
    **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!** **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)**
    
    n/img_convert/9f49b566129f47b8a67243c1008edf79.png)
    
     
    
    **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!** **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)**
    
    <img src="" alt="img" style="zoom:50%;" />
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

全部评论 (0)

还没有任何评论哟~