@@ -1547,7 +1547,7 @@ Important differences from vigra and fastfilters:
15471547 largest → smallest. This matches ` fastfilters ` . To get vigra's
15481548 ascending order, reverse with ` result[..., ::-1] ` .
15491549- No IIR / recursive Gaussian, no ` convolve ` / ` recursiveFilter2D ` , no
1550- morphology, no distance transforms, no nonlinear diffusion, and no
1550+ morphology, no nonlinear diffusion, and no
15511551 non-local means in v1. Use ` scipy.ndimage ` , ` skimage ` , or the original
15521552 vigra/fastfilters bindings if you need those.
15531553
@@ -1562,6 +1562,81 @@ Implementation notes:
15621562 ` detail/threading.hxx::parallel_for_chunks ` without changing the
15631563 public API.
15641564
1565+ ### Distance Transforms
1566+
1567+ ` bioimage-cpp ` exposes exact binary Euclidean distance transforms under
1568+ ` bic.distance ` . The implementation uses the separable
1569+ Felzenszwalb–Huttenlocher algorithm, complexity O(N · ndim), with optional
1570+ multithreading across the orthogonal lines of each axis sweep.
1571+
1572+ SciPy / vigra:
1573+
1574+ ``` python
1575+ from scipy import ndimage
1576+ dist = ndimage.distance_transform_edt(mask, sampling = (2.0 , 1.0 ))
1577+
1578+ import vigra.filters as vf
1579+ vec = vf.vectorDistanceTransform(mask)
1580+ ```
1581+
1582+ bioimage-cpp:
1583+
1584+ ``` python
1585+ import bioimage_cpp as bic
1586+
1587+ # One call can return any combination of distances, feature indices, and
1588+ # difference vectors — the C++ kernel computes them in a single sweep.
1589+ dist = bic.distance.distance_transform(mask, sampling = (2.0 , 1.0 ))
1590+ dist, idx, vec = bic.distance.distance_transform(
1591+ mask,
1592+ sampling = (2.0 , 1.0 ),
1593+ return_distances = True ,
1594+ return_indices = True ,
1595+ return_vectors = True ,
1596+ )
1597+
1598+ # Short alias kept for parity with vigra; equivalent to the call above with
1599+ # return_distances=False, return_indices=False, return_vectors=True.
1600+ vec = bic.distance.vector_difference_transform(mask, sampling = (2.0 , 1.0 ))
1601+ ```
1602+
1603+ Name mapping:
1604+
1605+ | scipy / vigra name | bioimage-cpp name |
1606+ | --- | --- |
1607+ | ` scipy.ndimage.distance_transform_edt ` | ` distance_transform ` |
1608+ | ` vigra.filters.vectorDistanceTransform ` | ` vector_difference_transform ` |
1609+
1610+ Important differences:
1611+
1612+ - Distance-valued outputs are ` float32 ` , not SciPy's ` float64 ` . Indices are
1613+ ` int32 ` with shape ` (ndim, *mask.shape) ` (matches SciPy's layout). Vectors
1614+ are ` float32 ` with shape ` (*mask.shape, ndim) ` ; components are sampled
1615+ displacements ` (feature_coord - pixel_coord) * sampling[ax] ` per axis.
1616+ - ` distance_transform ` follows SciPy's binary convention: nonzero values are
1617+ foreground and distances are measured to the nearest zero-valued element.
1618+ ` bool ` and ` uint8 ` C-contiguous inputs are fast-pathed without a copy;
1619+ other dtypes are converted via ` array != 0 ` .
1620+ - A single ` distance_transform ` call can return any non-empty subset of
1621+ ` distances ` , ` indices ` , and ` vectors ` via the corresponding
1622+ ` return_distances ` / ` return_indices ` / ` return_vectors ` flags. The result
1623+ is the array itself when only one output is requested, otherwise a tuple
1624+ in ` (distances, indices, vectors) ` order with omitted entries skipped.
1625+ - Pre-allocated output buffers are supported via the ` distances= ` ,
1626+ ` indices= ` , and ` vectors= ` keyword arguments. They must be C-contiguous,
1627+ writable, of the documented shape and dtype, and are written into in
1628+ place. Pre-allocated outputs are excluded from the return value (matching
1629+ SciPy's convention); the call returns ` None ` if every requested output
1630+ was preallocated.
1631+ - ` number_of_threads ` selects the thread count for the per-axis sweep.
1632+ ` 1 ` (the default) is single-threaded; ` 0 ` uses
1633+ ` std::thread::hardware_concurrency() ` ; positive values pin an explicit
1634+ count. Output is deterministic and bitwise identical across thread counts.
1635+ - For an all-foreground input (no zero-valued elements), the result matches
1636+ SciPy: distances and indices report a virtual background point at
1637+ axis-0 coordinate ` -1 ` and ` 0 ` on all other axes. The first row of
1638+ ` indices ` will then contain ` -1 ` everywhere.
1639+
15651640## I/O and Build Dependencies
15661641
15671642` bioimage-cpp ` intentionally does not replace nifty or affogato I/O helpers.
0 commit comments