Skip to content

Commit

Permalink
Merge pull request #13 from BMCV/develop
Browse files Browse the repository at this point in the history
Update to 1.5.0, including #11, #12, #14, #15
  • Loading branch information
kostrykin authored Mar 14, 2024
2 parents 4838e3f + 1415eec commit 1f34b61
Show file tree
Hide file tree
Showing 29 changed files with 1,557 additions and 743 deletions.
7 changes: 7 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[flake8]

extend-ignore = E221,E211,E222,E202,F541,E201,E203

per-file-ignores =
segmetrics/__init__.py:F401
tests/isbi_seg.py:E501
2 changes: 0 additions & 2 deletions .gitattributes

This file was deleted.

63 changes: 57 additions & 6 deletions .github/workflows/testsuite.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
name: Test suite


on:

workflow_dispatch:
Expand All @@ -24,19 +23,68 @@ on:
branches:
- master


permissions:
contents: read
issues: write
pull-requests: write


jobs:

run_testsuite:
python_lint:

name: Linting
runs-on: ubuntu-latest

steps:

- name: Checkout
uses: actions/checkout@v4

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 isort
- name: Run flake8
shell: bash
run: |
flake8 segmetrics
flake8 tests
- name: Run isort
shell: bash
run: |
isort segmetrics --check-only
isort tests --check-only
type_checking:

name: Type checking
runs-on: ubuntu-latest

steps:

- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy
name: Test suite
- name: Run mypy
shell: bash
run: |
mypy --config-file .mypy.ini --ignore-missing-imports segmetrics
run_testsuite:

name: Tests
runs-on: ubuntu-latest

strategy:
Expand Down Expand Up @@ -76,4 +124,7 @@ jobs:
gist-id: f46ddefff0798639bc320b13331dc7ca
github-auth: ${{ secrets.GITHUB_TOKEN }}
gist-auth: ${{ secrets.GIST_SECRET }}
gist-filename: segmetrics.json
gist-filename: segmetrics.json
run: |
coverage run -m unittest discover
python -m coverage json --omit "tests/*,segmetrics/deprecated.py"
5 changes: 5 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[settings]

multi_line_output = 3
force_grid_wrap = 2
include_trailing_comma = true
3 changes: 3 additions & 0 deletions .mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[mypy]

disable_error_code = import-untyped
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
build:
os: "ubuntu-20.04"
tools:
python: "3.7"
python: "3.8"

sphinx:
fail_on_warning: true
Expand Down
61 changes: 41 additions & 20 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,66 +9,87 @@ First public release
1.0.0
-----

Drops compatibility with Python 2.7.
Drop compatibility with Python 2.7.

Adds ``replace`` argument to ``segmetrics.study.Study`` class.
Add ``replace`` argument for ``segmetrics.study.Study`` class.

Marks functions in ``segmetrics.boundary`` as private.
Mark functions in ``segmetrics.boundary`` as private.

Marks ``segmetrics.boundary.ObjectBasedDistance.obj_mapping`` as private.
Mark ``segmetrics.boundary.ObjectBasedDistance.obj_mapping`` as private.

Removes ``segmetrics.legacy``.
Remove ``segmetrics.legacy``.

Renames ``segmetrics.metric.Metric`` to ``segmetrics.measure.Measure``.
Rename ``segmetrics.metric.Metric`` to ``segmetrics.measure.Measure``.

Renames ``segmetrics.boundary.ObjectBasedDistance`` to ``segmetrics.boundary.ObjectBasedDistanceMeasure``.
Rename ``segmetrics.boundary.ObjectBasedDistance`` to ``segmetrics.boundary.ObjectBasedDistanceMeasure``.

1.1.0
-----

Adds ``segmetrics.cli``.
Add ``segmetrics.cli``.

Adds ``segmetrics.Measure.accumulative`` parameter and makes detection-based measures non-accumulative by default.
Add ``segmetrics.Measure.accumulative`` parameter and makes detection-based measures non-accumulative by default.

Removes the ``segmetrics.Measure.ACCUMULATIVE`` field.
Remove the ``segmetrics.Measure.ACCUMULATIVE`` field.

1.2.0
-----

Changes default names of performance measures in ``segmetrics.study.Study.add_measure()``.
Change default names of performance measures in ``segmetrics.study.Study.add_measure()``.

Adds ``segmetrics.measure.Measure.default_name()`` method.
Add ``segmetrics.measure.Measure.default_name()`` method.

1.2.1
-----

