Dice score分割评价指标

介绍分割任务中常见的评价指标Dice coefficient score

代码实现和注意事项。

介绍

Dice-Sørensen coefficient用于衡量两个样本相似性的统计量,最初旨在应用于离散数据。

其定义为:

$$
DSC = \frac{2|X \bigcap Y|}{|X| + |Y|}
$$

  • $|X|$,$|Y|$两个集合的元素。

在图像分割任务中:

  • X和Y:一个代表预测标签,一个代表真实

代码实现

  1. Python手动实现(By Claude)💦
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 import numpy as np

def dice_score(array1, array2):
"""
Calculate Dice coefficient between two 2D binary arrays.

Parameters:
array1, array2: numpy arrays with binary values (0 and 1)

Returns:
dice: float, the Dice coefficient between the two arrays
"""
# Ensure the inputs are binary
array1 = np.asarray(array1).astype(bool)
array2 = np.asarray(array2).astype(bool)

# Calculate intersection and sum
intersection = np.logical_and(array1, array2).sum()
sum_arrays = array1.sum() + array2.sum()

# Handle edge case where both arrays are empty
if sum_arrays == 0:
return 1.0 # Both arrays are empty, consider them identical

# Calculate Dice coefficient
dice = (2.0 * intersection) / sum_arrays

return dice

if __name__ == '__main__':
# Create two sample 2D binary arrays
mask1 = np.array([
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 1, 1, 0],
[0, 0, 0, 0]
])

mask2 = np.array([
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 0]
])

# Calculate Dice score
score = dice_score(mask1, mask2)
print(f"Dice score: {score:.4f}") # Result: 0.8571 (6/7)
  1. 调用medpy中现有的dice计算👍

::: success
推荐使用这个方法
:::

1
pip install medpy

其具有几个优点:

  1. 充分的测试和优化
  2. 正确处理边缘情况
  3. 无需编写复杂的计算

如果是多分类的时候,可能需要计算不同类别的Dice分数,其实现方法为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from medpy import metric
import numpy as np

# For multi-class segmentation
def multi_class_dice(array1, array2, num_classes):
"""
Calculate Dice score for each class in multi-class segmentation.

Parameters:
array1, array2: numpy arrays with class labels (0, 1, 2, etc.)
num_classes: number of classes including background

Returns:
dice_scores: list of Dice scores for each class
"""
dice_scores = []

for i in range(num_classes):
# Create binary masks for the current class
mask1 = (array1 == i).astype(np.uint8)
mask2 = (array2 == i).astype(np.uint8)

# Calculate Dice score for the current class
if np.sum(mask1) == 0 and np.sum(mask2) == 0:
# Both masks are empty, consider perfect overlap
dice_scores.append(1.0)
else:
dice_scores.append(metric.binary.dc(mask1, mask2))

return dice_scores

medpy中包含了很多便于处理医学图像的功能。

注意❗

CSDN博客中,有不少文章在手动实现Dice计算的时候,为了防止除以0发生,加入一个极小值smooth来计算。

这个极小值会两倍加在分子,一倍加入分母。

但是,我在实验中发现即使是再小的极小值,都会对分割分数有极大地影响,分割结果越是差,这个加入了极小值的计算方法得到的dice越高。

(如:pred全为0,但gt不为0的时候,dice不为0且有70左右。)

尚未查证具体影响的原因,但推测是因为这个极小值加在了图像整体上,float的计算无法忽视这种“距离”的接近,造成了错误的结果。

本博客中的手动实现dice在遇到0的时候采用单独判断,不会影响,可以放心使用。但最推荐的还是使用medpy的方法。

作者

Zhou

发布于

2025-03-30

更新于

2025-04-01

许可协议

评论

+ + +