Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the code basis #11

Merged
merged 16 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[flake8]

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

per-file-ignores =
segmetrics/__init__.py:F401
32 changes: 27 additions & 5 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,39 @@ on:
branches:
- master


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


jobs:

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

- name: Run isort
shell: bash
run: isort segmetrics --check-only

run_testsuite:

name: Test suite

runs-on: ubuntu-latest

strategy:
Expand Down Expand Up @@ -76,4 +95,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"
4 changes: 4 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[settings]

multi_line_output = 3
force_grid_wrap = 2
4 changes: 4 additions & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ Changes default name of ``segmetrics.regional.ISBIScore`` if ``min_ref_size`` is

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

1.5
---

Rename ``segmetrics.boundary`` to ``segmetrics.contour``.
6 changes: 3 additions & 3 deletions docs/source/segmetrics.boundary.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
segmetrics.boundary
===================
segmetrics.contour
==================

.. automodule:: segmetrics.boundary
.. 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
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ 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)

201 changes: 0 additions & 201 deletions segmetrics/boundary.py

This file was deleted.

Loading