医疗图像切割日记 01 - 用nnUNet做Fatal Head Segmentation Challenge

目录

1. nnUNet 介绍

1.1 nnUNet 特点

2. 准备工作

2.1 整理数据格式 - 用自己的数据集

2.2 设置路径

2.3 nnUNet预处理数据

3. 训练

3.1 训练代码

​编辑​编辑

3.2 训练结果

3.2.1 骰子系数 - 最差结果 - Worst Cases​编辑​编辑

3.2.2 骰子系数 - 最优结果 - Best Cases​编辑​编辑模型分析

4. 优化

4.1 数据预处理

4.2 优化结果 - 图片

4.2.1 骰子系数 - 最差结果 - Worst Cases​编辑​编辑

4.2.2 骰子系数 - 最优结果 - Best Cases​编辑​编辑

4.3 优化结果 - 数字

4.3.1 骰子

4.3.2 豪斯多夫

4.3.3 周长误差 (Circumference Error in mm)

5. 模型分析

5.1 索伦森-骰子系数 (Dice Distance)

5.2 豪斯多夫距离 (Hausdorff Distance) 

5.3 代码实现

6. 总结

总结(节俭版)


发的第一篇文,有很多要改进的地方。求各路大神多多指引
费时5天完成的一个Segmentation挑战,之前没有做过segmentation所以走了一点点弯路

nnUNet的github链接 - GitHub - MIC-DKFZ/nnUNet
nnUNet的文章链接- -nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation | Nature Methods
Fatal Head Segmentation Challenge的链接 - Home - Grand Challenge 

*部分代码非原创,会标注出处以及链接*


1. nnUNet 介绍

nnUNet是一款可以自己调整数据预处理,模型架构,训练,和后处理的深度学习医疗图片分割模型。在没有人工调参的情况下,nnUNet 在23个图形切割挑战上得到了最优的分数/前沿的效果。作者把nnUNet开源,让更多人,不论背景,都能轻松的接触到医疗图形切割的领域。

1.1 nnUNet 特点

  • 衡量标准:nnUNet 在很多数据集都达到了最优的结果。作者表示nnUNet可以算是行业标杆,让其他用户的模型和nnUNet做准确率比对。(咱也不敢问,咱也不敢说,大佬说什么都对)
  • 开箱即食:nnUNet 是第一个“开箱即食”的先进图像分割系统。没有segmentation经验的用户也可以(相对)流畅的使用nnUNet来做图像分割的任务。
  • 框架:nnUNet的模块化框架可以让用户替换/优化部分,可以有效的看到自己优化的效果。

2. 准备工作

2.1 整理数据格式 - 用自己的数据集

nnUNet 对数据的格式要求比较高,是根据Medical Segmentation Decathlon (MSD)的格式。

nnUNet_raw_data_base/nnUNet_raw_data/
├── Task001_BrainTumour
├── Task002_Heart
├── Task003_Liver
├── Task004_Hippocampus
├── Task005_Prostate
├── ...

~/Task001_BrainTumour/
├── dataset.json
├── imagesTr
├── (imagesTs)
└── labelsTr

详细转换方法请借鉴作者 github:nnUNet/dataset_conversion.md at master · MIC-DKFZ/nnUNet · GitHub

2.2 设置路径

nnUNet的初衷是能让每个数据集都能用这个模型跑,所以环境设置很重要!我是在colab上面跑的,如果要本地跑的话需要修改。这里有三个环境设置:

  • Raw database - 源数据路径
  • Preprocessed - 处理后的数据路径
  • Results Folder - 结果储存路径
os.environ['nnUNet_raw_data_base'] = "content/raw_data_base"
os.environ['nnUNet_preprocessed'] = "content/raw_data_base/nnUNet_preprocessed"
os.environ["RESULTS_FOLDER"] = "content/raw_data_base/results"

2.3 nnUNet预处理数据

在训练nnUNet之前需要用他们的代码预处理一下数据,代码如下:

nnUNet_plan_and_preprocess -t XXX --verify_dataset_integrity

这里nnUNet_plan_and_preprocess是命令,XXX是自定义的任务编号,建议设置在500+以防和现有模型冲突。如果这代码跑出来没问题就可以开始训练了。

