moonbit-visual-debug

Visual algorithm debugging overlays and SVG/HTML report generation for MoonBit.

visual-debug
overlay
computer-vision
svg
report
moon add xlh123jjj/moonbit-visual-debug@0.2.1
Download zip
Author
Version
0.2.1
License
Apache-2.0
Last updated
4 hours ago
Downloads
4
README

#moonbit-visual-debug

Typed visual-debugging reports for MoonBit computer-vision and image-analysis workflows.

#Project Positioning

moonbit-visual-debug turns structured algorithm outputs into inspectable visual evidence. It models boxes, masks, keypoints, trajectories, heatmaps, error regions, and detection matches, then renders a deterministic SVG, self-contained HTML report, or PNG snapshot.

It is a library-first reporting layer, not a detector, segmenter, image decoder, or general SVG engine. The package is intended for CI artifacts, experiments, demos, and reviewable visual regression evidence.

#Core Capabilities

  • Image-space geometry, intersection, and IoU primitives.
  • Typed overlays for bounding boxes, polygon masks, keypoints, trajectories, heatmaps, and error regions.
  • SVG and standalone HTML reports with layer metadata.
  • Pure MoonBit RGBA canvas and deterministic PNG encoding.
  • Detection comparison with true-positive, false-positive, false-negative, and label-mismatch output.
  • COCO datasets/results plus YOLO and Pascal VOC box adapters.
  • Baseline-versus-candidate document diffs, per-class metrics, and machine-readable manifests.

#Quick Start

moon add xlh123jjj/moonbit-visual-debug

///|
test "build a visual inspection report" {
let layer = Layer::new(id="detections").add(
BBox(
rect=Rect::new(x=12.0, y=10.0, width=48.0, height=36.0),
label=Some(Label::new(text="part", score=0.91)),
color=Some(Color::rgb(r=39, g=125, b=255)),
),
)
let doc = DebugDocument::new(
title="inspection",
image=ImageSpec::new(width=96, height=64),
).add_layer(layer)
inspect(doc.overlay_count(), content="1")
inspect(doc.to_svg().contains("<svg"), content="true")
inspect(doc.to_html_report().contains("<table>"), content="true")
}

#CLI

moon run --target wasm-gc cmd/main > report.html

The command writes a self-contained HTML report to standard output. Open report.html in a browser, or attach it to a CI job as a review artifact.

#Dataset Interoperability

CocoDataset::from_json accepts a COCO object containing annotations, optional categories, and image metadata. It validates required IDs and [x, y, width, height] boxes, then resolves category names when producing Detection values. Scored prediction arrays are handled separately by CocoResults. Unknown category IDs remain usable through a stable category-<id> fallback label.

///|
test "load COCO annotations" {
let source =
#|{"categories":[{"id":1,"name":"part"}],
#|"annotations":[{"id":7,"image_id":1,"category_id":1,
#|"bbox":[10,12,20,16]}]}
match CocoDataset::from_json(source) {
Ok(dataset) => inspect(dataset.to_detections()[0].label, content="part")
Err(_) => fail("expected valid COCO data")
}
}

#Architecture

ComponentResponsibility
geometry.mbt, color.mbtValue types and deterministic presentation primitives.
overlay.mbt, transform.mbtOverlay document model, composition, transforms, and bounds.
svg.mbt, report.mbt, raster.mbtSVG, HTML, canvas, and PNG output backends.
analysis.mbt, validation.mbtDetection matching, error overlays, and input diagnostics.
dataset.mbt, adapter.mbtCOCO, YOLO, and Pascal VOC interchange.
diff.mbt, metrics.mbt, manifest.mbtCI-ready diffing, evaluation summaries, and stable exports.

#Benchmarks

visual_bench.mbt uses MoonBit's built-in benchmark runner. On the recorded Windows 11 native-release run, rendering 256 labelled overlays averaged 934.37 µs for SVG and 9.39 ms for PNG. See docs/benchmarks.md for the command, environment, and complete measurements.

Run the same benchmark locally with:

moon bench visual_bench.mbt --target native --release --deny-warn

#Testing

moon fmt --check moon check --target wasm-gc --deny-warn moon test --target wasm-gc --deny-warn moon check --target native --deny-warn moon test --target native --deny-warn moon info --target wasm-gc git diff --exit-code

The suite covers rendering, polygon rasterization, PNG block boundaries, COCO/YOLO/VOC interchange, malformed annotations, matching thresholds, report diffs, metrics, manifests, and diagnostic behavior.

#CI

GitHub Actions installs the current stable MoonBit toolchain, checks formatting and generated interfaces, runs warning-denied wasm-gc tests on Ubuntu, macOS, and Windows, and validates native builds, coverage, and benchmark compilation on Ubuntu.

#Scope

The package deliberately has no runtime dependency on an image library, model framework, dataset host, or browser. Polygon detail is retained in SVG and HTML, and the PNG backend uses deterministic even-odd polygon filling for masks.

#License

Apache-2.0. See LICENSE.

#
AdapterError

pub(all) enum AdapterError {
InvalidImageSize(message~ : String)
InvalidYolo(field~ : String, message~ : String)
InvalidYoloText(message~ : String)
MissingClassMapping(class_id~ : Int)
InvalidVoc(path~ : String, message~ : String)
} derive(ToJson,
Debug
)

Errors returned by the text-only YOLO and Pascal VOC annotation adapters.

#
Affine2D

pub(all) struct Affine2D {
sx : Double
sy : Double
tx : Double
ty : Double
} derive(ToJson,
Debug
)

#
Affine2D::apply_point

fn Affine2D::apply_point(self : Affine2D, point : Point) -> Point

#
Affine2D::apply_rect

fn Affine2D::apply_rect(self : Affine2D, rect : Rect) -> Rect

#
Affine2D::identity

fn Affine2D::identity() -> Affine2D

#
Affine2D::scale

fn Affine2D::scale(sx~ : Double, sy~ : Double) -> Affine2D

#
Affine2D::then

fn Affine2D::then(self : Affine2D, next : Affine2D) -> Affine2D

#
Affine2D::translate

fn Affine2D::translate(tx~ : Double, ty~ : Double) -> Affine2D

#
AggregateMetrics

pub(all) struct AggregateMetrics {
true_positive : Int
false_positive : Int
false_negative : Int
label_mismatch : Int
precision : Double
recall : Double
f1 : Double
} derive(ToJson,
Debug
)

Counts and derived scores for a single class or aggregate. Aggregate label_mismatch counts each mismatched match record once.

#
Canvas

pub(all) struct Canvas {
width : Int
height : Int
pixels : Array[Byte]
} derive(
Debug
)

#
Canvas::draw_point

fn Canvas::draw_point(self : Canvas, point : Point, color : Color, radius? : Int) -> Unit

#
Canvas::fill_polygon

fn Canvas::fill_polygon(self : Canvas, polygon : Array[Point], color : Color) -> Unit

Fills one polygon using even-odd containment evaluated at pixel centers.

An edge contributes only when a pixel center's horizontal ray crosses its half-open vertical range [min_y, max_y), so shared vertices and horizontal edges have deterministic coverage. Polygons with fewer than three points are ignored and all writes are clipped to the canvas.

#
Canvas::fill_polygons

fn Canvas::fill_polygons(self : Canvas, polygons : Array[Array[Point]], color : Color) -> Unit

Fills polygons with the even-odd rule, allowing nested polygons to form holes.

Pixels are evaluated at (x + 0.5, y + 0.5). The same half-open edge rule as fill_polygon makes boundary coverage reproducible regardless of edge order.

#
Canvas::fill_rect

fn Canvas::fill_rect(self : Canvas, rect : Rect, color : Color) -> Unit

#
Canvas::from_image_spec

fn Canvas::from_image_spec(image : ImageSpec, background? : Color) -> Canvas

#
Canvas::new

fn Canvas::new(width~ : Int, height~ : Int, background? : Color) -> Canvas

#
Canvas::set_pixel

