Skip to content

Commit

Permalink
Bump version to 06 (#112)
Browse files Browse the repository at this point in the history
Bump version to 06
  • Loading branch information
constantinpape authored Jan 1, 2025
1 parent dac6a91 commit 158c675
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/build_docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- "elf/**/*.py" # Trigger on any changes in python files.
branches:
- master # Run the workflow only on pushes to the main branch
- bump-version
workflow_dispatch:

# security: restrict permissions for CI jobs.
Expand Down Expand Up @@ -34,6 +35,10 @@ jobs:
shell: bash -l {0}
run: pip install -e .

- name: Install napari
shell: bash -l {0}
run: pip install napari

- name: Install pdoc
shell: bash -l {0}
run: pip install pdoc
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# elf

This repository implements common functionality for (large-scale) bio-medical image analysis:
This repository implements common functionality for biomedical image analysis:
- **evaluation**: evaluation of partitions via rand index and variation of information
- **io**: common interface for different libraries / formats
- **parallel**: parallel / larger than memory implementation of common numpy functions
Expand All @@ -13,7 +13,7 @@ This repository implements common functionality for (large-scale) bio-medical im
- **wrapper**: volume wrappers for on-the-fly transformations
- **tracking**: graph based tracking algorithms

and more.
and more. See [the documentation]() for how to use elf.

See `examples` for some usage examples. For processing large data on a cluster, check out [cluster_tools](https://github.com/constantinpape/cluster_tools), which uses a lot of `elf` functionality internally.

Expand Down
2 changes: 1 addition & 1 deletion elf/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.5.2"
__version__ = "0.6.0"
15 changes: 11 additions & 4 deletions elf/tracking/motile_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
from copy import deepcopy
from typing import Dict, List, Optional, Tuple, Union

import motile
import networkx as nx
import numpy as np

from motile import costs, constraints
try:
import motile
from motile import costs, constraints
except ImportError:
motile, costs, constraints = None, None, None

from nifty.tools import takeDict
from skimage.measure import regionprops

Expand Down Expand Up @@ -126,14 +130,14 @@ def create_data_for_track_layer(segmentation, lineage_graph, node_to_track, skip
#


# TODO expose the relevant weights and constants!
# We could expose further relevant weights and constants.
def construct_problem(
segmentation: np.ndarray,
node_costs: np.ndarray,
edges_and_costs: List[Dict[str, Union[int, float]]],
max_parents: int = 1,
max_children: int = 2,
) -> Tuple[motile.solver.Solver, motile.track_graph.TrackGraph]:
) -> Tuple["motile.solver.Solver", "motile.track_graph.TrackGraph"]:
"""Construct a motile tracking problem from a segmentation timeseries.
Args:
Expand Down Expand Up @@ -255,6 +259,9 @@ def track_with_motile(
The track graph, a directed graph that connects segmentation ids across time points.
Map of track ids to segmentation ids.
"""
if motile is None:
raise RuntimeError("You have to install motile to use track_with_motile")

solver, graph, segmentation = _track_with_motile_impl(
segmentation, relabel_segmentation, node_cost_function, edge_cost_function,
node_selection_cost, **problem_kwargs,
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _check_labeling(self, data, res):
# napari.run()

vis, vim = variation_of_information(exp, res)
self.assertAlmostEqual(vis + vim, 0)
self.assertAlmostEqual(vis + vim, 0, places=4)

def test_label(self):
from elf.parallel import label
Expand Down Expand Up @@ -94,7 +94,7 @@ def test_label_with_roi_2d(self):
expected = np.zeros_like(res)
expected[roi] = label_reference(data[roi])
vis, vim = variation_of_information(expected, res)
self.assertAlmostEqual(vis + vim, 0)
self.assertAlmostEqual(vis + vim, 0, places=4)

def test_label_with_roi_3d(self):
from elf.parallel import label
Expand Down
27 changes: 17 additions & 10 deletions test/segmentation/test_stitching.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ def get_tiled_data(self, tile_shape, size=1024, ndim=2):

return labels, original_data # returns the stitched labels and original labels

def _check_result(self, segmentation, expected_segmentation, rtol=1e-2, atol=1e-2):
self.assertEqual(segmentation.shape, expected_segmentation.shape)

# We remove small segments before evaluation, since these may get stitched wrongly.
ids, sizes = np.unique(segmentation, return_counts=True)
filter_ids = ids[sizes < 250]
mask = np.isin(segmentation, filter_ids)
segmentation[mask] = 0
expected_segmentation[mask] = 0

# We allow for some tolerance, because small objects might get stitched incorrectly.
are, _ = rand_index(segmentation, expected_segmentation)
self.assertTrue(np.isclose(are, 0, rtol=rtol, atol=atol))

def test_stitch_segmentation(self):
from elf.segmentation.stitching import stitch_segmentation

Expand All @@ -54,10 +68,7 @@ def _segment(input_, block_id=None):
data = self.get_data()
expected_segmentation = _segment(data)
segmentation = stitch_segmentation(data, _segment, tile_shape, tile_overlap, verbose=False)

are, _ = rand_index(segmentation, expected_segmentation)
# We allow for some tolerance, because small objects might get stitched incorrectly.
self.assertTrue(np.isclose(are, 0, rtol=1e-3, atol=1e-3))
self._check_result(segmentation, expected_segmentation)

def test_stitch_segmentation_3d(self):
from elf.segmentation.stitching import stitch_segmentation
Expand All @@ -72,8 +83,7 @@ def _segment(input_, block_id=None):
data = self.get_data(256, ndim=3)
expected_segmentation = _segment(data)
segmentation = stitch_segmentation(data, _segment, tile_shape, tile_overlap, verbose=False)
are, _ = rand_index(segmentation, expected_segmentation)
self.assertTrue(np.isclose(are, 0, rtol=1e-2, atol=1e-2))
self._check_result(segmentation, expected_segmentation, rtol=0.1, atol=0.1)

def test_stitch_tiled_segmentation(self):
from elf.segmentation.stitching import stitch_tiled_segmentation
Expand All @@ -83,10 +93,7 @@ def test_stitch_tiled_segmentation(self):
# Get the tiled segmentation with unmerged instances at tile interfaces.
labels, original_labels = self.get_tiled_data(tile_shape=tile_shape, size=1000)
stitched_labels = stitch_tiled_segmentation(segmentation=labels, tile_shape=tile_shape, verbose=False)
self.assertEqual(labels.shape, stitched_labels.shape)

are, _ = rand_index(stitched_labels, original_labels)
self.assertTrue(np.isclose(are, 0, rtol=1e-3, atol=1e-3))
self._check_result(stitched_labels, original_labels)


if __name__ == "__main__":
Expand Down

0 comments on commit 158c675

Please sign in to comment.