audit YOLO geometry and overlapping validation rows
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import pytest
|
||||
|
||||
from scripts.audit_yolo_cross_tile_repetition import (
|
||||
interior_global_key,
|
||||
tile_offsets,
|
||||
)
|
||||
from scripts.audit_yolo_label_relationships import Box
|
||||
|
||||
|
||||
def test_tile_offsets_parse_exporter_filename() -> None:
|
||||
assert tile_offsets("/data/geel_0005_r256_c512.png") == (256, 512)
|
||||
with pytest.raises(ValueError, match="no row/column offsets"):
|
||||
tile_offsets("/data/not-a-tile.png")
|
||||
|
||||
|
||||
def test_interior_global_key_reconstructs_same_object_across_tiles() -> None:
|
||||
first = Box(0, 0.75, 0.5, 0.1, 0.1)
|
||||
second = Box(0, 0.25, 0.5, 0.1, 0.1)
|
||||
|
||||
first_key = interior_global_key(
|
||||
first,
|
||||
row_offset=0,
|
||||
column_offset=0,
|
||||
tile_size=512,
|
||||
edge_tolerance_pixels=0.5,
|
||||
)
|
||||
second_key = interior_global_key(
|
||||
second,
|
||||
row_offset=0,
|
||||
column_offset=256,
|
||||
tile_size=512,
|
||||
edge_tolerance_pixels=0.5,
|
||||
)
|
||||
|
||||
assert first_key == second_key == (358.4, 230.4, 409.6, 281.6)
|
||||
|
||||
|
||||
def test_interior_global_key_rejects_edge_clipped_box() -> None:
|
||||
edge_box = Box(0, 0.05, 0.5, 0.1, 0.1)
|
||||
|
||||
assert (
|
||||
interior_global_key(
|
||||
edge_box,
|
||||
row_offset=0,
|
||||
column_offset=256,
|
||||
tile_size=512,
|
||||
edge_tolerance_pixels=0.5,
|
||||
)
|
||||
is None
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
from scripts.audit_yolo_label_outliers import classify_box
|
||||
from scripts.audit_yolo_label_relationships import Box
|
||||
|
||||
|
||||
DEFAULTS = {
|
||||
"tile_size": 640,
|
||||
"min_dimension_pixels": 4.0,
|
||||
"extreme_aspect_ratio": 8.0,
|
||||
"edge_tolerance_pixels": 0.5,
|
||||
}
|
||||
|
||||
|
||||
def test_classify_box_reports_independent_geometric_risks() -> None:
|
||||
box = Box(0, 0.5, 0.003, 0.2, 0.006)
|
||||
|
||||
assert classify_box(box, **DEFAULTS) == [
|
||||
{
|
||||
"category": "small_dimension",
|
||||
"width_px": 128.0,
|
||||
"height_px": 3.84,
|
||||
"area_px2": 491.52,
|
||||
"aspect_ratio": 33.333333,
|
||||
},
|
||||
{
|
||||
"category": "extreme_aspect_ratio",
|
||||
"width_px": 128.0,
|
||||
"height_px": 3.84,
|
||||
"area_px2": 491.52,
|
||||
"aspect_ratio": 33.333333,
|
||||
},
|
||||
{
|
||||
"category": "tile_edge",
|
||||
"edge_sides": ["top"],
|
||||
"width_px": 128.0,
|
||||
"height_px": 3.84,
|
||||
"area_px2": 491.52,
|
||||
"aspect_ratio": 33.333333,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_classify_box_ignores_ordinary_interior_box() -> None:
|
||||
box = Box(0, 0.5, 0.5, 0.1, 0.08)
|
||||
|
||||
assert classify_box(box, **DEFAULTS) == []
|
||||
@@ -0,0 +1,29 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from scripts.evaluate_yolo_checkpoint_matrix import dataset_overlap_evidence
|
||||
|
||||
|
||||
def test_dataset_overlap_evidence_marks_repeated_validation_rows(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
dataset_yaml = tmp_path / "dataset.yaml"
|
||||
dataset_yaml.write_text("path: .\nval: images/val\n", encoding="utf-8")
|
||||
(tmp_path / "yolo_tile_dataset_summary.json").write_text(
|
||||
json.dumps({"tile_size": 512, "stride": 256}), encoding="utf-8"
|
||||
)
|
||||
|
||||
evidence = dataset_overlap_evidence(dataset_yaml)
|
||||
|
||||
assert evidence["status"] == "overlapping"
|
||||
assert evidence["overlap_pixels"] == 256
|
||||
assert evidence["validation_rows_independent"] is False
|
||||
|
||||
|
||||
def test_dataset_overlap_evidence_is_explicit_when_summary_missing(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
evidence = dataset_overlap_evidence(tmp_path / "dataset.yaml")
|
||||
|
||||
assert evidence["status"] == "unavailable"
|
||||
assert evidence["validation_rows_independent"] is None
|
||||
@@ -2,6 +2,7 @@ import pytest
|
||||
|
||||
from scripts.render_operator_yolo_label_qa_contact_sheets import (
|
||||
CONTACT_SHEET_NAME_TEMPLATE,
|
||||
build_label_highlights,
|
||||
build_relationship_highlights,
|
||||
filter_tiles_by_samples,
|
||||
)
|
||||
@@ -72,3 +73,25 @@ def test_relationship_highlights_bind_indices_and_preserve_highest_priority() ->
|
||||
7: "near_duplicate",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_label_highlights_support_outliers_with_stable_priority() -> None:
|
||||
summary = {
|
||||
"flagged_tiles": [
|
||||
{
|
||||
"label_path": "/data/tile.txt",
|
||||
"outliers": [
|
||||
{"category": "tile_edge", "index": 3},
|
||||
{"category": "small_dimension", "index": 3},
|
||||
{"category": "extreme_aspect_ratio", "index": 4},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
assert build_label_highlights(summary) == {
|
||||
"/data/tile.txt": {
|
||||
3: "small_dimension",
|
||||
4: "extreme_aspect_ratio",
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user