///|
pub fn run_default_caliper(image : GrayImage) -> PipelineResult {
let config = CaliperConfig::new(
start=Point::Point(x=0.0, y=Double::from_int(image.height / 2)),
finish=Point::Point(
x=Double::from_int((image.width - 1).max(0)),
y=Double::from_int(image.height / 2),
),
threshold=0.05,
mode=Both,
expected_edges=2,
unit="px",
)
let tolerance = Tolerance::Tolerance(
nominal=0.0,
lower=-1.0e9,
upper=1.0e9,
unit="px",
)
safe_measure_caliper(image, config, tolerance)
}
///|
pub fn run_default_inspection(image : GrayImage) -> String {
inspection_summary(run_default_caliper(image))
}
///|
pub fn image_dimensions_text(image : GrayImage) -> String {
image.width.to_string() + "x" + image.height.to_string()
}
///|
pub fn mask_dimensions_text(mask : BinaryMask) -> String {
mask.width.to_string() + "x" + mask.height.to_string()
}
///|
pub fn profile_dimensions_text(profile : ProfileSummary) -> String {
"samples=" +
profile.samples.length().to_string() +
"; edges=" +
profile.edges.length().to_string()
}
///|
pub fn component_dimensions_text(component : Component) -> String {
(component.bounds.max_x - component.bounds.min_x + 1).to_string() +
"x" +
(component.bounds.max_y - component.bounds.min_y + 1).to_string()
}
///|
pub fn summary_dimensions_text(summary : MeasurementSummary) -> String {
"total=" +
summary.total.to_string() +
"; pass=" +
summary.pass.to_string() +
"; warn=" +
summary.warn.to_string() +
"; fail=" +
summary.fail.to_string()
}
///|
pub fn make_report_for_image(image : GrayImage, part_id : String) -> String {
let result = run_default_caliper(image)
inspection_markdown(part_id, image, result)
}
///|
pub fn make_json_for_image(image : GrayImage, part_id : String) -> String {
let result = run_default_caliper(image)
let batch = BatchRun::new(part_id)
for measurement in result.measurements {
batch.add(measurement)
}
render_batch_json(batch)
}
///|
pub fn make_csv_for_image(image : GrayImage) -> String {
render_measurements_csv(run_default_caliper(image).measurements)
}
///|
pub fn make_quality_for_image(image : GrayImage) -> String {
quality_summary_text(frame_quality(image))
}
///|
pub fn make_benchmark_summary() -> String {
"checksums:\n" + benchmark_checksum_text()
}
///|
pub fn package_health(image : GrayImage) -> Array[PipelineDiagnostic] {
let result = contract_diagnostics_image(image)
result.append(
contract_diagnostics_mask(threshold_image(image, otsu_threshold(image))),
)
result
}
///|
pub fn package_health_text(image : GrayImage) -> String {
contract_summary(package_health(image))
}
///|
pub fn supported_report_formats() -> Array[String] {
["markdown", "csv", "json", "diagnostic-csv", "profile-csv", "edge-csv"]
}
///|
pub fn supported_targets() -> Array[String] {
["wasm", "wasm-gc", "js", "native"]
}
///|
pub fn supported_measurements() -> Array[String] {
[
"distance", "angle", "line-fit", "circle-fit", "width", "height", "area", "perimeter",
"roundness", "runout",
]
}
///|
pub fn public_project_summary() -> String {
"A deterministic MoonBit-native visual measurement core for profiles, edges, geometry, calibration, tolerances, and reports."
}
///|
pub fn versioned_project_summary() -> String {
inspection_version() + " - " + public_project_summary()
}
///|
pub fn algorithm_inventory() -> Array[String] {
[
"bilinear sampling", "Sobel gradient", "hysteresis edges", "median and Gaussian smoothing",
"morphology", "connected components", "contours", "convex hull", "line and circle fit",
"affine calibration", "tolerance analysis", "uncertainty propagation", "batch analytics",
]
}
///|
pub fn deterministic_fixture_inventory() -> Array[String] {
[
"bracket", "slot", "circle", "ring", "diagonal edge", "rotated rectangle", "checker",
"ramp", "multi-part", "noisy frame",
]
}
///|
pub fn api_contract_inventory() -> Array[String] {
[
"safe image access", "safe fitting", "safe caliper", "mask shape validation",
"tolerance validation", "calibration validation",
]
}
///|
pub fn default_edge_policy() -> EdgePolicy {
EdgePolicy::new(
low_threshold=0.05,
high_threshold=0.12,
mode=Both,
min_strength=0.02,
)
}
///|
pub fn default_tolerance(nominal : Double, unit : String) -> Tolerance {
Tolerance::Tolerance(
nominal~,
lower=nominal * 0.99,
upper=nominal * 1.01,
unit~,
)
}
///|
pub fn default_caliper(image : GrayImage) -> CaliperConfig {
CaliperConfig::new(
start=Point::Point(x=0.0, y=Double::from_int(image.height / 2)),
finish=Point::Point(
x=Double::from_int((image.width - 1).max(0)),
y=Double::from_int(image.height / 2),
),
threshold=default_edge_policy().low_threshold,
mode=Both,
expected_edges=2,
unit="px",
)
}
///|
pub fn default_roi(image : GrayImage) -> Roi {
Roi::from_bounds(
"full-frame",
{ min_x: 0, min_y: 0, max_x: image.width - 1, max_y: image.height - 1 },
image,
)
}
///|
pub fn nominal_tolerance(nominal : Double) -> Tolerance {
default_tolerance(nominal, "mm")
}
///|
pub fn pixel_tolerance(nominal : Double) -> Tolerance {
default_tolerance(nominal, "px")
}
///|
pub fn full_frame_roi(image : GrayImage) -> Roi {
default_roi(image)
}
///|
pub fn frame_checksum(image : GrayImage) -> Double {
stable_checksum_image(image)
}
///|
pub fn frame_focus(image : GrayImage) -> Double {
focus_score(image)
}
///|
pub fn frame_sharpness(image : GrayImage) -> Double {
sharpness_score(image)
}
///|
pub fn frame_entropy(image : GrayImage) -> Double {
entropy_image(image, 32)
}
///|
pub fn frame_dynamic_range(image : GrayImage) -> Double {
image_dynamic_range(image)
}
///|
pub fn frame_noise(image : GrayImage) -> Double {
texture_noise(image)
}
///|
pub fn frame_edge_count(image : GrayImage) -> Int {
edge_map(image, 0.05, 0.12).count
}
///|
pub fn frame_component_count(image : GrayImage) -> Int {
label_components(adaptive_threshold(image, 2, 0.01)).length()
}
///|
pub fn frame_contour_count(image : GrayImage) -> Int {
contour_loops(adaptive_threshold(image, 2, 0.01)).length()
}
///|
pub fn frame_quality_score(image : GrayImage) -> Double {
image_quality_score(image)
}
///|
pub fn frame_health_text(image : GrayImage) -> String {
package_health_text(image)
}
///|
pub fn frame_dimensions(image : GrayImage) -> Bounds {
{ min_x: 0, min_y: 0, max_x: image.width - 1, max_y: image.height - 1 }
}