医学图像分割基于深度学习的肝脏肿瘤分割实战(⼀)
在之前的⼀篇博客⾥:,是学习并复现别⼈的实验。这篇将记录下⾃⼰毕设第⼀阶段的实验。毕设题⽬为:基于深度学习的肝脏肿瘤分割。经过⼏番调整,最终确定:第⼀阶段分割出腹部图像中的肝脏,作为第⼆阶段的ROI(region of interest),第⼆阶段利⽤ROI对腹部图像进⾏裁剪,裁剪后的⾮ROI区域变成⿊⾊,作为该阶段输⼊,分割出肝脏中的肿瘤(更新2019-4-2,已做完实验,。第三阶段⽤随机场的后处理⽅法进⾏优化。
此外,觉得当时的那篇⽂章写得很不⽤⼼,没费多⼤功夫,复制粘贴为主。我记录的主要原因之⼀就是觉得这⽅⾯⼊门实战的⽂章很少,希望让情况类似的同学少⾛⼀点弯路。可现在⾃⼰写的东西过⼏天再去看,都会⼀头雾⽔。没有从主⼲思路到细节的分层讲解,没有关键点的介绍。这篇⽂章开始,将尽我所能,写得利于接受⼀点。
(不过,⾃⼰才开始学习⼀个多⽉,python和框架都是临时学的,并不能保证博客⾥的东西是对的,有错误的话,望指出)
正⽂:
⽂章⽬录
⽬标
分割出CT腹部图像的肝脏区域。
原始数据介绍
实验⽤到的数据为3Dircadb,即腹部的CT图。⼀个病⼈为⼀个⽂件夹。
例如3Dircadb1.1(⼀共20位),该⽂件夹下会使⽤到的⼦⽂件夹为PATIENT_DICOM(病⼈原始腹部3D CT
图),MASKS_DICOM(该⽂件夹下具有不同部位的分割结果,⽐如liver和liver tumor等等)。如下图所⽰:
PATIENT_DICOM利⽤软件展⽰效果如下:⼀个dcm⽂件包含129张切⽚。
MASKS_DICOM下的liver分割图效果如下:
整体思路
1、数据提取
数据读取:
从原始dcm格式读⼊成我们需要的数组格式
import numpy as np
import pydicom
爱之城import os
import matplotlib.pyplot as plt
import cv2
from keras.preprocessing.image import ImageDataGenerator
from HDF5DatatWriter import HDF5DatatWriter
from HDF5DatatGenerator import HDF5DatatGenerator
for i in range(1,18):# 前17个⼈作为测试集
full_images =[]# 后⾯⽤来存储⽬标切⽚的列表
full_livers =[]#功能同上
# 注意不同的系统,⽂件分割符的区别
label_path ='~/3Dircadb/3Dircadb1.%d/MASKS_DICOM/liver'%i
data_path ='~/3Dircadb/3Dircadb1.%d/PATIENT_DICOM'%i
liver_slices =[pydicom.dcmread(label_path +'/'+ s)for s in os.listdir(label_path)]
# 注意需要排序,即使⽂件夹中显⽰的是有序的,读进来后就是随机的了
liver_slices.sort(key =lambda x:int(x.InstanceNumber))
# s.pixel_array 获取dicom格式中的像素值
海门老街livers = np.stack([s.pixel_array for s in liver_slices])
image_slices =[pydicom.dcmread(data_path +'/'+ s)for s in os.listdir(data_path)]
image_slices.sort(key =lambda x:int(x.InstanceNumber))
""" 省略进⾏的预处理操作,具体见part2"""
full_images.append(images)
full_livers.append(livers)
full_images = np.vstack(full_images)
full_images = np.expand_dims(full_images,axis=-1)
full_livers = np.vstack(full_livers)
full_livers = np.expand_dims(full_livers,axis=-1)
2、数据的预处理
1、将ct值转化为标准的hu值
⾄于为什么要将值进⾏转化,这⼉就不详细说明,具体可以参考,这篇博⽂中有⼀样的get_pixels_hu函数2、窗⼝化操作
3、直⽅图均衡化
def clahe_equalized(imgs,start,end):
asrt(len(imgs.shape)==3)#3D arrays
#create a CLAHE object (Arguments are optional).
clahe = ateCLAHE(clipLimit=2.0, tileGridSize=(8,8))
七彩果
imgs_equalized = np.empty(imgs.shape)
for i in range(start, end+1):
imgs_equalized[i,:,:]= clahe.apply(np.array(imgs[i,:,:], dtype = np.uint8))
return imgs_equalized
4、归⼀化
5、仅提取腹部所有切⽚中包含了肝脏的那些切⽚,其余的不要
# 接part1
images = get_pixels_hu(image_slices)
棉花简笔画
images = transform_ctdata(images,500,150)
start,end = getRangImageDepth(livers)
images = clahe_equalized(images,start,end)
images /=255.
# 仅提取腹部所有切⽚中包含了肝脏的那些切⽚,其余的不要
total =(end -4)-(start+4)+1
print("%d person, total slices %d"%(i,total))
# ⾸和尾⽬标区域都太⼩,舍弃
images = images[start+5:end-5]
print("%d person, images.shape:(%d,)"%(i,images.shape[0]))
livers[livers>0]=1三月的英文
livers = livers[start+5:end-5]
3、数据增强
利⽤keras的数据增强接⼝,可以实现分割问题的数据增强。⼀般的增强是分类问题,这种情况,只需要对image变形,label保持不变。但分割问题,就需要image和mask进⾏同样的变形处理。具体怎么实现,参考下⾯代码,注意种⼦设定成⼀样的。
# 可以在part1之前设定好(即循环外)
ed=1
暑假学习计划
data_gen_args =dict(rotation_range=3,
width_shift_range=0.01,
height_shift_range=0.01,
shear_range=0.01,
嫩白肌肤
zoom_range=0.01,
fill_mode='nearest')
image_datagen = ImageDataGenerator(**data_gen_args)
mask_datagen = ImageDataGenerator(**data_gen_args)
#part3 接part2
image_datagen.fit(full_images, augment=True, ed=ed)
mask_datagen.fit(full_livers, augment=True, ed=ed)
image_generator = image_datagen.flow(full_images,ed=ed)
mask_generator = mask_datagen.flow(full_livers,ed=ed)
train_generator =zip(image_generator, mask_generator)
x=[]
志愿服务活动
y=[]
i =0
for x_batch, y_batch in train_generator:
i +=1
x.append(x_batch)
y.append(y_batch)
if i>=2:# 因为我不需要太多的数据
break
x = np.vstack(x)
y = np.vstack(y)
4、数据存储
⼀般⽽⾔,数据量较⼤的话,都会先将原始数据库的东西转化为np或者h5格式的⽂件,我感觉这样有
两个好处,⼀是真正输⼊⽹络训练的时候io量会⼤⼤减少(特别是h5很适⽤于⼤的数据库),⼆是数据分享或者上传⾄服务器时也⽅便⼀点。
实验中会出现两个类,分别是写h5和读h5⽂件的辅助类:
这读⽂件的类写成了generator,这样可以结合训练⽹络时,keras的fit_generator来使⽤,降低内存开销。
class HDF5DatatWriter:
"""⽤来写数据到h5⽂件"""
class HDF5DatatGenerator:
"""⽤来读h5⽂件的数据"""
它们具体的实现在,因为篇幅问题,所以这⼉不详述
h5⽂件操作需要的包:import h5py
# 可以在part1之前设定好(即循环外)
# 这⼉的数量需要提前写好,感觉很不⽅便,但不知道怎么改,我是先跑了之前的程序,计算了⼀共有多少
# 张图⽚后再写的,但这样明显不是好的解决⽅案
datat = HDF5DatatWriter(image_dims=(2782,512,512,1),
mask_dims=(2782,512,512,1),
outputPath="data_train/train_liver.h5")
#part4 接part3
datat.add(full_images, full_livers)
datat.add(x, y)
# end of lop
datat.clo()
测试数据存储的全部过程
测试数据与上⾯训练数据的处理过程⼏乎⼀样,但测试数据不要进⾏数据增强