[常规赛] PALM眼底彩照视盘探测与分割 - 9月第1名方案
赛题链接:常规赛:PALM眼底彩照视盘探测与分割赛题简介:ISBI2019 PALM眼科挑战赛赛题再现,提供800张眼底彩照训练数据集, 要求选手训练模型完成眼底视盘结构的探测和分割任务。赛题背景:本赛题原型为ISBI2019PALM眼科大赛。 近视已成为全球公共卫生负担。在近视患者中,约35%为高度近视。近视导致眼轴长度的延长,可能引起视网膜和脉络膜的病理改变。随着近视屈光度的增加,高度近视将发
·
- 赛题链接:常规赛:PALM眼底彩照视盘探测与分割
- 赛题简介:ISBI2019 PALM眼科挑战赛赛题再现,提供800张眼底彩照训练数据集, 要求选手训练模型完成眼底视盘结构的探测和分割任务。
- 赛题背景:
- 本赛题原型为ISBI2019PALM眼科大赛。 近视已成为全球公共卫生负担。在近视患者中,约35%为高度近视。近视导致眼轴长度的延长,可能引起视网膜和脉络膜的病理改变。随着近视屈光度的增加,高度近视将发展为病理性近视,其特点是病理改变的形成:(1)后极,包括镶嵌型眼底、后葡萄肿、视网膜脉络膜变性等;(2)视盘,包括乳头旁萎缩、倾斜等;(3)近视性黄斑,包括漆裂、福氏斑、CNV等。病理性近视对患者造成不可逆的视力损害。因此,早期诊断和定期随访非常重要。
- 视网膜由黄斑向鼻侧约3mm处有一直径约1.5mm、境界清楚的淡红色圆盘状结构,称为视神经盘,简称视盘。视盘是眼底图像的一个重要特征,对其进行准确、快速地定位与分割对利用眼底图像进行疾病辅助诊断具有重要意义。
- 飞桨工具组件 - PaddleX
- 飞桨全流程开发工具,集飞桨核心框架、模型库、工具及组件等深度学习开发所需全部能力于一身,打通深度学习开发全流程。
- PaddleX同时提供简明易懂的Python API,及一键下载安装的图形化开发客户端。用户可根据实际生产需求选择相应的开发方式,获得飞桨全流程开发的最佳体验。
[0] 安装PaddleX
- 此处默认为PaddleX 2.0.0版本。
!pip install paddlex --upgrade
[1] 导入依赖模块
import warnings
warnings.filterwarnings('ignore')
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
from paddlex import transforms as T
import paddlex as pdx
import paddle
from paddle.regularizer import L2Decay
import shutil
import glob
import numpy as np
import pandas as pd
import cv2
import imghdr
from PIL import Image
[2] 生成 VOC 格式文件夹
- Paddle系列开发套件为VOC格式文件夹提供友好的支持。
- 数据集结构如下,即可使用PaddleX自动进行数据划分:
Dataset/ # 语义分割数据集根目录
|--JPEGImages/ # 原图文件所在目录(默认不支持.TIF)
| |--1.jpg
| |--2.jpg
| |--...
| |--...
|
|--Annotations/ # 标注文件所在目录(注意为.PNG)
| |--1.png
| |--2.png
| |--...
| |--...
- 尊重数据版权,“切记不要将本数据集上传到任何渠道的个人空间(包括飞桨公开数据库),若被数据提供方发现,将被严肃处理”。
- 利用官网数据链接下载数据到
data/dataset.zip
。
!wget https://bj.bcebos.com/v1/dataset-bj/%E5%8C%BB%E7%96%97%E6%AF%94%E8%B5%9B/%E5%B8%B8%E8%A7%84%E8%B5%9B%EF%BC%9APALM%E7%9C%BC%E5%BA%95%E5%BD%A9%E7%85%A7%E8%A7%86%E7%9B%98%E6%8E%A2%E6%B5%8B%E4%B8%8E%E5%88%86%E5%89%B2.zip -O data/dataset.zip
- 使用
pdx.utils.decompress
解压目标文件至同级目录下(解压后注意文件名乱码,可手动复制路径)。 - 利用
mv
命令重命名至VOC格式文件夹。
pdx.utils.decompress('data/dataset.zip')
!rm -rf data/__MACOSX
!mv data/常规赛:PALM眼底彩照视盘探测与分割 data/dataset
!mv data/dataset/Train/fundus_image data/dataset/Train/JPEGImages
!mv data/dataset/Train/Disc_Masks data/dataset/Train/Annotations
!tree data/dataset/Train -L 1
data/dataset/Train
├── Annotations
└── JPEGImages
2 directories, 0 files
[3] 图片数据清洗
-
图片的模式(mode)分别为 RGB(真彩色、三通道) 和 L(8位灰度图),统一转成JPG和PNG格式;
-
图片的尺寸(size)统一为(1444,1444),因为有的 img/label 的尺寸不同。
-
语义分割的标注图像,如1.png,为单通道图像,像素标注类别需要从0开始递增(一般0表示background背景), 例如0, 1, 2, 3表示4种类别,标注类别最多255个类别(其中像素值255不参与训练和评估)。
-
此处将会把0-255变成0-1的PNG标注图。
jpg_path_list = glob.glob('data/dataset/Train/JPEGImages/*.jpg')
for i in range(len(jpg_path_list)):
jpg_path = jpg_path_list[i]
jpg_name = str(jpg_path.split('/')[-1]).split('.')[0]
ant_path = os.path.join('data/dataset/Train/Annotations', f'{jpg_name}.bmp')
if imghdr.what(jpg_path) and imghdr.what(ant_path):
img_jpg = Image.open(jpg_path).convert('RGB')
img_jpg = img_jpg.resize((1444, 1444))
img_jpg.save(jpg_path)
img_ant = Image.open(ant_path).convert('L')
img_ant = img_ant.resize((1444, 1444))
img_ant = np.array(img_ant, dtype='uint8')
img_ant = np.uint8((img_ant == 0) * 1)
cv2.imwrite(ant_path.split('.')[0]+'.png', img_ant)
os.remove(ant_path)
else:
if os.path.exists(jpg_path):
os.remove(jpg_path)
print('delete:', jpg_path)
if os.path.exists(ant_path):
os.remove(ant_path)
print('delete:', ant_path)
[4] 数据集划分
!paddlex --split_dataset --format SEG\
--dataset_dir data/dataset/Train/\
--val_value 0.25\
--test_value 0
[5] 定义数据增强,并装载数据集
- Mix-Up 数据增强操作在图像分类中更常用,但此处也能涨点。
- 图像尺寸归一化为512x512,加上水平翻转和垂直翻转,最后归一化(PaddleX默认为ImageNet的mean和std)。
train_transforms = T.Compose([
T.MixupImage(mixup_epoch=130),
T.Resize(512),
T.RandomHorizontalFlip(0.5),
T.RandomVerticalFlip(0.5),
T.Normalize()
])
eval_transforms = T.Compose([
T.Resize(512),
T.Normalize()
])
train_dataset = pdx.datasets.seg_dataset.SegDataset(
data_dir='data/dataset/Train',
file_list='data/dataset/Train/train_list.txt',
label_list='data/dataset/Train/labels.txt',
transforms=train_transforms,
shuffle=True)
eval_dataset = pdx.datasets.seg_dataset.SegDataset(
data_dir='data/dataset/Train',
file_list='data/dataset/Train/val_list.txt',
label_list='data/dataset/Train/labels.txt',
transforms=eval_transforms)
[6] 配置 UNet 模型并训练
- 图像分割任务中常出现类别不均衡的情况,而 Lovasz Loss 对这种情况有一定的改善。
model = pdx.seg.UNet(
num_classes=len(train_dataset.labels),
use_mixed_loss=[('LovaszSoftmaxLoss', 1)])
- PaddleX内置了
Momentum
优化器和polynomial
学习率衰减策略。
model.train(
num_epochs=150,
train_dataset=train_dataset,
save_dir='output/UNet_Lovasz',
eval_dataset=eval_dataset,
train_batch_size=8,
learning_rate=0.02,
log_interval_steps=75,
pretrain_weights='IMAGENET',
save_interval_epochs=5,
use_vdl=False)
[7] 模型预测,另存为提交图片
model = pdx.load_model('output/UNet_Lovasz/epoch_150')
model.get_model_info()
- 单张图片的预测结果可视化。
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread('data/dataset/PALM-Testing400-Images/T0056.jpg')
result = model.predict(img.astype('float32'))
plt.figure(figsize=(8, 8))
plt.subplot(211)
plt.imshow(img[:, :, [2, 1, 0]])
plt.subplot(212)
plt.imshow(result['label_map'])
plt.show()
- 生成提交文件夹
work/Disc_Segmentation
,下载到本地压缩提交。 PIL.Image
方式读入图片并convert('RGB')
防止脏数据,预测时将RGB转换成BGR通道。- 模型输出0-1转换成255-0,和赛题要求一致。
if not os.path.exists('work/Disc_Segmentation'):
os.makedirs('work/Disc_Segmentation')
test_path_list = glob.glob('data/dataset/PALM-Testing400-Images/*.jpg')
for path in test_path_list:
img = Image.open(path).convert('RGB')
img = np.array(img, dtype='float32')
result = model.predict(img[:, :, [2, 1, 0]])
label_map = np.uint8((result['label_map'] == 0)*255)
img_name = str(path.split('/')[-1]).split('.')[0]
cv2.imwrite(f'work/Disc_Segmentation/{img_name}.png', label_map)
更多推荐
已为社区贡献1438条内容
所有评论(0)