3. 训练

3.1 训练代码

!nnUNet_train 2d nnUNetTrainerV2 555 0
!nnUNet_train 2d nnUNetTrainerV2 555 1
!nnUNet_train 2d nnUNetTrainerV2 555 2
!nnUNet_train 2d nnUNetTrainerV2 555 3
!nnUNet_train 2d nnUNetTrainerV2 555 4
#nnUNet_train 命令
#2d 跑2d nnUNet
#nnUNetTrainerV2 基础nnUNet
#555 任务编号
#0/1/2/3/4 多重编号
#!nnUNet_train 2d nnUNetTrainerV2 555 4 -c 
#Add -c to continue train from the last check point

3.2 训练结果

3.2.1 骰子系数 - 最差结果 - Worst Cases

3.2.2 骰子系数 - 最优结果 - Best Cases


模型分析

第一次跑出来的结果差强人意,并没有想象中能圈出预测的范围。绝大部分的预判结果都不是一个圈。大概想了一下导致这个的的原因,因为模型读到的mask是一个圈,他不会去学习圈圈中间的内容,只会去预判那个圈。这个方法的缺点就是在模型不确定的时候会不预判任何东西,导致我们不知道哪里出了问题。

4. 优化

4.1 数据预处理

这里数据做一个简单的数据增强,就是把这个圈圈填上。
*在自己处理的时候遇到了一些小问题所以联系了nnUNet的作者,Fabian在3天内就把图像预处理的代码做出来发布在github上了(发的时候bug已解决)*
Fabian 提供的官方代码链接:nnUNet/Task218_HC18.py at master · MIC-DKFZ/nnUNet · GitHub


4.2 优化结果 - 图片

填完之后再跑一次数据格式处理,如何再训练一次。得到的结果如下。

4.2.1 骰子系数 - 最差结果 - Worst Cases


4.2.2 骰子系数 - 最优结果 - Best Cases

4.3 优化结果 - 数字

4.3.1 骰子

The 7 cases with the worst results are:
023_2HC.png - 0.34406
022_2HC.png - 0.55531
024_HC.png - 0.59306
031_HC.png - 0.63960
009_HC.png - 0.65774
094_HC.png - 0.65859
007_HC.png - 0.74304
032_2HC.png - 0.75615
====================================
The 7 cases with the best results are:
037_HC.png - 0.98398
080_HC.png - 0.98411
054_HC.png - 0.98487
039_HC.png - 0.98496
061_HC.png - 0.98595
068_HC.png - 0.98621
072_HC.png - 0.98723
040_HC.png - 0.98864
The model achieved an average accuracy score of: 0.9255711501147182
The highest Accuracy in the batch: 0.9886378848728247
The lowest Accuracy in the batch: 0.34406099681349833

4.3.2 豪斯多夫

The 7 cases with the worst results are:
052_HC.png - 53.00000
002_HC.png - 73.23933
032_2HC.png - 96.89685
046_HC.png - 151.71355
012_HC.png - 229.80426
083_2HC.png - 279.57111
023_2HC.png - 351.10254
094_HC.png - 434.88504
====================================
The 7 cases with the best results are:
037_HC.png - 0.00000
011_HC.png - 1.00000
048_HC.png - 1.00000
054_HC.png - 1.00000
066_2HC.png - 1.00000
068_HC.png - 1.00000
072_HC.png - 1.00000
076_HC.png - 1.00000
The model achieved an average accuracy score of: 21.673193653752982
The longest Haussdorf Distance in the batch: 434.8850402832031
The shortest Haussdorf Distance in the batch: 0.0

4.3.3 周长误差 (Circumference Error in mm)

周长误差是算基准周长和预判结果的周长差距(单位为mm)

The average error in mm is: 11.292108091481538
The file set with the maximum error is: 083_2HC.png, with an error of 84.41819 mm
The file set with the minimum error is: 006_HC.png, with an error of 0.18754 mm

计算下来,平均误差是11.29mm
测试集中,最大的误差是84.42mm
测试集中,最小的误差是0.19mm

5. 模型分析

5.1 索伦森-骰子系数 (Dice Distance)

