unet分割如何取其中一类_深度学习与医学图像处理 案例学习1——Unet肺部分割(CT图像)...
该研究旨在构建一种用于肺部X射线图像分割的深度学习架构,在Keras框架下实现高效训练,并结合迁移学习策略以提升模型泛化能力。
#引入普通包
1导入库
2引入NumPy库,并以np进行引用
3引入Pandas库,并以pd进行引用
4导入OpenCV库(OpenCV),并使用cv2进行图像处理操作
5引入Matplotlib的pyplot模块,并以plt进行绘图操作
6设置为inline模式显示Matplotlib绘图结果
7从Scikit-learn的模型选择模块中导入train_test_split函数,
8用于将数据集划分为训练集和测试集两部分
#引入深度学习包
从Keras导入模型,并加载所有层
转载请注明出处
from keras.optimizers import Adam  # 从Keras的优化器模块导入Adam优化算法
from keras.regularizers import l2  # 从Keras的正则化模块导入L2正则化技术
from keras.preprocessing.image import ImageDataGenerator  # 从Keras的数据预处理模块中的图像增强子模块导入ImageDataGenerator类
from keras import backend as K
分别导入学习率调度器和模型检查点回调
#导入图像文件并图像设置为指定大小
IMAGE_LIB = '../input/2d_images/'#图片路径
指定为../input/2d_masks/的路径用于加载掩模文件
all_images = [x for x in sorted(os.listdir(IMAGE_LIB)) if x[-4:] == '.tif'] # 图片名列表(后缀为.tif)
x_data= np.empty((len(all_images), IMG_HEIGHT, IMG_WIDTH), dtype=np.float32) #图像数据内存分配
遍历所有图片文件名
for i, name in enumerate(all_images): #读取图片文件名列表
image_data = cv2.imread(IMAGE_LIB + name, cv2.IMREAD_UNCHANGED).convert_to("int16").convert_to('float32') #使用cv2.IMREAD_UNCHANGED参数以包含透明通道
im = OpenCV’s resize function applied to the image with dimensions IMG_WIDTH by IMG_HEIGHT using the OpenCV's INTER_LANCZOS4 algorithm. #OpenCV's INTER_LANCZOS4 algorithm, utilizing an 8x8 pixel neighborhood for Lanczos interpolation.
im= (im - np.min(im)) / (np.max(im) -np.min(im)) #归一化
x_data[i]=im
y_data = np.empty((len(all_images), IMG_HEIGHT, IMG_WIDTH), dtype='float32')  # 创建一个浮点型数组用于存储掩模数据
for i, name in enumerate(all_images):  # 遍历所有图像文件名
im= cv2.imread(MASK_LIB + name, cv2.IMREAD_UNCHANGED).astype('float32')/255.
The image resizing operation employs the OpenCV function cv2.resize with the desired dimensions (IMG_WIDTH and IMG_HEIGHT) and nearest neighbor interpolation. The parameter cv2.INTER_NEAREST is utilized to specify this method.
y_data[i]= im
#显示图像及掩模
fig, ax = plt.subplots(1,2, figsize = (8,4)) #1行两列显示图像
ax[0].imshow(x_data[10], cmap='gray') #图像
ax[1].imshow(y_data[10], cmap='gray') #掩模
plt.show()

x_data =x_data[:,:,:,np.newaxis] #喂入神经网络前需新增第四维度
y_data=y_data[:,:,:,np.newaxis]
x_train, x_val, y_train, y_val = train_test_split(x_data, y_data, test_size=0.5) # 将数据集以一半的比例分割为训练集与验证集
#定义标准——dice系数
def dice_coef(y_true, y_pred):
y_true_f=K.flatten(y_true) #多维张量一维化
y_pred_f=K.flatten(y_pred)
交集项由K.sum(y_true\_f \times y\_pred\_f)计算得出。
返回值为(2 \times \text{交集项} + \epsilon)/(\text{总真实数} + \text{总预测数} + \epsilon)。
当实际集合与预测集合相等时(即A=B),该评估指标达到最大值1。
#模型
input_layer = Input(shape=x_train.shape[1:]) #shape=32,32,1
c1 = ConvLayer(filters=8, kernel_size=(3x3), activation='relu', padding='same')(input_layer) # Shape of the output tensor: 32x32x8
l= MaxPool2D(strides=(2,2))(c1) #shape=16,16,8
c2= Conv2D(filters=16, kernel_size=(3,3), activation='relu', padding='same')(l) #shape=16,16,16
l= MaxPool2D(strides=(2,2))(c2) #shape=8,8,16
c3= Conv2D(filters=32, kernel_size=(3,3), activation='relu', padding='same')(l) #shape=8,8,32
l= MaxPool2D(strides=(2,2))(c3) #shape=4,4,32
c4= Conv2D(filters=32, kernel_size=(1,1), activation='relu', padding='same')(l) #shape=4,4,32
l= concatenate([UpSampling2D(size=(2,2))(c4), c3], axis=-1) #UpSampling2D上采样,shape=8,8,64
l= Conv2D(filters=32, kernel_size=(2,2), activation='relu', padding='same')(l) #shape=8,8,32
l= concatenate([UpSampling2D(size=(2,2))(l), c2], axis=-1) #上采样,shape=16,16,48
l= Conv2D(filters=24, kernel_size=(2,2), activation='relu', padding='same')(l) #shape=16,16,24
l= concatenate([UpSampling2D(size=(2,2))(l), c1], axis=-1) #上采样,shape=32,32,32
l= Conv2D(filters=16, kernel_size=(2,2), activation='relu', padding='same')(l) #shape=32,32,16
l= Conv2D(filters=64, kernel_size=(1,1), activation='relu')(l) #shape=32,32,64
l= Dropout(0.5)(l) #shape=32,32,64
output_layer= Conv2D(filters=1, kernel_size=(1,1), activation='sigmoid')(l) #shape=32,32,1
model= Model(input_layer, output_layer)
#模型参数数量