Adds quantile-based implementation of ``segmetrics.boundary.Hausdorff``.
Add quantile-based implementation of ``segmetrics.boundary.Hausdorff``.

1.2.2
-----

Positional and keyword arguments passed to ``segmetrics.boundary.DistanceMeasure.object_based`` are passed through to ``ObjectBasedDistanceMeasure``.
Pass positional and keyword arguments for ``segmetrics.boundary.DistanceMeasure.object_based`` through to ``ObjectBasedDistanceMeasure``.

1.2.3
-----

Adds ``--semicolon`` CLI option.
Add ``--semicolon`` CLI option.

1.3
---

Adds the ``aggregation`` keyword argument and member variable of the ``segmetrics.measure.Measure`` base class.
Add the ``aggregation`` keyword argument and member variable of the ``segmetrics.measure.Measure`` base class.

Removes the ``accumulative`` keyword argument and member variable of the ``segmetrics.measure.Measure`` base class.
Remove the ``accumulative`` keyword argument and member variable of the ``segmetrics.measure.Measure`` base class.

Removes the ``FRACTIONAL`` class variable of the ``segmetrics.measure.Measure`` base class.
Remove the ``FRACTIONAL`` class variable of the ``segmetrics.measure.Measure`` base class.

The method ``add_measure``` of the ``segmetrics.study.Study`` class now returns the name of the measure.

1.4
---

Changes default name of ``segmetrics.regional.ISBIScore`` if ``min_ref_size`` is not the default.
Change default name of ``segmetrics.regional.ISBIScore`` if ``min_ref_size`` is not the default.

Changes default name of ``segmetrics.boundary.ObjectBasedDistanceMeasure`` if ``skip_fn`` is not the default.
Change default name of ``segmetrics.boundary.ObjectBasedDistanceMeasure`` if ``skip_fn`` is not the default.

1.5
---

Rename ``segmetrics.boundary`` to ``segmetrics.contour``.

Move ``segmetrics.detection.COCOmAP`` to ``segmetrics.deprecated.COCOmAP``.

Minimum supported Python version is now 3.8 due to type linting.

Replace the ``ObjectBasedDistanceMeasure`` class by the more general ``segmetrics.measure.ObjectMeasureAdapter`` class.

Add ``.object_based()`` method for all image-level measures (including region-based measures).
The method does not accept positional arguments any more, only keyword arguments.

Remove the argument and attribute ``mode`` from the Hausdorff distance.

Add ``.reversed()`` and ``.symmetric()`` methods for all asymmetric measures (e.g., object-based).

Add ``geometric-mean`` aggregation method.

Rename aggregation method ``obj-mean`` to ``object-mean``.
7 changes: 0 additions & 7 deletions docs/source/segmetrics.boundary.rst

This file was deleted.

7 changes: 7 additions & 0 deletions docs/source/segmetrics.contour.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
segmetrics.contour
==================

.. automodule:: segmetrics.contour
:members:
:undoc-members:
:show-inheritance:
2 changes: 1 addition & 1 deletion docs/source/segmetrics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ segmetrics API
segmetrics.study
segmetrics.measure
segmetrics.regional
segmetrics.boundary
segmetrics.contour
segmetrics.detection
segmetrics.parallel
6 changes: 3 additions & 3 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ Region-based performance measures:
Contour-based performance measures:
- :class:`segmetrics.boundary.Hausdorff`
- :class:`segmetrics.boundary.NSD`
- :class:`segmetrics.contour.Hausdorff`
- :class:`segmetrics.contour.NSD`
Detection-based performance measures:
Expand All @@ -71,7 +71,7 @@ The choice of suitable performance measaures for evaluation should depend on the
One of the most widely used performance measures is the :py:class:`~segmetrics.regional.Dice` score. This is sensitive to false-positive detections, but invariant to falsely split/merged objects. On the other hand, :py:class:`~segmetrics.regional.ISBIScore` is sensitive to falsely split/merged but invariant to false-positive detections. Thus, using :py:class:`~segmetrics.regional.Dice` in combination with :py:class:`~segmetrics.regional.ISBIScore` well reflects the overall segmentation performance from a region-based point of view.
The :py:class:`~segmetrics.boundary.Hausdorff` distance is very sensitive to outliers (e.g., few objects which yield very high distance values). This high sensitivity is required in some applications (e.g., medical), but it can also cause misleading results in other applications (e.g., cell segmentation). In the latter case, one solution is to use the object-based variant instead (see :ref:`object-based-distance-measures`), which means that such outliers will be averaged out. Another, more simple solution, is to use the quantile-based variant of the :py:class:`~segmetrics.boundary.Hausdorff` distance, which cuts off the outliers based on a carefully chosen quantile value. Suitable choices for the quantile should be between ``0.9`` and ``0.99``, and should be chosen equal for all methods within a comparison. The :py:class:`~segmetrics.boundary.NSD` measure does not suffer from outliers. Using the quantile-based variant of the :py:class:`~segmetrics.boundary.Hausdorff` distance in combination with :py:class:`~segmetrics.boundary.NSD` thus well reflects the overall segmentation performance from a contour-based point of view.
The :py:class:`~segmetrics.contour.Hausdorff` distance is very sensitive to outliers (e.g., few objects which yield very high distance values). This high sensitivity is required in some applications (e.g., medical), but it can also cause misleading results in other applications (e.g., cell segmentation). In the latter case, one solution is to use the object-based variant instead (see :ref:`object-based-distance-measures`), which means that such outliers will be averaged out. Another, more simple solution, is to use the quantile-based variant of the :py:class:`~segmetrics.contour.Hausdorff` distance, which cuts off the outliers based on a carefully chosen quantile value. Suitable choices for the quantile should be between ``0.9`` and ``0.99``, and should be chosen equal for all methods within a comparison. The :py:class:`~segmetrics.contour.NSD` measure does not suffer from outliers. Using the quantile-based variant of the :py:class:`~segmetrics.contour.Hausdorff` distance in combination with :py:class:`~segmetrics.contour.NSD` thus well reflects the overall segmentation performance from a contour-based point of view.
Including the :py:class:`~segmetrics.detection.FalseSplit` and :py:class:`~segmetrics.detection.FalseMerge` measures is always useful in applications where a main challenge is the separation of the individual objects (e.g., cluster splitting in cell segmentation).
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
numpy>=1.18
numpy>=1.20
scipy
scikit-image>=0.18
scikit-learn
dill
Deprecated==1.2
36 changes: 26 additions & 10 deletions segmetrics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
from segmetrics.boundary import Hausdorff, NSD
from segmetrics.regional import Dice, JaccardCoefficient, JaccardIndex, RandIndex, AdjustedRandIndex, ISBIScore
from segmetrics.detection import FalsePositive, FalseNegative, FalseSplit, FalseMerge
from segmetrics.study import Study

import segmetrics.parallel

from segmetrics.contour import (
NSD,
Hausdorff,
)
from segmetrics.detection import (
FalseMerge,
FalseNegative,
FalsePositive,
FalseSplit,
)
from segmetrics.regional import (
AdjustedRandIndex,
Dice,
ISBIScore,
JaccardCoefficient,
JaccardIndex,
RandIndex,
)
from segmetrics.study import Study

VERSION_MAJOR = 1
VERSION_MINOR = 4
VERSION_PATCH = 1

VERSION = '%d.%d%s' % (VERSION_MAJOR, VERSION_MINOR, '.%d' % VERSION_PATCH if VERSION_PATCH > 0 else '')
VERSION_MINOR = 5
VERSION_PATCH = 0

VERSION = '%d.%d%s' % (
VERSION_MAJOR,
VERSION_MINOR,
'.%d' % VERSION_PATCH if VERSION_PATCH > 0 else '',
)
8 changes: 4 additions & 4 deletions segmetrics/_aux.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

def bbox(*masks, margin=0):
assert len(masks) > 0
assert len(masks) == 1 or all(masks[0].shape == mask.shape for mask in masks[1:])
mask_shape = masks[0].shape
assert len(masks) == 1 or all(
masks[0].shape == mask.shape for mask in masks[1:]
)
_rmin, _rmax = np.inf, -np.inf
_cmin, _cmax = np.inf, -np.inf
for mask in masks:
Expand All @@ -20,6 +21,5 @@ def bbox(*masks, margin=0):
_cmax += margin
_rmin, _rmax = max((_rmin, 0)), min((_rmax, mask.shape[0] - 1))
_cmin, _cmax = max((_cmin, 0)), min((_cmax, mask.shape[1] - 1))
sel = np.s_[_rmin : _rmax + 1, _cmin : _cmax + 1]
sel = np.s_[_rmin:_rmax + 1, _cmin:_cmax + 1]
return sel, (_rmin, _rmax), (_cmin, _cmax)

Loading

0 comments on commit 1f34b61

Please sign in to comment.