医学图像分割 基于深度学习的肝脏肿瘤分割 实战(二)

医学图像分割 基于深度学习的肝脏肿瘤分割 实战(一)中,实现了对肝脏的分割,但是后续在使用相同的处理方法与模型进行肿瘤分割的时候,遇到了两次问题。

第一次,网络的dice系数,训练集上一直只能达到40%左右,测试集上只有10%左右,而且结果明显不对。我认为是数据层面有问题,随机又看了很多原始图片,发现很多肿瘤肉眼都无法分辨,于是进行了实验验证猜想,实验写在了博客:医学图像预处理(五) 器官与病灶的直方图即验证很多病人的肝脏和肿瘤灰度值(更准确地说是hu值)几乎是重叠的

实验验证了猜想,开始重新做实验。我于是从3Dircadb数据库换成了LiTS2017数据库,后者的数据量更大。然后根据病人的肝脏与肿瘤直方图分布,手动将130位病人划分成了三个等级:level1:肝脏与肿瘤对比度最大。level3:肝脏与肿瘤的对比度几乎没有。训练数据只选择level1&level2。

当然,数据预处理操作和ROI操作和之前一样,是都有的。
但是这回做实验,一样出了问题。即第二次问题。

第二次:先是dice系数在训练集上可以到10%,可是又会突然回到接近0的值。我百思不得其解,以为是发生了梯度消失或者梯度爆炸的问题,还差了很多资料看如何解决。
可是,后来想着想着,发现一个奇怪又严肃的问题,就是ROI操作会将真实肝脏分割结果与原图做“与”操作,这样,非感兴趣的区域就会变黑,就可以让网络集中注意力在肝脏内部的区域,可是,肝脏内部的肿瘤也是黑色(一般灰度值低于肝脏)的呀??为什么外面变成黑色就是“非感兴趣区域”,而肝脏里的就得是“目标”呢? 想了想之前肝脏分割的图片,发现做窗口值等的操作,也是将非目标区域变黑,然后可以突出肝脏(肝脏变成灰白色,当然,还有其他器官更是白色)。
于是,我做了一个大胆的实验,将肝脏变成灰色,肿瘤变成白色,肝脏外的区域为黑色。(进行了颜色翻转
在这里插入图片描述
在这里插入图片描述
这一次实验,训练集上,dice系数90%左右,测试集上70%左右。虽然不够好,但是至少证明了猜想是可行的。也反映了,数据是王道:种瓜得瓜,种豆得豆。

下面是实验的代码,第一部分是准备数据集的过程(预处理后写成h5文件),这部分在本地环境进行。第二部分是模型构建和训练过程,这部分在服务器进行(ubuntu16.04, tensorflow-gpu)

第一部分:
(注:有关h5文件读写的工具类也放在了博客里)

# -*- coding: utf-8 -*-

"""
根据LITS_check.py,观察结果
根据肝脏与肿瘤的对比度,将病人分成 3 level
1 level:对比度最高(随机选出两个作为validation集)
2 level: 对比度中等(随机选出两个作为validation集)
3 level:对比度最低
"""
# theshold = 1e-3, total=755
# 81,125作为测试集
level_1 = [0,1,22,23,25,26,27,31,37,46,49,50,55,57,58,59,61,62,
           63,64,66,78,79,82,83,90,92,95,99,109,112,124]

#level_1 = [63,64,66,78,79,81,82,83]
# theshold = 1e-3, total= 1345
# 11,110作为测试集
level_2 = [2,7,8,9,10,12,14,15,17,28,35,40,42,
           53,56,69,76,93,96,101,111,113,117]

level12 = level_1 + level_2
level12.sort()

test_list = [11,81,110,125]

a = [i for i in range(130)]
level_3 =list(set(a)-set(level_1)-set(level_2))
# sort方法直接改变原列表,无返回值
level_3.sort()


"""
将level_1的其余图片观察,确定是否对比度高
观察后确定窗口值为:[-50,200]
"""
onServer = False
if onServer:
    niiSegPath = './LITS17/seg/'
    niiImagePath = './LITS17/ct/'
else:
    niiSegPath = '~/Documents/LITS17/seg/'
    niiImagePath = '~/Documents/LITS17/ct/'


import numpy as np
import SimpleITK as sitk
import matplotlib.pyplot as plt

def getRangeImageDepth(image):
    z = np.any(image, axis=(1,2)) # z.shape:(depth,)
    #print("all index:",np.where(z)[0])
    if len(np.where(z)[0]) >0:
        startposition,endposition = np.where(z)[0][[0,-1]]
    else:
        startposition = endposition = 0
    
    return startposition, endposition

def sample_stack(stack, name="images.png", rows=4, cols=2, start_with=0, show_every=1):
    fig,ax = plt.subplots(rows,cols,figsize=[5*cols,5*rows])
    if rows==1 or cols==1 :
        nums = rows*cols
        for i in range(nums):
            ind = start_with + i*show_every
            ax[int(i % nums)].set_title('slice %d' % ind)
            ax[int(i % nums)].imshow(stack[ind],cmap='gray')
            ax[int(i % nums)].axis('off')
    else:
        for i in range(rows*cols):
            ind = start_with + i*show_every
            ax[int(i/cols),int(i % cols)].set_title('slice %d' % ind)
            ax[int(i/cols),int(i % cols)].imshow(stack[ind],cmap='gray')
            ax[int(i/cols),int(i % cols)].axis('off')
    # 这句话一定要在show之前写,否则show函数之后会创建新的空白图
#    plt.savefig(name)
    plt.show()

"""
工具函数,左边原图,右边真实分割图
"""
def show_src_seg(srcimg, segimg,index, rows=3,start_with=0, show_every=1):
    assert srcimg.shape == segimg.shape
    
    rows = srcimg.shape[0]
    plan_rows = start_with + rows*show_every - 1
    print("rows=%d,planned_rows=%d"%(rows,plan_rows))
    
    rows = plan_rows if (rows > plan_rows) else rows
    cols = 2
    print("final rows=%d"%rows)
    
    fig,ax = plt.subplots(rows,cols,figsize=[5*cols,5*rows])
    for i in range(rows):
        ind = start_with + i*show_every
        ax[i,0].set_title('src slice %d' % ind)
        ax[i,0].imshow(srcimg[ind],cmap='gray')
        ax[i,0].axis('off')
        
        ax[i,1].set_title('truth seg slice %d' % ind
### 关于肝脏肿瘤分割实战代码 #### 开发环境准备 为了顺利开展基于深度学习医学图像分割项目,特别是针对肝脏肿瘤分割的任务,建议搭建如下开发环境[^2]: - **操作系统**:推荐使用 Linux 或 Windows。 - **编程语言**:Python 是首选的语言工具。 - **深度学习框架**:可以选择 TensorFlow 或 PyTorch 来构建模型。 - **医学图像处理库**:安装 PIL 和 OpenCV 库有助于图像预处理工作。 #### 数据集获取 对于数据集的选择,可以考虑使用公开可用的数据集如 BraTS、LUNA、CAMELYON 等。另外,特定于肝脏肿瘤的研究还可以利用 3D-IRCADB 数据集,该数据集中包含了20个病人的 CT 影像序列以及对应的标注信息,原始文件采用 DICOM 格式保存[^4]。 #### U-net 架构的应用实例 U-net 是一种常用于医学图像分割任务的有效网络架构。下面给出一段简单的 PyTorch 版本 U-net 的实现片段,适用于肝脏及其内部结构(比如肿瘤)的自动识别与划分操作[^1]: ```python import torch from torch import nn, optim import torchvision.transforms as transforms from unet_model import UNet # 假设已经定义好了unet模型类 def train(model, device, train_loader, optimizer, epoch): model.train() criterion = nn.CrossEntropyLoss() # 定义损失函数 for batch_idx, (data, target) in enumerate(train_loader): data, target = data.to(device), target.to(device) optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() if __name__ == "__main__": use_cuda = torch.cuda.is_available() device = torch.device("cuda" if use_cuda else "cpu") transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) dataset = ... # 加载并初始化自己的数据集 dataloader_args = dict(shuffle=True, batch_size=8) loader = torch.utils.data.DataLoader(dataset, **dataloader_args) net = UNet(n_channels=1, n_classes=2).to(device) opt = optim.Adam(net.parameters(), lr=1e-4) epochs = 10 for e in range(epochs): train(net, device, loader, opt, e) ``` 这段代码展示了如何设置训练循环,并调用了自定义的 `UNet` 类来进行前向传播计算和反向梯度更新过程。需要注意的是实际应用中还需要根据具体情况进行参数调整优化。
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值