Files
code-test-drone/utils/tests/stereo_ranger/matching_test.py
T

88 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""匹配器测试(规格 §6.2/§11.4:硬约束各一例、贪心排序、一一配对、cost ≥ 1 拒绝)。"""
import pytest
from stereo_ranger import Detection, GreedyMatcher, SamplePoint, StereoConfig, sample_point
CFG = StereoConfig()
MATCHER = GreedyMatcher()
def _point(cx: float, cy: float, *, w: float = 60.0, h: float = 40.0, class_id: int = 0) -> SamplePoint:
return sample_point(
Detection(cx - w / 2.0, cy - h / 2.0, cx + w / 2.0, cy + h / 2.0, class_id=class_id)
)
def test_class_mismatch_rejected():
assert MATCHER.match([_point(1000.0, 500.0)], [_point(1000.0, 500.0, class_id=1)], CFG) == []
def test_dy_beyond_tau_rejected():
assert MATCHER.match([_point(1000.0, 500.0)], [_point(1000.0, 502.1)], CFG) == []
def test_dy_within_tau_accepted_with_cost():
pairs = MATCHER.match([_point(1000.0, 500.0)], [_point(1000.0, 501.9)], CFG)
assert len(pairs) == 1
assert pairs[0].cost == pytest.approx(1.9 / CFG.tau_y_px)
def test_height_ratio_beyond_tau_rejected():
assert MATCHER.match([_point(1000.0, 500.0, h=100.0)], [_point(1000.0, 500.0, h=140.0)], CFG) == []
def test_height_ratio_near_tau_accepted():
pairs = MATCHER.match([_point(1000.0, 500.0, h=120.0)], [_point(1000.0, 500.0, h=159.0)], CFG)
assert len(pairs) == 1
def test_cost_at_one_rejected():
# dy = tau_y ⇒ cost = 1.0,严格 cost < 1 才接受(§6.2)
assert MATCHER.match([_point(1000.0, 500.0)], [_point(1000.0, 502.0)], CFG) == []
def test_combined_cost_at_one_rejected():
# dy/tau = 0.5 与 Δh/(tau_h·h_max) = 0.5 相加恰为 1.0 → 拒绝
assert MATCHER.match([_point(1000.0, 500.0, h=112.0)], [_point(1000.0, 501.0, h=128.0)], CFG) == []
def test_greedy_pairs_cheapest_first_and_one_to_one():
left = [_point(1000.0, 500.0), _point(1000.0, 501.0)]
right = [_point(1000.0, 500.0), _point(1000.0, 501.0)]
pairs = MATCHER.match(left, right, CFG)
assert [(p.left_index, p.right_index) for p in pairs] == [(0, 0), (1, 1)]
assert pairs[0].cost == pytest.approx(0.0)
def test_one_left_claims_cheapest_right():
pairs = MATCHER.match([_point(1000.0, 500.0)], [_point(1000.0, 500.0), _point(1000.0, 500.5)], CFG)
assert [(p.left_index, p.right_index) for p in pairs] == [(0, 0)]
def test_two_lefts_cannot_share_one_right():
left = [_point(1000.0, 500.0), _point(1000.0, 500.2)]
right = [_point(1000.0, 500.0)]
pairs = MATCHER.match(left, right, CFG)
assert len(pairs) == 1
assert pairs[0].left_index == 0
def test_unmatched_right_is_not_paired():
pairs = MATCHER.match([_point(1000.0, 500.0)], [_point(1000.0, 500.0), _point(1400.0, 500.0)], CFG)
assert len(pairs) == 1
assert pairs[0].right_index == 0
def test_non_finite_points_excluded():
bad = sample_point(Detection(float("nan"), 500.0, 1060.0, 540.0))
good = _point(1000.0, 500.0)
assert MATCHER.match([bad], [good], CFG) == []
assert MATCHER.match([good], [bad], CFG) == []
def test_zero_height_box_rejected():
left = sample_point(Detection(970.0, 500.0, 1030.0, 500.0))
right = sample_point(Detection(970.0, 500.0, 1030.0, 500.0))
assert MATCHER.match([left], [right], CFG) == []