neu_eval.assign¶
Matching one side’s labels to the other’s, and the completeness metrics that follow.
Pure functions of a Contingency, in two families:
Matching: which segment is which body, one-to-one, as Plaza & Funke’s connectivity metrics require (otherwise a segmentation can claim one body twice). Greedy by default; the optimal assignment is opt-in, being the only non-linear cost in the package.
Completeness: how many segments account for a share of the volume.
fragmentationestimates how many merges a proofreader would need;coveringis the size-weighted share of each body captured by its best segment.
fragmentation is positive when side b has more labels (over-segmentation); that is
the only asymmetry, and c.T reverses it.
Attributes¶
Classes¶
How many segments account for a given share of each side. |
|
A one-to-one assignment between the two sides. |
Functions¶
|
A one-to-one assignment between the two sides of |
|
The smallest set of labels on each side covering |
|
Size-weighted mean, over side |
|
|
|
Intersection over union for each pair in |
|
Matching and completeness as one flat row, to merge with |
Module Contents¶
- class neu_eval.assign.Completeness¶
How many segments account for a given share of each side.
fragmentationisn_b_kept - n_a_kept, the extra segments a proofreader would merge to recover the kept reference bodies. An estimate, not a true edit distance: it assumesbover-segmentsa.- as_dict() dict[str, float | int]¶
- a_ids: numpy.ndarray¶
- at: float¶
- b_ids: numpy.ndarray¶
- property fragmentation: int¶
- n_a_kept: int¶
- n_b_kept: int¶
- class neu_eval.assign.Match¶
A one-to-one assignment between the two sides.
a_to_bandb_to_aare inverse mappings over matched labels; any other label is unmatched.methodis recorded because greedy and optimal results are not comparable.- unmatched_a(c: neu_eval.overlap.Contingency) list[int]¶
- unmatched_b(c: neu_eval.overlap.Contingency) list[int]¶
- a_to_b: dict[int, int]¶
- b_to_a: dict[int, int]¶
- method: str = 'greedy'¶
- min_iou: float = 0.0¶
- property n_matched: int¶
- neu_eval.assign.best_match(c: neu_eval.overlap.Contingency, *, method: str = 'greedy', min_iou: float = 0.0, by: str = 'iou') Match¶
A one-to-one assignment between the two sides of
c.method="greedy"repeatedly takes the best remaining pair, O(pairs log pairs), for volume scale.method="hungarian"maximises the total instead; it densifies the table, so it is capped atHUNGARIAN_MAX_LABELSper side.byis"iou"(default) or"overlap"(raw voxels); they differ when a large segment overlaps a small body.min_ioudrops pairs below it: 0 admits any co-occurring pair, and 0.5 is the usual choice for calling a body “found” (above 0.5 a label can have only one admissible partner).
- neu_eval.assign.completeness(c: neu_eval.overlap.Contingency, at: float = 0.9) Completeness¶
The smallest set of labels on each side covering
atof that side’s voxels.“How many segments reconstruct 90% of this volume” is a question a proofreading plan can act on, where a raw label count is dominated by specks. The sides are thresholded independently, not paired.
- neu_eval.assign.covering(c: neu_eval.overlap.Contingency) float¶
Size-weighted mean, over side
a’s labels, of the best singleboverlap.The IoU of each
abody’s bestbsegment, weighted by body size; 1.0 when every body is captured exactly. Unlike VOI it is a bounded fraction, but it ignores the rest of the best segment, so it misses a merge that leaves the body itself intact.
- neu_eval.assign.fragmentation(c: neu_eval.overlap.Contingency) int¶
n_b - n_aover the scored region: extra segments, as an edit-distance estimate.
- neu_eval.assign.iou(c: neu_eval.overlap.Contingency) numpy.ndarray¶
Intersection over union for each pair in
c, parallel to its arrays.|a ∩ b| / (|a| + |b| - |a ∩ b|), with each label’s total taken over the scored region, so a body clipped by the crop is not penalised for the part outside it.
- neu_eval.assign.summary(c: neu_eval.overlap.Contingency, *, at: tuple[float, ...] = (0.5, 0.9)) dict[str, float | int]¶
Matching and completeness as one flat row, to merge with
voxel.summary().
- neu_eval.assign.HUNGARIAN_MAX_LABELS = 5000¶