"""Test POST /api/pose_3d/align: fit Umeyama + persistenza config.""" from __future__ import annotations from unittest.mock import patch, MagicMock import numpy as np from fastapi.testclient import TestClient from presa_mano.main import app from presa_mano.config import get_config client = TestClient(app) _CORNERS_PX = [[100, 100], [140, 100], [140, 140], [100, 140]] def _cam_with_points(points_by_pixel): cam = MagicMock() cam.intrinsics.return_value = {"rgb": {"fx": 600.0, "fy": 600.0, "cx": 320.0, "cy": 240.0}} cam.rgb_url.return_value = "http://cam/rgb.png" def _measure(u, v, radius=2): key = (int(u), int(v)) if key in points_by_pixel: x, y, z = points_by_pixel[key] else: xs = [p[0] for p in points_by_pixel.values()] ys = [p[1] for p in points_by_pixel.values()] zs = [p[2] for p in points_by_pixel.values()] x, y, z = sum(xs)/len(xs), sum(ys)/len(ys), sum(zs)/len(zs) return {"point_m": {"x": x, "y": y, "z": z}, "depth_mm": int(z * 1000)} cam.measure.side_effect = _measure return cam def _marker(found_ids): mk = MagicMock() mk.detect_url.return_value = { "found": [{"id": i, "corners": _CORNERS_PX} for i in found_ids], "not_found": [], } return mk def test_align_fits_and_persists(): nuwa_pts = { (100, 100): (0.10, 0.10, 0.30), (140, 100): (0.14, 0.10, 0.30), (140, 140): (0.14, 0.14, 0.30), (100, 140): (0.10, 0.14, 0.30), } d435_pts = {k: (v[0]*2, v[1]*2, v[2]*2) for k, v in nuwa_pts.items()} with patch("presa_mano.api.pose_3d_routes._deps.nuwa") as nuwa_f, \ patch("presa_mano.api.pose_3d_routes._deps.front_camera") as front_f, \ patch("presa_mano.api.pose_3d_routes._deps.marker") as mk_f: nuwa_f.return_value = _cam_with_points(nuwa_pts) front_f.return_value = _cam_with_points(d435_pts) mk_f.return_value = _marker([7]) r = client.post("/api/pose_3d/align?ids=0-9&align_id=7") assert r.status_code == 200 body = r.json() assert body["found_in_both"] is True assert abs(body["scale"] - 2.0) < 1e-3 assert body["align_id"] == 7 cc = get_config()["pose_3d"]["cross_camera"] assert abs(cc["scale"] - 2.0) < 1e-3 assert cc["align_id"] == 7 assert len(cc["R"]) == 3 and len(cc["t"]) == 3 def test_align_tag_missing_in_one_camera_does_not_save(): pts = {(100,100):(0.1,0.1,0.3),(140,100):(0.14,0.1,0.3), (140,140):(0.14,0.14,0.3),(100,140):(0.1,0.14,0.3)} with patch("presa_mano.api.pose_3d_routes._deps.nuwa") as nuwa_f, \ patch("presa_mano.api.pose_3d_routes._deps.front_camera") as front_f, \ patch("presa_mano.api.pose_3d_routes._deps.marker") as mk_f: nuwa_f.return_value = _cam_with_points(pts) front_f.return_value = _cam_with_points(pts) mk_f.return_value = _marker([1]) # nessun tag id=99 r = client.post("/api/pose_3d/align?ids=0-9&align_id=99") assert r.status_code == 200 body = r.json() assert body["found_in_both"] is False assert body.get("error") assert "cross_camera" not in get_config().get("pose_3d", {})