Spaces:
Sleeping
Sleeping
| """Test phần THUẦN của poolcoach_cv.overlay (lát A2 phần 3) — venv app, | |
| không cv2/torch: RecordingModel (ghi bbox quanh predict) + _uncomp_xy | |
| (nghịch đảo bù độ cao — vẽ ngược lên frame phải ra chỗ bi HIỆN RA). | |
| Render thật nghiệm thu bằng smoke trên clip cú 03 rack_a1 (venv CV, | |
| 13/08) + gate A2.2 khi rerun trọn VOD. | |
| """ | |
| from __future__ import annotations | |
| import numpy as np | |
| import pytest | |
| from poolcoach_cv.camera import HeightCompensation | |
| from poolcoach_cv.overlay import BALL_BGR, RecordingModel, _uncomp_xy | |
| class _Box: | |
| def __init__(self, cls_i, conf, xyxy): | |
| self.cls = cls_i | |
| self.conf = conf | |
| self.xyxy = [xyxy] | |
| class _Res: | |
| names = {0: "Cue", 1: "Solid"} | |
| def __init__(self, boxes): | |
| self.boxes = boxes | |
| class _FakeYolo: | |
| def predict(self, imgs, **kw): | |
| # mỗi ảnh 1 kết quả — ảnh thứ hai không có det nào | |
| out = [_Res([_Box(0, 0.9, (10.0, 20.0, 30.0, 40.0)), | |
| _Box(1, 0.8, (50.0, 60.0, 70.0, 80.0))])] | |
| out += [_Res([]) for _ in imgs[1:]] | |
| return out | |
| def test_recording_model_ghi_bbox_theo_thu_tu_frame(): | |
| rec = RecordingModel(_FakeYolo()) | |
| res = rec.predict(["f0", "f1"], conf=0.3, imgsz=640, verbose=False) | |
| assert len(res) == 2 # forward nguyên kết quả | |
| assert len(rec.frames) == 2 | |
| assert rec.frames[0] == [("Cue", 0.9, (10.0, 20.0, 30.0, 40.0)), | |
| ("Solid", 0.8, (50.0, 60.0, 70.0, 80.0))] | |
| assert rec.frames[1] == [] | |
| rec.predict(["f2"], conf=0.3) | |
| assert len(rec.frames) == 3 # batch sau nối tiếp, không đè | |
| def test_uncomp_xy_dao_dung_bu_do_cao(): | |
| """apply (bù) rồi _uncomp_xy (đảo) phải về đúng toạ độ map gốc — vẽ | |
| ngược qua homography mới trúng chỗ bi hiện ra trên frame.""" | |
| comp = HeightCompensation(True, cam_xy=(0.6, 1.2), h_m=2.41, | |
| f_px=2236.0, ball_r=0.028575) | |
| raw = np.array([[0.2, 0.4], [1.1, 2.3]]) | |
| compensated = comp.apply(raw) | |
| meta = {"on": True, "h_m": 2.41, "cx_m": 0.6, "cy_m": 1.2} | |
| assert _uncomp_xy(compensated, meta) == pytest.approx(raw, abs=1e-9) | |
| def test_uncomp_xy_off_hay_thieu_camera_giu_nguyen(): | |
| pts = np.array([[0.5, 0.5]]) | |
| assert _uncomp_xy(pts, {"on": False}) is pts | |
| assert _uncomp_xy(pts, None) is pts | |
| # on nhưng thiếu cx/cy (kết quả thời kỳ BG31 trước BG32) — không đoán | |
| assert _uncomp_xy(pts, {"on": True, "h_m": 2.4}) is pts | |
| def test_bang_mau_bi_du_1_den_9(): | |
| assert set(BALL_BGR) == set(range(1, 10)) | |