Dice = \frac{2|X \cap Y|}{|X|+|Y|}
筛子系数是2乘以模型结果和基准的结合除以两个图片的像素总值
IoU = \frac{2|X \cap Y|}{X \cup Y}
两个公式是正相关的,比如如果模型A的骰子系数比模型B的骰子系数高,这么模型A的IoU系数比也会比模型B的IoU系数高

5.2 豪斯多夫距离 (Hausdorff Distance) 

豪斯多夫距离是在度量空间中任意两个集合之间定义的一种距离。 设X和Y是度量空间M的两个真子集,那么豪斯多夫距离dH(X,Y)是最小的数r使得X的闭r—邻域包含Y,Y的闭r—邻域也包含X

 -这段来于百度百科


5.3 代码实现

def get_Dice_list(resList, predPath, gtPath):
  for file in os.listdir(predPath):
    path = predPath + file
    if os.path.isfile(path):
      predicted = predPath + file
      groundTruth = gtPath + file
      acc = diceScore(predicted, groundTruth)
      resList.append(acc)
    else:
      pass
  return(resList)
def get_Haussdorf_list(listHaussdorf, predPath, gtPath):
"""
Calculate the Haussdorf distance between the results and the ground truth
    and returning them in a list.
list listHaussdorf - Haussdorf result list
str gtPath - Path to the ground truth masks
str predPath - Path to the predicted masks

计算模型跑出来的结果和基准的Haussdorf值,返回一个数值列表
list listHaussdorf - Haussdorf 结果列表
str gtPath - 基准路径
str predPath - 预测结果路径
"""
  for file in os.listdir(predPath): #Iterate through Result Path 
    path = gtPath + file
    if os.path.isfile(path): 
      predicted = predPath + file
      groundTruth = gtPath + file

      # 1.Import the Photos
      # 1.导入图片
      img_cs1 = cv2.imread(predicted)
      img_cs2 = cv2.imread(groundTruth)
      
      # 2.Get the contours of both images
      # 2.获取图片连通域
      try:
        cnt_cs1 = get_contours(img_cs1)
        cnt_cs2 = get_contours(img_cs2)
        hausdorff_sd = cv2.createHausdorffDistanceExtractor()

      # 3.Calculate the distance between the contours
      # 3.计算轮廓之间的距离
        d3 = hausdorff_sd.computeDistance(cnt_cs2, cnt_cs1)
        listHaussdorf.append(d3)
      except IndexError:
        listHaussdorf.append(999999) 
      
  return listHaussdorf



def get_contours(img):
    """
    Get contours of the image
    img: Image generated from the model and ground truth
    Returns image of contour

    获取连通域
    :param img: 输入图片
    :return: 最大连通域
    """
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Grayscale 灰度化
    ret, img_bin = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY)
    # Binary and set threshold 二值化, 连通域分析
    contours, hierarchy = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    
    return contours[0]

#The contour calculation code is adapted from https://www.pythonf.cn/read/57691
#连通区域计算代码来源于: https://www.pythonf.cn/read/57691


6. 总结

nnUNet是一个非常容易调用的深度学习模型,很多初学者可以拿他入手做一些有趣的项目。例如肿瘤检测: Task 029 - nnUNet/Task029_LiverTumorSegmentationChallenge.py at master · MIC-DKFZ/nnUNet · GitHub,马路检测: Task 120 - MassGIS Data: Massachusetts Department of Transportation (MassDOT) Roads | Mass.gov

总结(节俭版)

Fabian nb
 


资源整理
nnUNet 代码GitHub - MIC-DKFZ/nnUNet
nnUNet 文献nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation | Nature Methods
Fatal Head Segmentation 链接Home - Grand Challenge
数据链接Automated measurement of fetal head circumference using 2D ultrasound images | Zenodo
豪斯多夫 - 代码Python+opencv2(I)豪斯多夫距离,PythonOpencv2,一,Hausdorff
推荐nnUNet文章(四:2020.07.28)nnUNet最舒服的训练教程(让我的奶奶也会用nnUNet(上))(21.04.20更新)_花卷汤圆的博客-CSDN博客_nnunet
Colab 代码链接


×注-Colab当时写的有点急促,这一段忙完了会加备注后发布,如果需要跑的话欢迎私信。也欢迎各路大佬评论留言多提建议!谢谢~

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值