fn Canvas::set_pixel(self : Canvas, x : Int, y : Int, color : Color) -> Unit

#
Canvas::stroke_rect

fn Canvas::stroke_rect(self : Canvas, rect : Rect, color : Color, width? : Int) -> Unit

#
Canvas::to_png

fn Canvas::to_png(self : Canvas) -> Bytes

#
ClassMetrics

pub(all) struct ClassMetrics {
label : String
true_positive : Int
false_positive : Int
false_negative : Int
label_mismatch : Int
support : Int
precision : Double
recall : Double
f1 : Double
} derive(ToJson,
Debug
)

Per-label metrics. support is the number of expected detections. A label mismatch contributes a false negative to its expected class and a false positive to its actual class, so it is visible in both affected class rows.

#
CocoAnnotation

pub(all) struct CocoAnnotation {
id : Int
image_id : Int
category_id : Int
bbox : Rect
area : Double?
iscrowd : Int?
} derive(ToJson,
Debug
)

One ground-truth bounding-box annotation in a COCO dataset. Scores belong in CocoResult records, not annotations.

#
CocoAnnotation::new

fn CocoAnnotation::new(id~ : Int, image_id~ : Int, category_id~ : Int, bbox~ : Rect, area? : Double, iscrowd? : Int) -> CocoAnnotation

Creates a COCO annotation. Omitted area is derived during export; supplied iscrowd must be 0 or 1.

#
CocoCategory

pub(all) struct CocoCategory {
id : Int
name : String
} derive(ToJson,
Debug
)

#
CocoCategory::new

fn CocoCategory::new(id~ : Int, name~ : String) -> CocoCategory

#
CocoDataset

pub(all) struct CocoDataset {
images : Array[CocoImage]
categories : Array[CocoCategory]
annotations : Array[CocoAnnotation]
} derive(ToJson,
Debug
)

A COCO ground-truth object with image, category, and annotation arrays. Legacy annotation-only objects without images remain accepted.

#
CocoDataset::from_json

fn CocoDataset::from_json(source : String) -> Result[CocoDataset, CocoError]

Parses a COCO ground-truth object. annotations is required; images and categories may be omitted only for legacy annotation-only input.

#
CocoDataset::new

fn CocoDataset::new(annotations~ : Array[CocoAnnotation], categories? : Array[CocoCategory], images? : Array[CocoImage]) -> CocoDataset

Creates a COCO dataset without validation for convenient literals. Prefer CocoDataset::try_new when constructed input can be invalid.

#
CocoDataset::to_coco_json

fn CocoDataset::to_coco_json(self : CocoDataset) -> Result[String, CocoError]

Serializes this ground-truth dataset as a standard COCO object.

#
CocoDataset::to_detections

fn CocoDataset::to_detections(self : CocoDataset) -> Array[Detection]

Converts ground-truth annotations into visual-debug detections.

#
CocoDataset::try_new

fn CocoDataset::try_new(annotations~ : Array[CocoAnnotation], categories? : Array[CocoCategory], images? : Array[CocoImage]) -> Result[CocoDataset, CocoError]

Creates and validates a COCO dataset, returning a field-specific error.

#
CocoDataset::validate

fn CocoDataset::validate(self : CocoDataset) -> Result[Unit, CocoError]

Validates COCO IDs, image dimensions, finite boxes, areas, crowd flags, and referential image IDs in linear time.

#
CocoError

pub(all) enum CocoError {
InvalidJson(message~ : String)
InvalidField(path~ : String, message~ : String)
} derive(ToJson,
Debug
)

#
CocoImage

pub(all) struct CocoImage {
id : Int
width : Int
height : Int
file_name : String?
} derive(ToJson,
Debug
)

Metadata for one image in a COCO dataset. file_name is optional because COCO image assets can be addressed outside the annotation file.

#
CocoImage::new

fn CocoImage::new(id~ : Int, width~ : Int, height~ : Int, file_name? : String) -> CocoImage

Creates a COCO image record. Use CocoDataset::try_new to validate it.

#
CocoResult

