胃肠道癌症图像分割数据分析

简介: 胃肠道癌症图像分割数据分析

一、胃肠道癌症图像分割数据分析


比赛地址: www.kaggle.com/competition…


1.比赛简介


2019 年,全球估计有 500 万人被诊断出患有胃肠道癌症。在这些患者中,大约一半有资格接受放射治疗,通常每天进行 10-15 分钟,持续 1-6 周。放射肿瘤学家尝试使用指向肿瘤的 X 射线束进行高剂量辐射,同时避开胃和肠。借助集成磁共振成像和线性加速器系统(也称为 MR-Linacs)等新技术,肿瘤学家能够可视化肿瘤和肠道的每日位置,这些位置每天都在变化。在这些扫描中,放射肿瘤学家必须手动勾勒出胃和肠的位置,以便调整 X 射线束的方向,以增加向肿瘤输送的剂量并避开胃和肠。这是一个耗时且劳动密集型的过程,可以将治疗从每天 15 分钟延长到每天一个小时,这对于患者来说可能难以忍受——除非深度学习可以帮助自动化分割过程。分割胃和肠的方法将使治疗更快,并使更多患者获得更有效的治疗。


UW-Madison Carbone 癌症中心是基于 MR-Linac 放射治疗的先驱,自 2015 年以来一直根据患者的日常解剖结构对患者进行 MRI 引导放射治疗。UW-Madison 已慷慨同意支持该项目,该项目为接受治疗的患者提供匿名 MRI在威斯康星大学麦迪逊卡本癌症中心。威斯康星大学麦迪逊分校是威斯康星州麦迪逊市的一所公立研究型大学。威斯康星大学的理念是大学向国家、国家和世界的承诺,他们的努力将使所有公民受益。

在本次比赛中,您将创建一个模型以在 MRI 扫描中自动分割胃和肠。MRI 扫描来自实际的癌症患者,他们在放射治疗期间的不同日子进行了 1-5 次 MRI 扫描。您将基于这些扫描的数据集制定您的算法,以提出创造性的深度学习解决方案,帮助癌症患者获得更好的护理。


在此图中,肿瘤(粉红色粗线)靠近胃(红色粗线)。高剂量的放射线直接照射到肿瘤上,同时避开胃部。剂量水平由彩虹轮廓表示,较高剂量由红色表示,较低剂量由绿色表示。


癌症需要付出足够的代价。如果成功,您将使放射肿瘤学家能够安全地向肿瘤提供更高剂量的辐射,同时避开胃和肠。这将使癌症患者的日常治疗更快,并让他们获得更有效的治疗,副作用更少,更好地长期控制癌症。


2.数据简介


在本次比赛中,我们在图像中分割器官细胞。训练注释以 RLE 编码掩码的形式提供,图像采用 16 位灰度 PNG 格式。


本次比赛中的每个案例都由多组扫描切片表示(每组由扫描发生的日期标识)。有些案例是按时间拆分的(早期是在训练中,后期是在测试中),而有些案例是按案例拆分的——整个案例都在训练中或测试中。本次比赛的目标是能够推广到部分和完全未见的案例。


请注意,在这种情况下,测试集是完全看不见的。如训练集中所示,大约有 50 个案例,具有不同的天数和切片数。


  • train.csv - 所有训练对象的 ID 和掩码。
  • sample_submission.csv - 格式正确的示例提交文件。
  • train - 案例/日文件夹的文件夹,每个文件夹包含给定日期特定案例的切片图像。
  • id- 对象的唯一标识符
  • class- 对象的预测类别
  • EncodedPixels - 已识别对象的 RLE 编码像素


二、数据处理


1.Imports库


!pip install wandb >log.log
WARNING: You are using pip version 22.0.4; however, version 22.1.2 is available.
You should consider upgrading via the '/opt/conda/envs/python35-paddle120-env/bin/python -m pip install --upgrade pip' command.

from pathlib import Path
import random
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from glob import glob
from PIL import Image
from IPython.display import IFrame
import imageio
import os


2.数据解压缩


!unzip -qoa data/data149096/uw-madison-gi-tract-image-segmentation.zip -d data


