新增双目yolo实现python代码

This commit is contained in:
keita
2026-09-14 15:05:03 +08:00
parent 538ae4c6c7
commit 3a8e2c7f4b
65 changed files with 2467 additions and 10 deletions
@@ -0,0 +1,87 @@
"""匹配器测试(规格 §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) == []