pub(all) struct CocoResult {
image_id : Int
category_id : Int
bbox : Rect
score : Double
} derive(ToJson,
Debug
)

One scored COCO detection result. Standard COCO result JSON is a root array of these records rather than a dataset annotations array.

#
CocoResult::new

fn CocoResult::new(image_id~ : Int, category_id~ : Int, bbox~ : Rect, score~ : Double) -> CocoResult

Creates a scored COCO result. Use CocoResults::try_new to validate it.

#
CocoResults

pub(all) struct CocoResults {
results : Array[CocoResult]
} derive(ToJson,
Debug
)

A root-array COCO prediction/result payload.

#
CocoResults::from_json

fn CocoResults::from_json(source : String) -> Result[CocoResults, CocoError]

Parses a standard root-array COCO result payload. Each object must contain image_id, category_id, bbox, and a finite score.

#
CocoResults::new

fn CocoResults::new(results~ : Array[CocoResult]) -> CocoResults

Creates COCO results without validation for convenient literals. Prefer CocoResults::try_new when constructed input can be invalid.

#
CocoResults::to_coco_json

fn CocoResults::to_coco_json(self : CocoResults) -> Result[String, CocoError]

Serializes these predictions as the standard root-array COCO result format.

#
CocoResults::try_new

fn CocoResults::try_new(results~ : Array[CocoResult]) -> Result[CocoResults, CocoError]

Creates and validates a COCO result payload, including finite scores.

#
CocoResults::validate

fn CocoResults::validate(self : CocoResults) -> Result[Unit, CocoError]

Validates every result ID, bounding box, and score in linear time.

#
Color

pub(all) struct Color {
r : Int
g : Int
b : Int
a : Double
} derive(ToJson,
Debug
)

#
Color::rgb

fn Color::rgb(r~ : Int, g~ : Int, b~ : Int) -> Color

#
Color::rgba

fn Color::rgba(r~ : Int, g~ : Int, b~ : Int, a~ : Double) -> Color

#
Color::to_css

fn Color::to_css(self : Color) -> String

#
Color::to_hex

fn Color::to_hex(self : Color) -> String

#
Color::with_alpha

fn Color::with_alpha(self : Color, alpha : Double) -> Color

#
ConfusionCell

pub(all) struct ConfusionCell {
expected_label : String?
actual_label : String?
count : Int
} derive(ToJson,
Debug
)

One non-zero, typed cell of a detection confusion matrix. None denotes an unmatched expected or actual detection.

#
ConfusionMatrix

pub(all) struct ConfusionMatrix {
labels : Array[String]
cells : Array[ConfusionCell]
} derive(ToJson,
Debug
)

A stable, sparse confusion matrix ordered by expected label then actual label.

#
DebugDocument

pub(all) struct DebugDocument {
title : String
image : ImageSpec
image_href : String?
layers : Array[Layer]
} derive(ToJson,
Debug
)

#
DebugDocument::add_layer

fn DebugDocument::add_layer(self : DebugDocument, layer : Layer) -> DebugDocument

#
DebugDocument::content_bounds

fn DebugDocument::content_bounds(self : DebugDocument) -> Rect?

#
DebugDocument::is_valid

fn DebugDocument::is_valid(self : DebugDocument) -> Bool

#
DebugDocument::manifest

Builds a report manifest without changing the document, its layers, or their overlay arrays. Layer entries preserve the document insertion order.

#
DebugDocument::new

fn DebugDocument::new(title~ : String, image~ : ImageSpec, image_href? : String) -> DebugDocument

#
DebugDocument::overlay_count

fn DebugDocument::overlay_count(self : DebugDocument) -> Int

#
DebugDocument::resize

fn DebugDocument::resize(self : DebugDocument, width~ : Int, height~ : Int) -> DebugDocument

#
DebugDocument::to_canvas

fn DebugDocument::to_canvas(self : DebugDocument, background? : Color) -> Canvas

#
DebugDocument::to_html_report

fn DebugDocument::to_html_report(self : DebugDocument) -> String

#
DebugDocument::to_html_report_with

