今天为大家带来的内容是Mean surface distance 平均表面距离的原理介绍及MindSpore的实现代码。
当我们评价图像分割的质量和模型表现时,经常会用到各类表面距离的计算。比如:
-
Mean surface distance 平均表面距离
-
Hausdorff distance 豪斯多夫距离(也被称为max_surface_distance 最大表面距离MSD)
-
Surface overlap 表面重叠度
-
Surface dice 表面dice值
-
Volumetric dice 三维dice值
等,都可以称为表面距离系列了。今天简单的讲解一下Mean surface distance 平均表面距离。
Mean surface distance 介绍
顾名思义,Mean surface distance这个指标就是P中所有点的表面距离的平均。这个指标又可称为Average Symmetric Surface Distance (ASSD),它也是医疗图像分割竞赛CHAOS中的一个评估指标。
This function is used to compute the Average Surface Distance from `y_pred` to `y` under the default setting. Mean Surface Distance(MSD), the mean of the vector is taken. This tell us how much, on average, the surface varies between the segmentation and the GT.
其实这个表面距离也没啥可介绍的,似乎就这么简单。来看看公式吧:
MindSpore 代码实现
原理已经讲完,话不多说,我们开始上代码。使用的是MindSpore框架实现的代码。
"""MeanSurfaceDistance."""
from scipy.ndimage import morphology
import numpy as np
from mindspore._checkparam import Validator as validator
from .metric import Metric
class MeanSurfaceDistance(Metric):
def __init__(self, symmetric=False, distance_metric="euclidean"):
super(MeanSurfaceDistance, self).__init__()
self.distance_metric_list = ["euclidean", "chessboard", "taxicab"]
distance_metric = validator.check_value_type("distance_metric", distance_metric, [str])
self.distance_metric = validator.check_string(distance_metric, self.distance_metric_list, "distance_metric")
self.symmetric = validator.check_value_type("symmetric", symmetric, [bool])
self.clear()
def clear(self):
"""Clears the internal evaluation result."""
self._y_pred_edges = 0
self._y_edges = 0
self._is_update = False
def _get_surface_distance(self, y_pred_edges, y_edges):
"""
计算从预测图片边界到真实图片边界的表面距离。
"""
if not np.any(y_pred_edges):
return np.array([])
if not np.any(y_edges):
dis = np.full(y_edges.shape, np.inf)
else:
if self.distance_metric == "euclidean":
dis = morphology.distance_transform_edt(~y_edges)
elif self.distance_metric in self.distance_metric_list[-2:]:
dis = morphology.distance_transform_cdt(~y_edges, metric=self.distance_metric)
surface_distance = dis[y_pred_edges]
return surface_distance
def update(self, *inputs):
"""
更新输入数据。
"""
if len(inputs) != 3:
raise ValueError('MeanSurfaceDistance need 3 inputs (y_pred, y, label), but got {}.'.format(len(inputs)))
y_pred = self._convert_data(inputs[0])
y = self._convert_data(inputs[1])
label_idx = inputs[2]
if y_pred.size == 0 or y_pred.shape != y.shape:
raise ValueError("y_pred and y should have same shape, but got {}, {}.".format(y_pred.shape, y.shape))
if y_pred.dtype != bool:
y_pred = y_pred == label_idx
if y.dtype != bool:
y = y == label_idx
self._y_pred_edges = morphology.binary_erosion(y_pred) ^ y_pred
self._y_edges = morphology.binary_erosion(y) ^ y
self._is_update = True
def eval(self):
"""
计算平均表面距离。
"""
if self._is_update is False:
raise RuntimeError('Call the update method before calling eval.')
mean_surface_distance = self._get_surface_distance(self._y_pred_edges, self._y_edges)
if mean_surface_distance.shape == (0,):
return np.inf
avg_surface_distance = mean_surface_distance.mean()
if not self.symmetric:
return avg_surface_distance
contrary_mean_surface_distance = self._get_surface_distance(self._y_edges, self._y_pred_edges)
if contrary_mean_surface_distance.shape == (0,):
return np.inf
contrary_avg_surface_distance = contrary_mean_surface_distance.mean()
return np.mean((avg_surface_distance, contrary_avg_surface_distance))
使用方法如下:
import numpy as np
from mindspore import Tensor
from mindspore.nn.metrics import MeanSurfaceDistance
def test_mean_surface_distance():
"""test_mean_surface_distance"""
x = Tensor(np.array([[3, 0, 1], [1, 3, 0], [1, 0, 2]]))
y = Tensor(np.array([[0, 2, 1], [1, 2, 1], [0, 0, 1]]))
metric = MeanSurfaceDistance()
metric.clear()
metric.update(x, y, 0)
distance = metric.eval()
print(distance)
test_mean_surface_distance()
1.4142135623730951
每个batch(比如两组数据)进行计算的时候如下:
import numpy as np
from mindspore import Tensor
from mindspore.nn.metrics import MeanSurfaceDistance
x = Tensor(np.array([[3, 0, 1], [1, 3, 0], [1, 0, 2]]))
y = Tensor(np.array([[0, 2, 1], [1, 2, 1], [0, 0, 1]]))
metric = MeanSurfaceDistance()
metric.clear()
metric.update(x, y, 0)
x1 = Tensor(np.array([[3, 0, 1], [1, 3, 0], [1, 0, 2]]))
y1 = Tensor(np.array([[0, 2, 1], [1, 2, 1], [0, 0, 1]]))
metric.update(x1, y1, 0)
distance = metric.eval()
print(distance)
MindSpore官方资料
官方QQ群 : 486831414
官网:https://www.mindspore.cn/
Gitee : https : //gitee.com/mindspore/mindspore
GitHub : https://github.com/mindspore-ai/mindspore
论坛:https://bbs.huaweicloud.com/forum/forum-1076-1.html