Skip to content

modosaic.segmentation.validators.impl.boundary_rgb_edge_overlap

modosaic.segmentation.validators.impl.boundary_rgb_edge_overlap

SegRgbEdgeOverlapValidator

SegRgbEdgeOverlapValidator(boundary_thickness=1, tolerance_radius=2, rgb_edge_quantile=0.9)

Bases: SegmentationValidator[BoundaryAlignmentStats]

Compare segmentation boundaries with RGB image edges.

Initialize the validator.

Parameters:

Name Type Description Default
boundary_thickness int

Mask boundary thickness in pixels.

1
tolerance_radius int

Pixel tolerance used for precision and recall.

2
rgb_edge_quantile float

Quantile threshold for RGB edge detection.

0.9
Source code in modosaic/segmentation/validators/impl/boundary_rgb_edge_overlap.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def __init__(
        self,
        boundary_thickness: int = 1,
        tolerance_radius: int = 2,
        rgb_edge_quantile: float = 0.90,
) -> None:
    """Initialize the validator.

    Args:
        boundary_thickness: Mask boundary thickness in pixels.
        tolerance_radius: Pixel tolerance used for precision and recall.
        rgb_edge_quantile: Quantile threshold for RGB edge detection.
    """
    self.boundary_thickness = boundary_thickness
    self.tolerance_radius = tolerance_radius
    self.rgb_edge_quantile = rgb_edge_quantile

validate

validate(record, generated)

Compute RGB-edge alignment for generated segmentation masks.

Source code in modosaic/segmentation/validators/impl/boundary_rgb_edge_overlap.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@override
def validate(self, record: ImageRecord, generated: list[np.ndarray]) -> BoundaryAlignmentStats:
    """Compute RGB-edge alignment for generated segmentation masks."""
    logger.debug(
        f"Computing RGB edge overlap for record sample {record.sample_id} with {len(generated)} masks"
    )
    pil = ImageService.bytes_to_pil(record.image_bytes)
    rgb = np.array(pil, dtype=np.uint8)  # HxWx3 RGB

    boundary = BoundaryService.masks_to_boundary(generated, expected_shape=(rgb.shape[0], rgb.shape[1]),
                                                 thickness=self.boundary_thickness)
    if not np.any(boundary):
        logger.debug(f"No segmentation boundary found for record sample {record.sample_id}")
        return BoundaryAlignmentStats()

    edges = EdgeService.rgb_edge_map(rgb, q=self.rgb_edge_quantile)

    stats = ToleranceService.compute_boundary_alignment_stats(
        edge_map=edges,
        boundary_map=boundary,
        tolerance_radius=self.tolerance_radius,
    )
    logger.debug(f"Computed RGB edge overlap for record sample {record.sample_id}")
    return stats