fn DebugDocument::to_html_report_with(self : DebugDocument, options : ReportOptions) -> String

#
DebugDocument::to_png

fn DebugDocument::to_png(self : DebugDocument) -> Bytes

#
DebugDocument::to_svg

fn DebugDocument::to_svg(self : DebugDocument) -> String

#
DebugDocument::to_svg_with

fn DebugDocument::to_svg_with(self : DebugDocument, options : SvgOptions) -> String

#
DebugDocument::validate

fn DebugDocument::validate(self : DebugDocument) -> Array[Diagnostic]

#
DebugDocument::visible_layers

fn DebugDocument::visible_layers(self : DebugDocument) -> Array[Layer]

#
Detection

pub(all) struct Detection {
id : String
rect : Rect
label : String
score : Double
} derive(ToJson,
Debug
)

#
Detection::new

fn Detection::new(id~ : String, rect~ : Rect, label~ : String, score? : Double) -> Detection

#
DetectionMetrics

pub(all) struct DetectionMetrics {
iou_threshold : Double
score_threshold : Double
matches : MatchSummary
classes : Array[ClassMetrics]
confusion : ConfusionMatrix
micro : AggregateMetrics
macro_average : AggregateMetrics
} derive(ToJson,
Debug
)

A deterministic metrics report for one IoU and score threshold pair. Classes are the lexical union of expected and score-filtered actual labels. Macro scores average those class rows; precision, recall, and F1 use 0.0 whenever their denominator is zero.

#
DetectionMetrics::to_csv

fn DetectionMetrics::to_csv(self : DetectionMetrics) -> String

Renders stable LF-delimited CSV class metrics text for CI logs and artifacts.

#
DetectionMetrics::to_html_table

fn DetectionMetrics::to_html_table(self : DetectionMetrics) -> String

Renders a compact escaped HTML table suitable for CI artifacts.

#
Diagnostic

pub(all) struct Diagnostic {
level : DiagnosticLevel
path : String
message : String
} derive(ToJson,
Debug
)

#
Diagnostic::new

fn Diagnostic::new(level~ : DiagnosticLevel, path~ : String, message~ : String) -> Diagnostic

#
DiagnosticLevel

pub(all) enum DiagnosticLevel {
Info
Warning
Error
} derive(ToJson,
Debug
)

#
DiagnosticSeverityCounts

pub(all) struct DiagnosticSeverityCounts {
info : Int
warning : Int
error : Int
} derive(ToJson,
Debug
)

Counts diagnostics produced by document validation.

#
DocumentDiff

pub(all) struct DocumentDiff {
baseline_title : String
candidate_title : String
baseline_image : ImageSpec
candidate_image : ImageSpec
baseline_image_href : String?
candidate_image_href : String?
title_changed : Bool
image_size_changed : Bool
image_href_changed : Bool
overlay_count_delta : Int
layer_changes : Array[LayerChange]
} derive(ToJson,
Debug
)

Summarizes changes between two visual debugging documents.

#
DocumentDiff::to_html

fn DocumentDiff::to_html(self : DocumentDiff) -> String

Renders a deterministic, self-contained HTML summary of this diff.

#
DocumentManifest

pub(all) struct DocumentManifest {
title : String
image_width : Int
image_height : Int
layer_count : Int
visible_layer_count : Int
total_overlay_count : Int
visible_overlay_count : Int
overlays : OverlayKindCounts
visible_overlays : OverlayKindCounts
content_bounds : Rect?
diagnostics : DiagnosticSeverityCounts
is_valid : Bool
layers : Array[LayerManifest]
} derive(ToJson,
Debug
)

A machine-readable, non-mutating summary of a DebugDocument.

#
DocumentManifest::to_json_text

fn DocumentManifest::to_json_text(self : DocumentManifest) -> String

Serializes this manifest using the core Json encoder with a stable field order. String values are encoded by Json::string, so user input is escaped.

#
DocumentManifest::to_markdown

fn DocumentManifest::to_markdown(self : DocumentManifest) -> String

