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

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

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


比赛地址: 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])


目录
相关文章
|
机器学习/深度学习 XML 存储
深度学习Heartpy心电图分析
深度学习Heartpy心电图分析
464 0
|
1月前
|
机器学习/深度学习 数据可视化 TensorFlow
使用Python实现深度学习模型:智能天气预测与气候分析
使用Python实现深度学习模型:智能天气预测与气候分析
340 3
|
2月前
|
机器学习/深度学习 并行计算 搜索推荐
深度学习之基因组数据分析
基于深度学习的基因组数据分析利用深度学习技术来处理和分析基因组数据,帮助解决基因组学领域中一些复杂且具有挑战性的问题。
97 11
|
4月前
|
机器学习/深度学习 TensorFlow 数据处理
使用Python实现深度学习模型:医学影像识别与疾病预测
【7月更文挑战第24天】 使用Python实现深度学习模型:医学影像识别与疾病预测
69 4
|
3月前
|
数据采集 机器学习/深度学习 数据挖掘
【数学建模-某肿瘤疾病诊疗的经济学分析】数据清洗和特征工程
文章介绍了在一个肿瘤疾病诊疗经济学分析的数学建模案例中进行数据清洗和特征工程的方法,包括处理缺失值、进行编码、计算年龄以及对并发症严重程度和费用进行编码等步骤。
41 0
|
3月前
|
数据采集 机器学习/深度学习 数据挖掘
【数学建模-某肿瘤疾病诊疗的经济学分析】数据分析
本文提供了针对一个肿瘤疾病诊疗经济学分析的数学建模案例,其中包括了数据清洗、特征工程、模型分析等步骤,并提供了相关的代码和最终报告的下载链接。
45 0
|
6月前
|
机器学习/深度学习 数据采集 算法
机器学习赋能乳腺癌预测:如何使用贝叶斯分级进行精确诊断?
机器学习赋能乳腺癌预测:如何使用贝叶斯分级进行精确诊断?
115 0
|
机器学习/深度学习 数据采集 算法
基于影像组学的膀胱癌治疗反应评估:深度学习的应用
本文旨在探讨基于影像组学的膀胱癌治疗反应评估方法,介绍影像组学技术的基本概念和特征提取方法,并探讨深度学习算法在癌症治疗反应评估中的应用。将参考和解析文献Bladder Cancer Treatment Response Assessment in CT using Radiomics with Deep-Learning的分析过程。
142 0
|
机器学习/深度学习 人工智能 数据可视化
人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模
人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模
人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模
|
机器学习/深度学习 算法 Python
实战案例|肿瘤预测模型~
大家好,我是志斌~ 今天来跟大家分享一下朴素贝叶斯模型的原理以及通过肿瘤预测模型来看如何用Python实现它。
1125 0
实战案例|肿瘤预测模型~