3.数据加载


root_dir = Path('./data/')
df_train = pd.read_csv(root_dir / 'train.csv')
df_train.head()
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right; }

id class segmentation
0 case123_day20_slice_0001 large_bowel NaN
1 case123_day20_slice_0001 small_bowel NaN
2 case123_day20_slice_0001 stomach NaN
3 case123_day20_slice_0002 large_bowel NaN
4 case123_day20_slice_0002 small_bowel NaN


4.创建分割dataframe


dic = {}
for data in df_train.iterrows():
    p_key = data[1]['id']
    if not dic.get(p_key):
        dic[p_key] = {}
        dic[p_key]['large_bowel_segmentation'] = None
        dic[p_key]['small_bowel_segmentation'] = None
        dic[p_key]['stomach_segmentation'] = None
    if data[1]['class'] == 'large_bowel':
        key = 'large_bowel_segmentation'
    elif data[1]['class'] == 'small_bowel':
        key = 'small_bowel_segmentation'
    elif data[1]['class'] == 'stomach':
        key = 'stomach_segmentation'
    value = data[1]['segmentation']
    dic[p_key][key] = value
df_segmentation = pd.DataFrame.from_dict(dic, orient='index')
df_segmentation.head()
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right; }

large_bowel_segmentation small_bowel_segmentation stomach_segmentation
case123_day20_slice_0001 NaN NaN NaN
case123_day20_slice_0002 NaN NaN NaN
case123_day20_slice_0003 NaN NaN NaN
case123_day20_slice_0004 NaN NaN NaN
case123_day20_slice_0005 NaN NaN NaN


5.创建图像基本信息


# 生成图像文件列表
images_list = glob('./data/train/*/*/scans/*.png')
# path转dataframe
df_images = pd.DataFrame({'Path':images_list})
# 从文件路径分割
path_split = df_images['Path'].str.split('/',n=6,expand=True)
# 分割 [4] and [6]数据
df_images['CaseNum_Day'] = path_split[4]
df_images['SliceNum'] = path_split[6]
# 获取 day, slice, height and width
case_split = df_images['CaseNum_Day'].str.split('_',n=2, expand=True)
df_images['Case'] = case_split[0].str[4:].astype(int)
df_images['Day'] = case_split[1].str[3:].astype(int)
# 获取 slice, height and width
fileName_split = df_images['SliceNum'].str.split('_',n=6, expand=True)
df_images['Slice'] = fileName_split[1].astype(int)
df_images['Height'] = fileName_split[2].astype(int)
df_images['Width'] = fileName_split[3].astype(int)
#'id' in segmentation
df_images['id'] = df_images['CaseNum_Day'] + '_slice_' + fileName_split[1]
df_images.head()
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right; }

Path CaseNum_Day SliceNum Case Day Slice Height Width id
0 ./data/train/case131/case131_day23/scans/slice... case131_day23 slice_0044_360_310_1.50_1.50.png 131 23 44 360 310 case131_day23_slice_0044
1 ./data/train/case131/case131_day23/scans/slice... case131_day23 slice_0122_360_310_1.50_1.50.png 131 23 122 360 310 case131_day23_slice_0122
2 ./data/train/case131/case131_day23/scans/slice... case131_day23 slice_0031_360_310_1.50_1.50.png 131 23 31 360 310 case131_day23_slice_0031
3 ./data/train/case131/case131_day23/scans/slice... case131_day23 slice_0127_360_310_1.50_1.50.png 131 23 127 360 310 case131_day23_slice_0127
4 ./data/train/case131/case131_day23/scans/slice... case131_day23 slice_0115_360_310_1.50_1.50.png 131 23 115 360 310 case131_day23_slice_0115
# 数据信息统计
print('Unique case numbers ',len(df_images['Case'].unique()))
print('Unique Days ',len(df_images['Day'].unique()))
print('Unique Heights ',df_images['Height'].unique())
print('Unique Widths ',df_images['Width'].unique())
Unique case numbers  85
Unique Days  35
Unique Heights  [360 276 266 234]
Unique Widths  [310 276 266 234]
# Unique CaseNum_Day
unique_case_day = df_images['CaseNum_Day'].unique()
print(len(unique_case_day))
274