Renders a compact CI summary. User-controlled titles and layer IDs are escaped before insertion into Markdown.

#
HeatCell

pub(all) struct HeatCell {
rect : Rect
value : Double
} derive(ToJson,
Debug
)

#
HeatCell::new

fn HeatCell::new(rect~ : Rect, value~ : Double) -> HeatCell

#
ImageSpec

pub(all) struct ImageSpec {
width : Int
height : Int
} derive(Eq, ToJson,
Debug
)

#
ImageSpec::area

fn ImageSpec::area(self : ImageSpec) -> Int

#
ImageSpec::new

fn ImageSpec::new(width~ : Int, height~ : Int) -> ImageSpec

#
ImageSpec::valid

fn ImageSpec::valid(self : ImageSpec) -> Bool

#
Keypoint

pub(all) struct Keypoint {
point : Point
name : String
visible : Bool
} derive(ToJson,
Debug
)

#
Keypoint::new

fn Keypoint::new(point~ : Point, name~ : String, visible? : Bool) -> Keypoint

#
Label

pub(all) struct Label {
text : String
score : Double?
} derive(ToJson,
Debug
)

#
Label::new

fn Label::new(text~ : String, score? : Double) -> Label

#
Layer

pub(all) struct Layer {
id : String
visible : Bool
opacity : Double
overlays : Array[Overlay]
} derive(ToJson,
Debug
)

#
Layer::add

fn Layer::add(self : Layer, overlay : Overlay) -> Layer

#
Layer::bounds

fn Layer::bounds(self : Layer) -> Rect?

#
Layer::hidden

fn Layer::hidden(self : Layer) -> Layer

#
Layer::new

fn Layer::new(id~ : String, overlays? : Array[Overlay]) -> Layer

#
Layer::transform

fn Layer::transform(self : Layer, affine : Affine2D) -> Layer

#
Layer::with_opacity

fn Layer::with_opacity(self : Layer, opacity : Double) -> Layer

#
LayerChange

pub(all) struct LayerChange {
id : String
kind : LayerChangeKind
baseline_index : Int?
candidate_index : Int?
visibility_changed : Bool
opacity_changed : Bool
overlay_delta : Int
} derive(ToJson,
Debug
)

Describes one added, removed, or changed layer.

#
LayerChangeKind

pub(all) enum LayerChangeKind {
Added
Removed
Changed
} derive(ToJson,
Debug
)

Classifies a layer difference.

#
LayerManifest

pub(all) struct LayerManifest {
id : String
visible : Bool
opacity : Double
overlay_count : Int
overlays : OverlayKindCounts
} derive(ToJson,
Debug
)

A stable summary of a source layer in a document manifest.

#
MarkerShape

pub(all) enum MarkerShape {
Circle
Square
Diamond
Cross
} derive(ToJson,
Debug
)

#
MatchKind

pub(all) enum MatchKind {
TruePositive
FalsePositive
FalseNegative
LabelMismatch
} derive(ToJson,
Debug
)

#
MatchRecord

pub(all) struct MatchRecord {
kind : MatchKind
expected : Detection?
actual : Detection?
iou : Double
} derive(ToJson,
Debug
)

#
MatchRecord::is_error

fn MatchRecord::is_error(self : MatchRecord) -> Bool

#
MatchSummary

pub(all) struct MatchSummary {
records : Array[MatchRecord]
true_positive : Int
false_positive : Int
false_negative : Int
label_mismatch : Int
} derive(ToJson,
Debug
)

#
MatchSummary::error_count

fn MatchSummary::error_count(self : MatchSummary) -> Int

#
MatchSummary::precision

fn MatchSummary::precision(self : MatchSummary) -> Double

#
MatchSummary::recall

fn MatchSummary::recall(self : MatchSummary) -> Double

#
MatchSummary::to_error_layer

fn MatchSummary::to_error_layer(self : MatchSummary, id? : String) -> Layer

#
MetricsError