#数据增强器
def my_generator(x_train, y_train, batch_size):
data_generator=ImageDataGenerator(
width_shift_range=0.1,
height_shift_range=0.1,
rotation_range=10,
zoom_range=0.1).flow(x_train, x_train, batch_size, seed=SEED)
mask_generator=ImageDataGenerator(
width_shift_range=0.1,
height_shift_range=0.1,
rotation_range=10,
zoom_range=0.1).flow(y_train, y_train, batch_size, seed=SEED)whileTrue:
x_batch, _=data_generator.next()
y_batch, _=mask_generator.next()yield x_batch, y_batch
#基于相同的随机种子生成增强后的图像及其对应的掩模,并展示一批经过增强处理的图像及其对应的掩模
image_batch, mask_batch = next(my_generator(x_train, y_train, 8))
fix, ax= plt.subplots(8,2, figsize=(8,20))for i in range(8):
ax[i,0].imshow(image_batch[i,:,:,0])
ax[i,1].imshow(mask_batch[i,:,:,0])
plt.show()

#编译模型
model.compile(optimizer=Adam(2e-4), loss='binary_crossentropy', metrics=[dice_coef]) #使用Adam优化算法进行损失函数为二元交叉熵的模型编译,并采用Dice系数作为评估指标
#为模型条件检查点
weight_saver is a variable assigned to an instance of ModelCheckpoint class. It is configured to save the 'lung.h5' model file, monitor validation dice coefficient during training, and only retain the best checkpoint as well as the weights.
#文件名称, monitor 监控的值, save_best_only:仅在验证集上性能最佳时会保存, save_weights_only:若设置为true则仅保存权重;否则则完整保存模型
#自动调整学习率
annealer = LearningRateScheduler(lambda x: 1e-3 * 0.8 ** x)
#训练
hist = model.fit_generator(my_generator(x_train, y_train, 8),
steps_per_epoch= 200,
validation_data=(x_val, y_val),
epochs=10, verbose=2,
callbacks= [weight_saver, annealer])
#generator:生成器函数
#steps_per_epoch:int 类型,在循环中每次生成器返回 steps_per_epoch 次数据时完成一次 epoch 循环,并执行下一个 epoch.
#epochs:整数,数据迭代的轮数
#verbose:控制日志信息显示模式,默认为不显示标准输出流的日志信息。该参数设置如下:
- 0表示不向标准输出流发送日志信息
 - 1表示以进度条形式展示当前训练过程的进展
 - 2表示在每个训练周期结束后打印一条训练相关信息提示
 
#结果


#评价
#model.load_weights('lung.h5') #使用最佳参数
plt.plot(hist.history['loss'], color='b')
plt.plot(hist.history['val_loss'], color='r')
plt.legend(['train_loss','val_loss'])
plt.show()
plt.plot(hist.history['dice_coef'], color='b')
plt.plot(hist.history['val_dice_coef'], color='r')
plt.legend(['train_dice_coef','val_dice_coef'])
plt.show()

#测试
pre=model.predict(x_train[10].reshape(1,IMG_HEIGHT, IMG_WIDTH, 1))[0,:,:,0]
fig, ax = plt.subplots(1,3, figsize = (12,6))
ax[0].imshow(x_train[10],cmap='gray')
ax[1].imshow(y_train[10],cmap='gray')
ax[2].imshow(pre)

y_hat =model.predict(x_val)
fig, ax= plt.subplots(10,3,figsize=(12,30))
for i in range(10):
ax[i,0].imshow(x_val[i,:,:,0], cmap='gray')
ax[i,1].imshow(y_val[i,:,:,0])
ax[i,2].imshow(y_hat[i,:,:,0])

#讨论
深度学习生成的图像并非仅由单一数值构成;每个像素点的具体取值范围限定在0到1之间;无论数值多么接近边界值,在实际应用中始终保持正值;该网络结构经过sigmoid函数处理后输出数值范围限定在(0,1)区间内;dice系数并不等同于简单的交并运算而是一种更为复杂的度量方式
生成真正的预测掩模还需要一个阈值。
倒数第二幅图的分割明显有问题。
为何测试集中计算得到的dice系数普遍优于训练数据中的dice系数?
#数据分享:链接: https://pan.baidu.com/s/1xXlHwn7Ek4mjJlJ4OFkgaw 提取码: rd5y
欢迎探讨、指教。