6.RLE数据解码


详见baike.baidu.com/item/rle/36…

RLE全称(run-length encoding),翻译为游程编码,又译行程长度编码,又称变动长度编码法(run coding),在控制论中对于二值图像而言是一种编码方法,对连续的黑、白像素数(游程)以不同的码字进行编码。游程编码是一种简单的非破坏性资料压缩法,其好处是加压缩和解压缩都非常快。其方法是计算连续出现的资料长度压缩之。

  • 一种压缩过的位图文件格式,RLE压缩方案是一种极其成熟的压缩方案,特点是无损失压缩,既节省了磁盘空间又不损失任何图像数据。
  • 游程编码是一种统计编码,该编码属于无损压缩编码。对于二值图有效。其在对图像数据进行编码时,沿一定方向排列的具有相同灰度值的像素可看成是连续符号,用字串代替这些连续符号,可大幅度减少数据量。
  • 行程编码是连续精确的编码,在传输过程中,如果其中一位符号发生错误,即可影响整个编码序列,使行程编码无法还原回原始数据。
  • 游程编码所能获得的压缩比有多大,主要取决于图像本身的特点。如果图像中具有相同颜色的图像块越大,图像块数目越少,获得的压缩比就越高。反之,压缩比就越小。
# 获取像素位置的函数
def get_pixel_loc(random_segmentation, img_shape):
    loc = []
    for rle_string in random_segmentation:
        p_loc = []
        if isinstance(rle_string, str): # Handle NaN!
            rle = [int(i) for i in rle_string.split(' ')]
            pairs = list(zip(rle[0::2],rle[1::2]))    
            for start, length in pairs:
                for p_pos in range(start, start + length):
                    p_loc.append([p_pos // img_shape[1], p_pos % img_shape[1], len(loc)])
        loc.append(p_loc)
    return loc
# 获取 mask
def get_mask(rle_group, img_shape):
    masks = np.zeros(img_shape)
    masks = np.repeat(masks[:, :, np.newaxis], 3, axis=2)
    for rle_single in rle_group:
        for loc in rle_single:
            masks[tuple(loc)] = 1
    return masks
# 应用 mask
def apply_mask(image, loc_segm, img_shape):
    image = image / image.max()
    masks = get_mask(loc_segm, img_shape)    
    image = np.dstack((image + masks[..., 0], 
                       image + masks[..., 1],
                       image + masks[..., 2]))
    image = image / image.max()
    return image


7.mask打印


# 从数据集打印随机mask
# mask数据获取
mask_encoding = df_segmentation.loc[(df_segmentation['large_bowel_segmentation'].notnull()) |
                                    (df_segmentation['small_bowel_segmentation'].notnull()) |
                                    (df_segmentation['stomach_segmentation'].notnull())]
# 列表id转换
mask_id = list(mask_encoding.index)
for _ in range(5):   
    random_id = mask_id[np.random.randint(0,len(mask_id) - 1)]
    random_segmentation = mask_encoding.loc[random_id]
    splits = random_id.split('_')
    x = df_images[(df_images['Case']==int(splits[0][4:]))
                       &(df_images['Day']==int(splits[1][3:]))
                       &(df_images['Slice']==int(splits[3]))]
    image = np.array(Image.open(x['Path'].values[0]))
    k = image.shape
    p_loc = get_pixel_loc(random_segmentation, k)
    fig, ax = plt.subplots(1,3, figsize=(12,16))
    ax[0].set_title('Image')
    ax[0].imshow(image, cmap='gray')
    ax[1].set_title('Mask')
    ax[1].imshow(get_mask(p_loc, k))
    ax[2].imshow(apply_mask(image, p_loc, k))
plt.show()


image.pngimage.pngimage.png


8.mask存储gif动画


def save_gif(random_case_day):
    gif_name = str(random_case_day + '.gif')
    filenames = []
    df_selected_images = df_images[df_images['CaseNum_Day'] == random_case_day].sort_values('Slice').reset_index(drop=True)
    for i, row in df_selected_images.iterrows():
        image = np.array(Image.open(row['Path']))
        k = image.shape    
        segmentation = df_segmentation.loc[row['id']]
        pixel_loc = get_pixel_loc(segmentation, k)
        masked_image = apply_mask(image, pixel_loc, k)
        filename = f'{i}.png'
        filenames.append(filename)
        plt.imsave(filename, masked_image)
    with imageio.get_writer(gif_name, mode='I') as writer:
        for filename in filenames:
            image = imageio.imread(filename)
            writer.append_data(image)
    for filename in set(filenames):
        os.remove(filename)
    shape = (df_selected_images.iloc[0]['Width'], 
             df_selected_images.iloc[0]['Height'])
    return gif_name, shape
random_case_day = unique_case_day[np.random.randint(0,len(unique_case_day) - 1)]
out = save_gif(random_case_day)
IFrame(out[0], 
       out[1][0], 
       out[1][1])


目录
相关文章
|
4月前
|
机器学习/深度学习 数据采集 数据可视化
使用Python实现深度学习模型:智能舆情监测与分析
【8月更文挑战第16天】 使用Python实现深度学习模型:智能舆情监测与分析
394 1
|
1月前
|
机器学习/深度学习 数据采集 算法
机器学习在医疗诊断中的前沿应用,包括神经网络、决策树和支持向量机等方法,及其在医学影像、疾病预测和基因数据分析中的具体应用
医疗诊断是医学的核心,其准确性和效率至关重要。本文探讨了机器学习在医疗诊断中的前沿应用,包括神经网络、决策树和支持向量机等方法,及其在医学影像、疾病预测和基因数据分析中的具体应用。文章还讨论了Python在构建机器学习模型中的作用,面临的挑战及应对策略,并展望了未来的发展趋势。
111 1
|
3月前
|
机器学习/深度学习 并行计算 搜索推荐
深度学习之基因组数据分析
基于深度学习的基因组数据分析利用深度学习技术来处理和分析基因组数据,帮助解决基因组学领域中一些复杂且具有挑战性的问题。
138 11
|
4月前
|
机器学习/深度学习 运维 算法
【阿里天池-医学影像报告异常检测】2 特征工程
本文详细介绍了在医学影像报告异常检测任务中进行特征工程的步骤和方法。
37 1
|
4月前
|
机器学习/深度学习 数据采集 数据挖掘
【数学建模-某肿瘤疾病诊疗的经济学分析】第一问模型分析
探讨了使用诊断相关分组(DRGs)对肿瘤疾病的诊疗进行经济学分析的方法,并提出了通过决策树模型来预测不同诊断相关组(ADRG)费用水平的分类方案。
59 1
|
4月前
|
数据采集 机器学习/深度学习 数据挖掘
【数学建模-某肿瘤疾病诊疗的经济学分析】数据清洗和特征工程
文章介绍了在一个肿瘤疾病诊疗经济学分析的数学建模案例中进行数据清洗和特征工程的方法,包括处理缺失值、进行编码、计算年龄以及对并发症严重程度和费用进行编码等步骤。
42 0
|
4月前
|
数据采集 机器学习/深度学习 数据挖掘
【数学建模-某肿瘤疾病诊疗的经济学分析】数据分析
本文提供了针对一个肿瘤疾病诊疗经济学分析的数学建模案例,其中包括了数据清洗、特征工程、模型分析等步骤,并提供了相关的代码和最终报告的下载链接。
49 0
|
7月前
|
机器学习/深度学习 算法
利用机器学习进行股市预测的可行性分析
【5月更文挑战第31天】本文探讨了机器学习技术在股市预测中的应用。通过对历史数据的分析和模型训练,我们可以构建出能够预测未来股市走势的模型。然而,由于股市受到多种因素的影响,包括经济、政治和社会因素等,因此预测的准确性仍然存在挑战。本文将介绍一些常见的机器学习算法和它们在股市预测中的应用,并提供一些建议来提高预测的准确性。
|
搜索推荐 数据挖掘 大数据
数据分析10大经典模型
数据分析10大经典模型
262 0
|
机器学习/深度学习 人工智能 数据可视化
人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模
人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模
人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模

热门文章

最新文章