pub(all) enum MetricsError {
InvalidIouThreshold(value~ : Double)
InvalidScoreThreshold(value~ : Double)
InvalidDetectionScore(id~ : String, score~ : Double)
EmptyThresholdSweep
} derive(ToJson,
Debug
)

Input validation failures for detection metrics.

#
Overlay

pub(all) enum Overlay {
BBox(rect~ : Rect, label~ : Label?, color~ : Color?)
Mask(polygons~ : Array[Array[Point]], label~ : Label?, color~ : Color?)
Keypoints(points~ : Array[Keypoint], color~ : Color?)
Trajectory(path~ : Trajectory, color~ : Color?)
Heatmap(cells~ : Array[HeatCell], low~ : Color?, high~ : Color?)
ErrorRegion(rect~ : Rect, expected~ : String, actual~ : String, severity~ : Double)
} derive(ToJson,
Debug
)

#
Overlay::bounds

fn Overlay::bounds(self : Overlay) -> Rect?

#
Overlay::transform

fn Overlay::transform(self : Overlay, affine : Affine2D) -> Overlay

#
OverlayKindCounts

pub(all) struct OverlayKindCounts {
bbox : Int
mask : Int
keypoints : Int
trajectory : Int
heatmap : Int
error_region : Int
} derive(ToJson,
Debug
)

Counts overlays by their concrete rendering kind.

#
Point

pub(all) struct Point {
x : Double
y : Double
} derive(ToJson,
Debug
)

#
Point::new

fn Point::new(x~ : Double, y~ : Double) -> Point

#
Point::scale

fn Point::scale(self : Point, sx~ : Double, sy~ : Double) -> Point

#
Point::translate

fn Point::translate(self : Point, dx~ : Double, dy~ : Double) -> Point

#
Rect

pub(all) struct Rect {
x : Double
y : Double
width : Double
height : Double
} derive(ToJson,
Debug
)

#
Rect::area

fn Rect::area(self : Rect) -> Double

#
Rect::bottom

fn Rect::bottom(self : Rect) -> Double

#
Rect::intersection

fn Rect::intersection(self : Rect, other : Rect) -> Rect?

#
Rect::intersects

fn Rect::intersects(self : Rect, other : Rect) -> Bool

#
Rect::iou

fn Rect::iou(self : Rect, other : Rect) -> Double

#
Rect::new

fn Rect::new(x~ : Double, y~ : Double, width~ : Double, height~ : Double) -> Rect

#
Rect::right

fn Rect::right(self : Rect) -> Double

#
Rect::scale

fn Rect::scale(self : Rect, sx~ : Double, sy~ : Double) -> Rect

#
Rect::translate

fn Rect::translate(self : Rect, dx~ : Double, dy~ : Double) -> Rect

#
ReportOptions

pub(all) struct ReportOptions {
svg : SvgOptions
include_metadata : Bool
theme : String
} derive(ToJson,
Debug
)

#
ReportOptions::default

fn ReportOptions::default() -> ReportOptions

#
Size

pub(all) struct Size {
width : Double
height : Double
} derive(ToJson,
Debug
)

#
Size::new

fn Size::new(width~ : Double, height~ : Double) -> Size

#
SvgOptions

pub(all) struct SvgOptions {
show_labels : Bool
show_grid : Bool
background : Color
} derive(ToJson,
Debug
)

#
SvgOptions::default

fn SvgOptions::default() -> SvgOptions

#
Trajectory

pub(all) struct Trajectory {
id : String
points : Array[Point]
} derive(ToJson,
Debug
)

#
Trajectory::new

fn Trajectory::new(id~ : String, points~ : Array[Point]) -> Trajectory

#
VocAnnotation

pub(all) struct VocAnnotation {
filename : String?
size : ImageSpec
objects : Array[VocObject]
} derive(ToJson,
Debug
)

A lightweight Pascal VOC annotation with image dimensions and objects.

#
VocAnnotation::from_xml

fn VocAnnotation::from_xml(source : String) -> Result[VocAnnotation, AdapterError]

Parses VOC XML containing an optional XML declaration, standard metadata, ordered <size> dimensions, and ordered <object><name><bndbox> entries. Standard metadata is ignored; required geometric fields remain strict.

