Skip to content

Commit 9ca174b

Browse files
committed
Address review: docs entry, docstring caveats, formatting
- Add AbsoluteVolumeDifferenceMetric + compute_absolute_volume_difference to docs/source/metrics.rst - Note in the class docstring that 2D inputs yield surface areas and that values are raw voxel/pixel counts, not scaled by spacing - Drop the unnecessary __init__ docstring - Remove the redundant top-level import test - Assert ValueError (not bare Exception) on aggregate after reset - Apply black/isort formatting Signed-off-by: Md Salman Shams <salmanshams67@gmail.com>
1 parent df9a173 commit 9ca174b

3 files changed

Lines changed: 19 additions & 28 deletions

File tree

docs/source/metrics.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ Metrics
116116
.. autoclass:: SurfaceDiceMetric
117117
:members:
118118

119+
`Absolute volume difference`
120+
----------------------------
121+
.. autofunction:: compute_absolute_volume_difference
122+
123+
.. autoclass:: AbsoluteVolumeDifferenceMetric
124+
:members:
125+
119126
`PanopticQualityMetric`
120127
-----------------------
121128
.. autofunction:: compute_panoptic_quality

monai/metrics/absolute_volume_difference.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ class AbsoluteVolumeDifferenceMetric(CumulativeIterationMetric):
3131
segmentation (e.g. retinal fluid in OCT volumes) where Dice score is known to be
3232
overly sensitive to volume size and does not directly reflect volume discrepancies.
3333
34+
.. note::
35+
For 2D inputs this computes the difference in foreground **areas** rather than
36+
volumes. In all cases the returned values are raw voxel/pixel counts and are
37+
**not** scaled by the voxel/pixel spacing, so they are not expressed in the
38+
physical units of the original image.
39+
3440
Reference:
3541
Bogunovic et al. (2019). RETOUCH: The Retinal OCT Fluid Detection and
3642
Segmentation Benchmark and Challenge.
@@ -84,7 +90,6 @@ def __init__(
8490
get_not_nans: bool = False,
8591
ignore_empty: bool = True,
8692
) -> None:
87-
"""Initialize AbsoluteVolumeDifferenceMetric. See class docstring for argument descriptions."""
8893
super().__init__()
8994
self.include_background = include_background
9095
self.reduction = reduction
@@ -105,10 +110,7 @@ def _compute_tensor(self, y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor
105110
f"y_pred should have at least 3 dimensions (batch, channel, spatial), got {y_pred.ndimension()}."
106111
)
107112
return compute_absolute_volume_difference(
108-
y_pred=y_pred,
109-
y=y,
110-
include_background=self.include_background,
111-
ignore_empty=self.ignore_empty,
113+
y_pred=y_pred, y=y, include_background=self.include_background, ignore_empty=self.ignore_empty
112114
)
113115

114116
def aggregate(
@@ -129,10 +131,7 @@ def aggregate(
129131

130132

131133
def compute_absolute_volume_difference(
132-
y_pred: torch.Tensor,
133-
y: torch.Tensor,
134-
include_background: bool = True,
135-
ignore_empty: bool = True,
134+
y_pred: torch.Tensor, y: torch.Tensor, include_background: bool = True, ignore_empty: bool = True
136135
) -> torch.Tensor:
137136
"""
138137
Compute the Absolute Volume Difference (AVD) for a batch of segmentation predictions.
@@ -159,9 +158,7 @@ def compute_absolute_volume_difference(
159158
ValueError: when ``y_pred`` and ``y`` have different shapes.
160159
"""
161160
if y_pred.ndim < 3:
162-
raise ValueError(
163-
f"y_pred should have at least 3 dimensions (batch, channel, spatial), got {y_pred.ndim}."
164-
)
161+
raise ValueError(f"y_pred should have at least 3 dimensions (batch, channel, spatial), got {y_pred.ndim}.")
165162

166163
if not include_background:
167164
y_pred, y = ignore_background(y_pred=y_pred, y=y)

tests/metrics/test_absolute_volume_difference.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,12 @@ def test_ignore_empty_false_returns_pred_volume(self):
7878
def test_shape_mismatch_raises(self):
7979
"""Mismatched y_pred and y shapes should raise a ValueError."""
8080
with self.assertRaises(ValueError):
81-
compute_absolute_volume_difference(
82-
y_pred=torch.zeros(2, 3, 8, 8),
83-
y=torch.zeros(2, 3, 4, 4),
84-
)
81+
compute_absolute_volume_difference(y_pred=torch.zeros(2, 3, 8, 8), y=torch.zeros(2, 3, 4, 4))
8582

8683
def test_too_few_dims_raises(self):
8784
"""Input tensors with fewer than 3 dimensions should raise a ValueError."""
8885
with self.assertRaises(ValueError):
89-
compute_absolute_volume_difference(
90-
y_pred=torch.zeros(2, 3),
91-
y=torch.zeros(2, 3),
92-
)
86+
compute_absolute_volume_difference(y_pred=torch.zeros(2, 3), y=torch.zeros(2, 3))
9387

9488
def test_3d_volumes(self):
9589
"""AVD should correctly count voxel differences in 3-D spatial inputs."""
@@ -159,16 +153,9 @@ def test_reset_clears_buffer(self):
159153
metric(y, y)
160154
metric.reset()
161155
# after reset the buffer should be empty; calling aggregate raises
162-
with self.assertRaises(Exception):
156+
with self.assertRaises(ValueError):
163157
metric.aggregate()
164158

165-
def test_imported_from_top_level(self):
166-
"""AbsoluteVolumeDifferenceMetric should be importable from the monai.metrics top-level namespace."""
167-
# ensure the class is accessible from monai.metrics top-level
168-
from monai.metrics import AbsoluteVolumeDifferenceMetric as _AVD
169-
170-
self.assertIs(_AVD, AbsoluteVolumeDifferenceMetric)
171-
172159

173160
if __name__ == "__main__":
174161
unittest.main()

0 commit comments

Comments
 (0)