vessel_classifier#
Iterative artery/vein classification on a reduced vascular graph.
The algorithm has four phases:
Score — each edge gets a continuous artery score and vein score in [0, 1] based on radius, marker intensity, and binary mask.
Seed — high-confidence edges are assigned initial labels (artery, vein, or capillary).
Propagate — labels spread outward from seeds along the graph. Artery and vein labels propagate simultaneously and compete for ambiguous edges. Propagation uses a decaying score threshold.
Cleanup — remove small connected components (fragments).
All thresholds are collected in ClassificationConfig.
See also
VesselGraphProcessorOrchestrator that builds the graph and calls this classifier.
- class ClassificationConfig(vein_intensity_range: tuple[float, float], restrictive_vein_radius: float, permissive_vein_radius: float, final_vein_radius: float, arteries_min_noise_edges: int, artery_intensity_min: float, artery_trace_radius: float, vein_trace_radius: float, vein_intensity_min: float, distance_to_surface_min: float, max_artery_trace_iter: int, max_vein_trace_iter: int, artery_seed_threshold: float = 0.7, vein_seed_threshold: float = 0.6, min_artery_component_edges: int = 30, min_vein_component_edges: int = 30)[source]#
Bases:
objectAll thresholds for vessel classification.
Radius thresholds are unit-agnostic: they match whatever units
VesselSignals.radiiuses (µm for current graphs, voxels for legacy).The
from_configfactory resolves the correct source.- vein_intensity_range#
(low, high) intensity range on the artery channel that characterises veins. Edges within this range AND with large radius are classified as restrictive veins.
- Type:
tuple[float, float]
- restrictive_vein_radius#
Minimum radius for an edge to qualify as a restrictive (high-confidence) vein.
- Type:
float
- arteries_min_noise_edges#
Minimum number of connected artery edges to survive initial noise removal (step 1).
- Type:
int
- artery_intensity_min#
Minimum artery marker intensity for tracing to continue.
- Type:
float
- artery_trace_radius#
Minimum edge radius to continue artery tracing.
- Type:
float
- vein_trace_radius#
Minimum edge radius to continue vein tracing.
- Type:
float
- vein_intensity_min#
Minimum vein marker intensity to continue vein tracing. Only used when a dedicated vein channel exists.
- Type:
float
- distance_to_surface_min#
Minimum distance to brain surface (atlas voxels) for tracing to continue.
- Type:
float
- max_artery_trace_iter#
Maximum hysteresis iterations for artery tracing.
- Type:
int
- max_vein_trace_iter#
Maximum hysteresis iterations for vein tracing.
- Type:
int
- min_artery_component_edges#
Minimum edges in a connected artery component to survive final cleanup (step 7).
- Type:
int
- min_vein_component_edges#
Minimum edges in a connected vein component to survive final cleanup (step 7).
- Type:
int
- classmethod from_config(cfg: dict, legacy_thresholds: dict = None, use_legacy: bool = False) ClassificationConfig[source]#
Build from the
vessel_type_postprocessingconfig subtree.- Parameters:
cfg (dict) – The
vessel_type_postprocessingconfig subtree.legacy_thresholds (dict or None) –
VesselGraphProcessor._LEGACY_THRESHOLDSdict. Required whenuse_legacy=True.use_legacy (bool) – If True, read voxel-space thresholds from
legacy_thresholdsinstead of µm values from config.
- arteries_min_noise_edges: int#
- artery_intensity_min: float#
- artery_seed_threshold: float = 0.7#
- artery_trace_radius: float#
- distance_to_surface_min: float#
- final_vein_radius: float#
- property initial_threshold: float#
Starting score threshold for propagation.
- max_artery_trace_iter: int#
- property max_propagation_iter: int#
Total propagation budget derived from existing tracing iterations.
- max_vein_trace_iter: int#
- min_artery_component_edges: int = 30#
- property min_component_edges: dict[VesselType, int]#
Per-type minimum component sizes for cleanup.
- min_vein_component_edges: int = 30#
- permissive_vein_radius: float#
- property propagation_floor: float#
Score floor — propagation never accepts below this.
- restrictive_vein_radius: float#
- property seed_thresholds: dict[VesselType, float]#
Per-type seed thresholds.
- property threshold_decay: float#
Per-iteration decay. Reaches floor at last iteration.
- vein_intensity_min: float#
- vein_intensity_range: tuple[float, float]#
- vein_seed_threshold: float = 0.6#
- vein_trace_radius: float#
- class ClassificationMetrics(n_edges: int = 0, counts: dict = None, fractions: dict = None, seed_counts: dict = None, propagation_iterations: int = 0, propagated_counts: dict = None, n_seed_conflicts: int = 0, n_direct_contacts: int = 0, fragments_removed: dict = None, score_stats: dict = None)[source]#
Bases:
objectDiagnostic metrics produced after classification.
Intended for logging, QA dashboards, and sanity checks.
- record_final_counts(labels: ndarray, scores: dict[VesselType, ndarray]) None[source]#
Compute final distribution, propagated counts, and score statistics.
- counts: dict = None#
- fractions: dict = None#
- fragments_removed: dict = None#
- n_direct_contacts: int = 0#
- n_edges: int = 0#
- n_seed_conflicts: int = 0#
- propagated_counts: dict = None#
- propagation_iterations: int = 0#
- property sanity_warnings: list[str]#
Return a list of human-readable warnings if metrics look suspicious.
- score_stats: dict = None#
- seed_counts: dict = None#
- class VesselClassifier(graph: Graph, config: ClassificationConfig, signals: VesselSignals)[source]#
Bases:
objectScore-then-propagate vessel classifier for reduced vascular graphs.
Usage#
signals = VesselSignals(...) cfg = ClassificationConfig.from_config(config_dict) vc = VesselClassifier(graph, cfg, signals) metrics = vc.classify() print(metrics.summary())
- param graph:
The annotated, reduced graph. Modified in place.
- type graph:
Graph
- param config:
All classification thresholds.
- type config:
ClassificationConfig
- param signals:
Pre-collected per-edge signal arrays.
- type signals:
VesselSignals
- classify() ClassificationMetrics[source]#
Run the full classification pipeline: score → seed → propagate → cleanup.
After this call the graph has two boolean edge properties:
'artery'— True for edges classified as artery'vein'— True for edges classified as vein
Edges that are neither artery nor vein are implicitly capillaries.
Returns
- ClassificationMetrics
Diagnostic metrics and sanity check results.
- class VesselSignals(radii: ndarray, artery_binary: ndarray | None = None, artery_intensity: ndarray | None = None, vein_binary: ndarray | None = None, vein_intensity: ndarray | None = None, distance_to_surface: ndarray | None = None)[source]#
Bases:
objectAll per-edge arrays needed by the classifier.
radiiand allClassificationConfigradius thresholds are guaranteed to be in the same units. The caller resolves units before constructing this object.Fields are
Nonewhen the corresponding channel does not exist.- artery_binary: ndarray | None = None#
- artery_intensity: ndarray | None = None#
- distance_to_surface: ndarray | None = None#
- radii: ndarray#
- vein_binary: ndarray | None = None#
- vein_intensity: ndarray | None = None#
- class VesselType(value)[source]#
Bases:
IntEnumEdge classification labels for vessel type assignment.
IntEnum so labels can be used directly as numpy array values and in boolean comparisons without casting.
- classmethod competing_labels() tuple[VesselType, ...][source]#
The two vessel types that compete during propagation.
- competitor() VesselType[source]#
Return the competing vessel type.
- ARTERY = 1#
- CAPILLARY = 3#
- UNLABELLED = 0#
- VEIN = 2#