#
VocAnnotation::new

fn VocAnnotation::new(filename? : String, size~ : ImageSpec, objects~ : Array[VocObject]) -> VocAnnotation

Creates an unvalidated VOC annotation for convenient literals.

#
VocAnnotation::to_xml

fn VocAnnotation::to_xml(self : VocAnnotation) -> Result[String, AdapterError]

Exports canonical, escaped Pascal VOC XML. Rectangles are converted from zero-based half-open coordinates to VOC's one-based inclusive convention.

#
VocAnnotation::try_new

fn VocAnnotation::try_new(filename? : String, size~ : ImageSpec, objects~ : Array[VocObject]) -> Result[VocAnnotation, AdapterError]

Validates a VOC annotation without reading files or touching the runtime.

#
VocObject

pub(all) struct VocObject {
name : String
bbox : Rect
} derive(ToJson,
Debug
)

One object in a Pascal VOC annotation. bbox is pixel-space and uses the library's zero-based, half-open Rect convention.

#
VocObject::new

fn VocObject::new(name~ : String, bbox~ : Rect) -> VocObject

Creates an unvalidated VOC object. VocAnnotation::try_new and XML import validate names and boxes before returning a fallible result.

#
YoloBox

pub(all) struct YoloBox {
class_id : Int
center_x : Double
center_y : Double
width : Double
height : Double
confidence : Double?
} derive(ToJson,
Debug
)

A YOLO bounding box whose centre and dimensions are normalized to [0, 1]. confidence is optional because training labels normally omit it.

#
YoloBox::from_line

fn YoloBox::from_line(line : String, image~ : ImageSpec, classes~ : Array[String]) -> Result[YoloBox, AdapterError]

Parses one deterministic YOLO label line (five fields, or six with score). The caller's class mapping is checked so unknown numeric IDs are rejected.

#
YoloBox::from_rect

fn YoloBox::from_rect(class_id~ : Int, rect~ : Rect, image~ : ImageSpec, confidence? : Double) -> Result[YoloBox, AdapterError]

Converts a contained pixel-space rectangle into a normalized YOLO record.

#
YoloBox::to_line

fn YoloBox::to_line(self : YoloBox, classes : Array[String]) -> Result[String, AdapterError]

Serializes one record with single ASCII-space separators. The mapping is validated even though standard YOLO syntax stores the numeric ID.

#
YoloBox::to_rect

fn YoloBox::to_rect(self : YoloBox, image : ImageSpec) -> Result[Rect, AdapterError]

Converts this normalized box to the library's pixel-space Rect.

#
YoloBox::try_new

fn YoloBox::try_new(class_id~ : Int, center_x~ : Double, center_y~ : Double, width~ : Double, height~ : Double, confidence? : Double) -> Result[YoloBox, AdapterError]

Creates a validated normalized YOLO record.

#
compare_detections

fn compare_detections(expected : Array[Detection], actual : Array[Detection], iou_threshold? : Double) -> MatchSummary

#
compare_documents

fn compare_documents(baseline : DebugDocument, candidate : DebugDocument) -> DocumentDiff

Compares documents without mutating either input.

Unique non-empty layer IDs match by ID. Duplicate and empty IDs match by their occurrence order among layers with the same ID.

#
evaluate_detections

fn evaluate_detections(expected : Array[Detection], actual : Array[Detection], iou_threshold? : Double, score_threshold? : Double) -> Result[DetectionMetrics, MetricsError]

Evaluates detections after filtering actual detections whose score is below score_threshold. All thresholds and detection scores must be finite values in the inclusive range [0, 1].

#
palette

fn palette(index : Int) -> Color

#
sweep_iou_thresholds

fn sweep_iou_thresholds(expected : Array[Detection], actual : Array[Detection], thresholds : Array[Double], score_threshold? : Double) -> Result[Array[DetectionMetrics], MetricsError]

Runs the same score-filtered evaluation at every caller-supplied IoU threshold. Results are sorted from the loosest to strictest threshold.