import argparse from collections import defaultdict from pathlib import Path import random import numpy as np from tools.pdcl_inference.analyze_val_two_roi_badcases import ( FACE_VISIBILITY_BUCKET_ORDER, add_interval_visual_record, build_grouped_metric_bucket_interval_rows, build_badcase_draw_kwargs, flatten_grouped_metric_bucket_interval_rows, is_signed_lateral_yaw_compare_longitudinal_eligible, interval_label, make_metric_bucket, make_interval_visual_reservoirs, make_record, select_interval_visual_records, ) from tools.pdcl_inference.two_roi_inference import ( DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, _project_selected_face_edges_from_box, _selected_edge_residual_stats, _build_edge_heading_decoded, _restore_depth_scale, add_two_roi_inference_args, ) from ultralytics.utils.plotting_3d import ( compute_3d_box_corners, decode_edge_yaw_selection_from_prediction, decode_3d_prediction, extract_3d_attrs_from_prediction, face_center_from_corners, project_3d_to_2d, project_face_bottom_edge, project_partial_face_bottom_edge, reconstruct_edge_based_box_from_selection, reconstruct_two_face_box_from_edge_selection, ) def _encode_face_branch(pred, corners, face_type, score, anchor, stride, calib): face_center = face_center_from_corners(corners, face_type) face_uv = project_3d_to_2d(face_center[None, :], calib)[0] off = face_type * 6 pred[off] = face_center[2] pred[off + 1 : off + 3] = [face_uv[0] / stride - anchor[0], face_uv[1] / stride - anchor[1]] pred[off + 5] = score def _encode_edge_branch(pred_edge, face_type, points_3d, points_2d, anchor, stride): face_block = pred_edge[face_type * 15 : (face_type + 1) * 15].reshape(5, 3) face_block[:, 0] = points_2d[:, 0] / stride - anchor[0] face_block[:, 1] = points_2d[:, 1] / stride - anchor[1] face_block[:, 2] = points_3d[:, 2] def test_signed_lateral_yaw_compare_longitudinal_eligibility_uses_lt_50m(): assert is_signed_lateral_yaw_compare_longitudinal_eligible({"gt_z_m": 49.99}) is True assert is_signed_lateral_yaw_compare_longitudinal_eligible({"gt_z_m": 50.0}) is False assert is_signed_lateral_yaw_compare_longitudinal_eligible({"gt_z_m": 65.0}) is False assert is_signed_lateral_yaw_compare_longitudinal_eligible({"gt_z_m": -1.0}) is False assert is_signed_lateral_yaw_compare_longitudinal_eligible({"gt_z_m": None}) is False def test_build_grouped_metric_bucket_interval_rows_splits_face_visibility_buckets(): stores = {bucket_name: defaultdict(make_metric_bucket) for bucket_name in FACE_VISIBILITY_BUCKET_ORDER} front_bucket = stores["front_rear_only"][-5.0] front_bucket["matched_3d"] = 4 front_bucket["yaw_compare_eligible_count"] = 4 front_bucket["yaw_compare_pair_count"] = 2 front_bucket["direct_visible_yaw_abs_deg"] = [4.0, 6.0] front_bucket["edge_visible_yaw_abs_deg"] = [5.0, 7.0] front_bucket["direct_minus_edge_visible_yaw_abs_deg"] = [-1.0, -1.0] two_face_bucket = stores["two-face"][0.0] two_face_bucket["matched_3d"] = 5 two_face_bucket["yaw_compare_eligible_count"] = 5 two_face_bucket["yaw_compare_pair_count"] = 3 two_face_bucket["direct_visible_yaw_abs_deg"] = [2.0, 3.0, 4.0] two_face_bucket["edge_visible_yaw_abs_deg"] = [1.0, 2.0, 3.0] two_face_bucket["direct_minus_edge_visible_yaw_abs_deg"] = [1.0, 1.0, 1.0] rows_by_group = build_grouped_metric_bucket_interval_rows( stores, bin_width_m=5.0, prefix="lateral_bin", group_order=FACE_VISIBILITY_BUCKET_ORDER, ) assert list(rows_by_group) == list(FACE_VISIBILITY_BUCKET_ORDER) assert [row["lateral_bin_label"] for row in rows_by_group["front_rear_only"]] == ["[-5,0)m"] assert rows_by_group["side only"] == [] assert [row["lateral_bin_label"] for row in rows_by_group["two-face"]] == ["[0,5)m"] assert np.isclose(rows_by_group["two-face"][0]["direct_regression_yaw_mae_deg"], 3.0) assert np.isclose(rows_by_group["two-face"][0]["edge_based_yaw_mae_deg"], 2.0) flat_rows = flatten_grouped_metric_bucket_interval_rows(rows_by_group, group_key="face_visibility_bucket") assert [row["face_visibility_bucket"] for row in flat_rows] == ["front_rear_only", "two-face"] assert [row["lateral_bin_label"] for row in flat_rows] == ["[-5,0)m", "[0,5)m"] def test_restore_depth_scale_scales_edge_depth_channels_too(): preds_3d = np.ones((2, 41), dtype=np.float32) preds_edge = np.ones((2, 60), dtype=np.float32) restored_3d, restored_edge = _restore_depth_scale(preds_3d, preds_edge, 2.5) for channel in (0, 6, 12, 18, 24): assert np.allclose(restored_3d[:, channel], 2.5) untouched_3d = np.setdiff1d(np.arange(preds_3d.shape[1]), np.array([0, 6, 12, 18, 24])) assert np.allclose(restored_3d[:, untouched_3d], 1.0) assert restored_edge is not None assert np.allclose(restored_edge[:, 2::3], 2.5) assert np.allclose(restored_edge[:, 0::3], 1.0) assert np.allclose(restored_edge[:, 1::3], 1.0) assert np.allclose(preds_3d, 1.0) assert np.allclose(preds_edge, 1.0) def test_build_edge_heading_decoded_anchors_cut_objects_on_primary_face(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-4.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([0.0, 120.0, 80.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 # cut_in corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_partial_face_bottom_edge(corners, 3, calib, 640, 480, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None _encode_edge_branch(pred_edge, 0, front_points_3d, front_points_2d, anchor, stride) _encode_edge_branch(pred_edge, 3, side_points_3d, side_points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) assert edge_confident assert np.isfinite(edge_yaw) assert heading_decoded is not None assert heading_decoded["visible_face_type"] == 0 assert heading_decoded["visible_face_types"] == (0, 3) diff = (edge_yaw - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-3) assert np.allclose( face_center_from_corners(heading_decoded["corners_3d"], 0), face_center_from_corners(decoded["corners_3d"], 0), atol=1e-4, ) def test_build_edge_heading_decoded_falls_back_to_single_front_face_when_cut_side_edge_is_short(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-4.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([0.0, 120.0, 80.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 # cut_in corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, _ = project_partial_face_bottom_edge(corners, 3, calib, 640, 480, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None short_len = float(dims[0] * 0.4) side_dir = side_points_3d[-1] - side_points_3d[0] side_dir = side_dir / np.linalg.norm(side_dir) short_side_points_3d = side_points_3d[0] + np.linspace(0.0, short_len, 5, dtype=np.float32)[:, None] * side_dir[None, :] short_side_points_2d = project_3d_to_2d(short_side_points_3d, calib) assert np.all(np.isfinite(short_side_points_2d)) _encode_edge_branch(pred_edge, 0, front_points_3d, front_points_2d, anchor, stride) _encode_edge_branch(pred_edge, 3, short_side_points_3d, short_side_points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, img_h=480, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, edge_selection=edge_selection, ) assert edge_selection["cut_side_visible_length_ratio"] is not None assert edge_selection["cut_side_visible_length_ratio"] < 0.5 assert edge_selection["cut_side_visible_ratio_ok"] is False assert edge_selection["is_valid"] is False assert edge_selection["face_types"] == (0,) assert heading_decoded is not None assert edge_confident assert np.isfinite(edge_yaw) def test_reconstruct_two_face_box_from_edge_selection_uses_selected_edge_lengths(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None edge_box = reconstruct_two_face_box_from_edge_selection( { "yaw": float(rot_y), "face_types": (0, 3), "edge_points_3d": np.stack([front_points_3d, side_points_3d], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_height_m=float(dims[1]), ) assert edge_box is not None assert np.allclose(edge_box["center"], center, atol=1e-4) assert np.allclose(edge_box["dims"], dims, atol=1e-4) diff = (edge_box["yaw"] - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-5) def test_reconstruct_edge_based_box_from_selection_trusts_longitudinal_label_and_ignores_side_label(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0, 2), "face_is_partial": (False, False), "edge_points_3d": np.stack([front_points_3d, side_points_3d], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_center_y_m=float(center[1]), regressed_dims=dims, ) assert edge_box is not None assert edge_box["mode"] == "two-face" assert np.allclose(edge_box["center"], center, atol=1e-4) assert np.allclose(edge_box["dims"], dims, atol=1e-4) assert edge_box["face_types"] == (0, 3) def test_reconstruct_edge_based_box_from_selection_uses_edge_y_as_vertical_anchor(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.5, 0.3, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None noisy_front = front_points_3d.copy() noisy_side = side_points_3d.copy() noisy_front[:, 1] -= 0.9 noisy_side[:, 1] -= 0.7 edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0, 3), "edge_points_3d": np.stack([noisy_front, noisy_side], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_center_y_m=float(center[1]), regressed_dims=dims, ) assert edge_box is not None expected_center_y = float(np.mean(np.concatenate([noisy_front[:, 1], noisy_side[:, 1]], axis=0)) - float(dims[1]) * 0.5) assert np.isclose(float(edge_box["center"][1]), expected_center_y, atol=1e-5) assert np.allclose(edge_box["dims"], dims, atol=1e-4) def test_reconstruct_edge_based_box_from_selection_ignores_vertical_noise_in_edge_length(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None noisy_side = side_points_3d.copy() noisy_side[:, 1] += np.linspace(0.0, 8.0, noisy_side.shape[0], dtype=np.float32) edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0, 3), "edge_points_3d": np.stack([front_points_3d, noisy_side], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_center_y_m=float(center[1]), regressed_dims=dims, ) assert edge_box is not None assert np.isclose(float(edge_box["dims"][0]), float(dims[0]), atol=1e-4) assert np.isclose(float(edge_box["dims"][2]), float(dims[2]), atol=1e-4) def test_reconstruct_edge_based_box_from_front_face_uses_regressed_length(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.0, 0.1, 20.0], dtype=np.float32) true_dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) regressed_dims = np.array([5.2, 1.7, 1.8], dtype=np.float32) rot_y = 0.45 corners = compute_3d_box_corners(center, true_dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0,), "edge_points_3d": front_points_3d, "edge_points_2d": front_points_2d, }, box_center_y_m=float(center[1]), regressed_dims=regressed_dims, ) assert edge_box is not None assert edge_box["mode"] == "front-rear" assert np.isclose(float(edge_box["dims"][0]), float(regressed_dims[0]), atol=1e-5) assert np.isclose(float(edge_box["dims"][1]), float(regressed_dims[1]), atol=1e-5) assert np.isclose(float(edge_box["dims"][2]), float(true_dims[2]), atol=1e-4) expected_face_center = face_center_from_corners(corners, 0) assert expected_face_center is not None assert np.isclose(float(edge_box["center"][0]), float(expected_face_center[0]), atol=1e-4) assert np.isclose(float(edge_box["center"][2]), float(expected_face_center[2]), atol=1e-4) rebuilt_face_center = face_center_from_corners(edge_box["corners_3d"], 0) assert rebuilt_face_center is not None and expected_face_center is not None assert np.allclose(rebuilt_face_center, expected_face_center, atol=1e-4) def test_reconstruct_edge_based_box_from_side_face_uses_regressed_width(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-1.2, -0.2, 18.0], dtype=np.float32) true_dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) regressed_dims = np.array([4.0, 1.6, 2.4], dtype=np.float32) rot_y = -0.55 corners = compute_3d_box_corners(center, true_dims, rot_y, face_type=-1) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert side_points_3d is not None and side_points_2d is not None edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (3,), "edge_points_3d": side_points_3d, "edge_points_2d": side_points_2d, }, box_center_y_m=float(center[1]), regressed_dims=regressed_dims, ) assert edge_box is not None assert edge_box["mode"] == "side" assert np.isclose(float(edge_box["dims"][0]), float(true_dims[0]), atol=1e-4) assert np.isclose(float(edge_box["dims"][1]), float(regressed_dims[1]), atol=1e-5) assert np.isclose(float(edge_box["dims"][2]), float(regressed_dims[2]), atol=1e-5) expected_face_center = face_center_from_corners(corners, 3) assert expected_face_center is not None assert np.isclose(float(edge_box["center"][0]), float(expected_face_center[0]), atol=1e-4) assert np.isclose(float(edge_box["center"][2]), float(expected_face_center[2]), atol=1e-4) rebuilt_face_center = face_center_from_corners(edge_box["corners_3d"], 3) assert rebuilt_face_center is not None and expected_face_center is not None assert np.allclose(rebuilt_face_center, expected_face_center, atol=1e-4) def test_decode_edge_yaw_selection_single_side_face_uses_cut_cls_for_yaw_disambiguation(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-0.5, 0.0, 18.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.55 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([80.0, 120.0, 220.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 # cut_in corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=3, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert side_points_3d is not None and side_points_2d is not None _encode_edge_branch(pred_edge, 3, side_points_3d, side_points_2d, anchor, stride) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, max_faces=1, ) assert edge_selection["face_types"] == (3,) diff = (float(edge_selection["yaw"]) - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-4) def test_decode_edge_yaw_selection_single_side_face_left_cut_in_keeps_negative_yaw(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-4.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([0.0, 120.0, 80.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 # cut_in corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=3, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) side_points_3d, side_points_2d = project_partial_face_bottom_edge(corners, 3, calib, 640, 480, num_samples=5) assert side_points_3d is not None and side_points_2d is not None _encode_edge_branch(pred_edge, 3, side_points_3d, side_points_2d, anchor, stride) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, max_faces=1, ) assert edge_selection["face_types"] == (3,) diff = (float(edge_selection["yaw"]) - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-4) def test_decode_edge_yaw_selection_single_rear_face_cut_in_uses_reference_yaw_to_avoid_pi_flip(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-0.5, 0.0, 18.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([0.0, 120.0, 80.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 # cut_in corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=1, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) rear_points_3d, rear_points_2d = project_face_bottom_edge(corners, 1, calib, num_samples=5) assert rear_points_3d is not None and rear_points_2d is not None _encode_edge_branch(pred_edge, 1, rear_points_3d, rear_points_2d, anchor, stride) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, max_faces=1, ) assert edge_selection["face_types"] == (1,) diff = (float(edge_selection["yaw"]) - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-4) def test_reconstruct_edge_based_box_from_selection_falls_back_when_edge_metric_size_is_unstable(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([0.5, 0.0, 30.0], dtype=np.float32) dims = np.array([4.5, 1.5, 2.0], dtype=np.float32) rot_y = 0.6 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None inflated_front = front_points_3d.copy() inflated_side = side_points_3d.copy() front_mid = np.mean(inflated_front[:, [0, 2]], axis=0, keepdims=True) side_mid = np.mean(inflated_side[:, [0, 2]], axis=0, keepdims=True) inflated_front[:, [0, 2]] = front_mid + (inflated_front[:, [0, 2]] - front_mid) * 2.8 inflated_side[:, [0, 2]] = side_mid + (inflated_side[:, [0, 2]] - side_mid) * 2.8 edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0, 3), "face_is_partial": (False, False), "edge_points_3d": np.stack([inflated_front, inflated_side], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_center_y_m=float(center[1]), regressed_dims=dims, face_regressed_dims_by_type={ 0: {"height": float(dims[1]), "width": float(dims[2])}, 3: {"length": float(dims[0]), "height": float(dims[1])}, }, ) assert edge_box is not None assert np.allclose(edge_box["dims"], dims, atol=1e-4) assert edge_box["length_source"] == "regressed" assert edge_box["width_source"] == "regressed" def test_reconstruct_edge_based_box_from_selection_does_not_use_partial_edge_length_as_full_box_size(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-4.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None partial_side = side_points_3d.copy() full_len = np.linalg.norm(partial_side[-1, [0, 2]] - partial_side[0, [0, 2]]) partial_dir = partial_side[-1] - partial_side[0] partial_dir = partial_dir / np.linalg.norm(partial_dir) partial_side = partial_side[0] + np.linspace(0.0, float(full_len) * 0.875, 5, dtype=np.float32)[:, None] * partial_dir[None, :] edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0, 3), "face_is_partial": (False, True), "edge_points_3d": np.stack([front_points_3d, partial_side], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_center_y_m=float(center[1]), regressed_dims=dims, ) assert edge_box is not None assert np.isclose(float(edge_box["dims"][0]), float(dims[0]), atol=1e-4) assert np.isclose(float(edge_box["dims"][2]), float(dims[2]), atol=1e-4) assert edge_box["length_source"] == "regressed" assert edge_box["width_source"] == "edge" def test_reconstruct_edge_based_box_from_selection_ignores_face_size_priors_that_disagree_with_whole_box(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([0.5, 0.0, 30.0], dtype=np.float32) dims = np.array([4.5, 1.5, 2.0], dtype=np.float32) rot_y = 0.6 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None shrunk_front = front_points_3d.copy() shrunk_side = side_points_3d.copy() front_mid = np.mean(shrunk_front[:, [0, 2]], axis=0, keepdims=True) side_mid = np.mean(shrunk_side[:, [0, 2]], axis=0, keepdims=True) shrunk_front[:, [0, 2]] = front_mid + (shrunk_front[:, [0, 2]] - front_mid) * 0.7 shrunk_side[:, [0, 2]] = side_mid + (shrunk_side[:, [0, 2]] - side_mid) * 0.7 edge_box = reconstruct_edge_based_box_from_selection( { "yaw": float(rot_y), "face_types": (0, 3), "face_is_partial": (False, False), "edge_points_3d": np.stack([shrunk_front, shrunk_side], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), }, box_center_y_m=float(center[1]), regressed_dims=dims, face_regressed_dims_by_type={ 0: {"height": float(dims[1]), "width": float(dims[2] * 0.7)}, 3: {"length": float(dims[0] * 0.7), "height": float(dims[1])}, }, ) assert edge_box is not None assert np.allclose(edge_box["dims"], dims, atol=1e-4) assert edge_box["length_source"] == "regressed" assert edge_box["width_source"] == "regressed" def test_build_edge_heading_decoded_uses_edge_geometry_for_box_size(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.5, 0.0, 20.0], dtype=np.float32) true_dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) regressed_dims = np.array([6.5, 1.5, 2.6], dtype=np.float32) rot_y = 0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([120.0, 120.0, 240.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = regressed_dims pred[30] = 10.0 pred[34] = np.sin(rot_y) corners = compute_3d_box_corners(center, true_dims, rot_y, face_type=-1) for face_type, score in ((0, 0.95), (3, 0.9)): _encode_face_branch(pred, corners, face_type=face_type, score=score, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) for face_type in (0, 3): points_3d, points_2d = project_face_bottom_edge(corners, face_type, calib, num_samples=5) assert points_3d is not None and points_2d is not None _encode_edge_branch(pred_edge, face_type, points_3d, points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, img_h=480, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, edge_selection=edge_selection, ) assert edge_confident assert heading_decoded is not None diff = (edge_yaw - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-3) front_edge_3d, _ = project_face_bottom_edge(heading_decoded["corners_3d"], 0, calib, num_samples=5) side_edge_3d, _ = project_face_bottom_edge(heading_decoded["corners_3d"], 3, calib, num_samples=5) assert front_edge_3d is not None and side_edge_3d is not None rebuilt_width = float(np.linalg.norm(front_edge_3d[-1] - front_edge_3d[0])) rebuilt_length = float(np.linalg.norm(side_edge_3d[-1] - side_edge_3d[0])) assert np.isclose(rebuilt_length, float(true_dims[0]), atol=1e-4) assert np.isclose(rebuilt_width, float(true_dims[2]), atol=1e-4) assert not np.isclose(rebuilt_length, float(regressed_dims[0]), atol=1e-3) assert not np.isclose(rebuilt_width, float(regressed_dims[2]), atol=1e-3) def test_build_edge_heading_decoded_keeps_same_best_score_face_anchor_as_direct_box(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([0.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([120.0, 120.0, 240.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) for face_type, score in ((0, 0.95), (1, 0.99), (3, 0.80)): _encode_face_branch(pred, corners, face_type=face_type, score=score, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) for face_type in (0, 1, 3): points_3d, points_2d = project_face_bottom_edge(corners, face_type, calib, num_samples=5) assert points_3d is not None and points_2d is not None _encode_edge_branch(pred_edge, face_type, points_3d, points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, img_h=480, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, edge_selection=edge_selection, ) assert decoded is not None assert heading_decoded is not None assert edge_confident assert edge_selection["face_types"] == (1, 3) # Direct-yaw and edge-yaw reconstruction should share the same score-chosen face anchor; only yaw changes. assert heading_decoded["visible_face_type"] == decoded["visible_face_type"] == 1 diff = (edge_yaw - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-5), edge_yaw def test_build_edge_heading_decoded_keeps_primary_face_when_edge_points_leak_outside_image(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-12.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.9 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert float(np.min(front_points_2d[:, 0])) < 0.0 _encode_edge_branch(pred_edge, 0, front_points_3d, front_points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=None, calib=calib, img_w=640, img_h=480, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, edge_selection=edge_selection, ) assert decoded is not None assert edge_selection["face_types"] == (0,) assert heading_decoded is not None assert edge_confident diff = (edge_yaw - rot_y + np.pi) % (2 * np.pi) - np.pi assert np.isclose(diff, 0.0, atol=1e-4) def test_selected_edge_residual_stats_are_zero_for_matching_reprojected_edges(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([0.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) yaw = 0.75 corners = compute_3d_box_corners(center, dims, yaw, face_type=-1) edge_points_3d, edge_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) assert edge_points_3d is not None and edge_points_2d is not None projected = _project_selected_face_edges_from_box( corners, face_types=(0,), face_is_partial=(False,), calib=calib, img_w=640, img_h=480, ) stats = _selected_edge_residual_stats(edge_points_2d, projected) assert stats["available"] is True assert np.isclose(stats["mean_px"], 0.0, atol=1e-6) assert np.isclose(stats["max_px"], 0.0, atol=1e-6) def test_build_edge_heading_decoded_rejects_far_lateral_edge_yaw(): threshold_m = 5.0 calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([6.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([200.0, 120.0, 320.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.9, anchor=anchor, stride=stride, calib=calib) _encode_face_branch(pred, corners, face_type=3, score=0.85, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) for face_type in (0, 3): points_3d, points_2d = project_face_bottom_edge(corners, face_type, calib, num_samples=5) assert points_3d is not None and points_2d is not None _encode_edge_branch(pred_edge, face_type, points_3d, points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=threshold_m, ) assert whole_attrs is not None assert float(abs(whole_attrs["center"][0])) > threshold_m assert np.isfinite(edge_yaw) assert heading_decoded is None assert not edge_confident def test_build_edge_heading_decoded_reconstructs_single_front_face_from_edge_and_regressed_length(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-2.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.35 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([160.0, 120.0, 260.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.9, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) points_3d, points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) assert points_3d is not None and points_2d is not None _encode_edge_branch(pred_edge, 0, points_3d, points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) assert decoded is not None assert decoded["visible_face_types"] == (0,) assert heading_decoded is not None assert np.isfinite(edge_yaw) assert edge_confident rebuilt_front_edge_3d, _ = project_face_bottom_edge(heading_decoded["corners_3d"], 0, calib, num_samples=5) assert rebuilt_front_edge_3d is not None rebuilt_width = float(np.linalg.norm(rebuilt_front_edge_3d[-1] - rebuilt_front_edge_3d[0])) assert np.isclose(rebuilt_width, float(dims[2]), atol=1e-4) def test_build_edge_heading_decoded_reconstructs_cut_object_from_single_front_face_when_side_edge_invalid(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-4.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([0.0, 120.0, 80.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.95, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, _ = project_partial_face_bottom_edge(corners, 3, calib, 640, 480, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None short_len = float(dims[0] * 0.4) side_dir = side_points_3d[-1] - side_points_3d[0] side_dir = side_dir / np.linalg.norm(side_dir) short_side_points_3d = side_points_3d[0] + np.linspace(0.0, short_len, 5, dtype=np.float32)[:, None] * side_dir[None, :] short_side_points_2d = project_3d_to_2d(short_side_points_3d, calib) _encode_edge_branch(pred_edge, 0, front_points_3d, front_points_2d, anchor, stride) _encode_edge_branch(pred_edge, 3, short_side_points_3d, short_side_points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) edge_selection = decode_edge_yaw_selection_from_prediction( pred, pred_edge, anchor, stride, calib, bbox_xyxy=bbox_xyxy, img_w=640, img_h=480, max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, img_h=480, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, edge_selection=edge_selection, ) assert edge_selection["is_valid"] is False assert edge_selection["face_types"] == (0,) assert heading_decoded is not None assert np.isfinite(edge_yaw) assert edge_confident def test_build_edge_heading_decoded_limits_near_cut_boxes_to_two_edge_yaw_faces(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([-4.0, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = -0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([140.0, 120.0, 260.0, 240.0], dtype=np.float32) pred = np.zeros(41, dtype=np.float32) pred[24] = center[2] pred[25:27] = [center[0] / center[2] * calib["fx"] / stride + (calib["cx"] / stride - anchor[0]), 0.0] pred[27:30] = dims pred[30] = 10.0 pred[34] = np.sin(rot_y) pred[39] = 10.0 # cut_in-like, but not actually clipped at the border corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) _encode_face_branch(pred, corners, face_type=0, score=0.82, anchor=anchor, stride=stride, calib=calib) _encode_face_branch(pred, corners, face_type=1, score=0.95, anchor=anchor, stride=stride, calib=calib) _encode_face_branch(pred, corners, face_type=3, score=0.9, anchor=anchor, stride=stride, calib=calib) pred_edge = np.zeros(60, dtype=np.float32) for face_type in (0, 1, 3): points_3d, points_2d = project_face_bottom_edge(corners, face_type, calib, num_samples=5) assert points_3d is not None and points_2d is not None _encode_edge_branch(pred_edge, face_type, points_3d, points_2d, anchor, stride) decoded = decode_3d_prediction( pred, anchor, stride, calib, 640, 480, {0}, set(), 0, pred_edge_60=pred_edge, bbox_xyxy=bbox_xyxy, ) whole_attrs = extract_3d_attrs_from_prediction(pred, anchor, stride, calib, pred_edge_60=pred_edge) heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded=decoded, pred_41=pred, pred_edge_60=pred_edge, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, whole_attrs=whole_attrs, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, ) assert decoded is not None assert decoded["visible_face_types"] == (0, 1, 3) assert edge_confident assert np.isfinite(edge_yaw) assert heading_decoded is not None assert heading_decoded["visible_face_types"] == (0, 3) assert np.asarray(heading_decoded["edge_points_2d"], dtype=np.float32).shape == (2, 5, 2) def test_build_edge_heading_decoded_uses_resolved_side_face_type_for_edge_fit(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([1.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) rot_y = 0.75 anchor = np.array([10.0, 20.0], dtype=np.float32) stride = 8.0 bbox_xyxy = np.array([120.0, 120.0, 240.0, 240.0], dtype=np.float32) corners = compute_3d_box_corners(center, dims, rot_y, face_type=-1) front_points_3d, front_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) side_points_3d, side_points_2d = project_face_bottom_edge(corners, 3, calib, num_samples=5) assert front_points_3d is not None and front_points_2d is not None assert side_points_3d is not None and side_points_2d is not None pred = np.zeros(41, dtype=np.float32) pred[27:30] = dims edge_selection = { "yaw": float(rot_y), "face_types": (0, 2), "face_is_partial": (False, False), "edge_points_3d": np.stack([front_points_3d, side_points_3d], axis=0), "edge_points_2d": np.stack([front_points_2d, side_points_2d], axis=0), "lateral_ok": True, } heading_decoded, edge_yaw, edge_confident = _build_edge_heading_decoded( base_decoded={}, pred_41=pred, pred_edge_60=None, anchor_xy=anchor, stride=stride, bbox_xyxy=bbox_xyxy, calib=calib, img_w=640, img_h=480, whole_attrs=None, edge_yaw_max_lateral_dist_m=DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M, edge_selection=edge_selection, ) assert edge_confident assert np.isclose(edge_yaw, rot_y, atol=1e-5) assert heading_decoded is not None assert heading_decoded["visible_face_types"] == (0, 3) edge_box_selected_edges_2d = _project_selected_face_edges_from_box( heading_decoded["corners_3d"], heading_decoded["visible_face_types"], edge_selection["face_is_partial"], calib, 640, 480, ) edge_fit = _selected_edge_residual_stats(edge_selection["edge_points_2d"], edge_box_selected_edges_2d) assert edge_fit["available"] is True assert edge_fit["max_px"] is not None and edge_fit["max_px"] < 1e-3 def test_add_two_roi_inference_args_includes_edge_yaw_lateral_threshold(): parser = argparse.ArgumentParser() add_two_roi_inference_args(parser, include_output_dir=False) args = parser.parse_args([]) assert args.edge_yaw_max_lateral_dist == DEFAULT_EDGE_YAW_MAX_LATERAL_DIST_M def test_make_record_preserves_badcase_geometry_shapes_for_visualization(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([0.5, 0.0, 20.0], dtype=np.float32) pred_center = center + np.array([0.3, 0.1, 0.2], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) yaw = 0.2 pred_yaw = 0.35 corners = compute_3d_box_corners(center, dims, yaw, face_type=-1).astype(np.float32) pred_corners = compute_3d_box_corners(pred_center, dims, pred_yaw, face_type=-1).astype(np.float32) face_center = face_center_from_corners(corners, 0).astype(np.float32) pred_face_center = face_center_from_corners(pred_corners, 0).astype(np.float32) edge_points_3d, edge_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) assert edge_points_3d is not None assert edge_points_2d is not None gt_attrs = { "center": center, "depth": float(center[2]), "dims": dims, "yaw": yaw, "visible_face_type": 0, "face_center": face_center, "corners_3d": corners, } pred_attrs = { "center": pred_center, "depth": float(pred_center[2]), "dims": dims, "yaw": pred_yaw, "visible_face_type": 0, "face_center": pred_face_center, "corners_3d": pred_corners, } gt_decoded = { "face_center_2d": project_3d_to_2d(face_center[None, :], calib)[0], "face_color": (0, 0, 255), "visible_face_types": (0,), "edge_points_2d": edge_points_2d, } pred_decoded = { "face_center_2d": project_3d_to_2d(pred_face_center[None, :], calib)[0], "face_color": (0, 255, 0), "visible_face_types": (0,), "edge_points_2d": edge_points_2d, } record = make_record( sample_index=0, roi_name="roi0", image_path=Path("frame.png"), label_path=Path("frame.txt"), cls_name="car", gt_index=0, pred_index=0, gt_box=np.array([100.0, 120.0, 220.0, 260.0], dtype=np.float32), pred_box=np.array([102.0, 121.0, 222.0, 261.0], dtype=np.float32), match_iou=0.9, prediction={"cls_id": 0, "confidence": 0.95}, gt_attrs=gt_attrs, pred_attrs=pred_attrs, gt_decoded=gt_decoded, pred_decoded=pred_decoded, gt_visible_faces=[(0, np.zeros(8, dtype=np.float32))], gt_visible_yaw=yaw, pred_edge_visible_yaw=pred_yaw, is_cut_object_flag=False, position_eligible=True, yaw_compare_max_lateral_dist_m=5.0, ) assert np.asarray(record["gt_corners"], dtype=np.float32).shape == (8, 3) assert np.asarray(record["pred_corners"], dtype=np.float32).shape == (8, 3) assert np.asarray(record["gt_edge_points_2d"], dtype=np.float32).shape == (5, 2) assert np.asarray(record["pred_edge_points_2d"], dtype=np.float32).shape == (5, 2) draw_kwargs = build_badcase_draw_kwargs(record["gt_corners"], calib, visible_face_type=0, visible_face_types=[0]) assert "edge_points_2d" in draw_kwargs def test_make_record_invalidates_side_edge_length_for_front_rear_only_edge_box(): center = np.array([0.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) attrs = { "center": center, "depth": float(center[2]), "dims": dims, "yaw": 0.0, "visible_face_type": 0, "face_center": center, "corners_3d": np.zeros((8, 3), dtype=np.float32), } decoded = {"visible_face_types": (0,), "face_center_2d": None, "face_color": None, "edge_points_2d": None} record = make_record( sample_index=0, roi_name="roi1", image_path=Path("frame.png"), label_path=Path("frame.txt"), cls_name="car", gt_index=0, pred_index=0, gt_box=np.array([0.0, 0.0, 10.0, 10.0], dtype=np.float32), pred_box=np.array([0.0, 0.0, 10.0, 10.0], dtype=np.float32), match_iou=1.0, prediction={"cls_id": 0, "confidence": 0.95}, gt_attrs=attrs, pred_attrs=attrs, gt_decoded=decoded, pred_decoded=decoded, gt_visible_faces=[(0, np.zeros(8, dtype=np.float32))], gt_visible_yaw=0.0, pred_edge_visible_yaw=0.0, pred_edge_bucket_visible_yaw=0.0, pred_edge_box={"mode": "front-rear", "dims": np.array([9.9, 1.5, 1.8], dtype=np.float32)}, is_cut_object_flag=False, position_eligible=True, yaw_compare_max_lateral_dist_m=5.0, pred_yaw_compare_face_types=(0,), pred_yaw_compare_valid=False, ) assert record["pred_edge_box_mode"] == "front-rear" assert record["pred_edge_length_m"] is None assert record["edge_length_abs_err_m"] is None def test_make_record_tracks_strict_yaw_compare_face_bucket_metadata_separately(): calib = {"fx": 500.0, "fy": 500.0, "cx": 320.0, "cy": 240.0} center = np.array([0.5, 0.0, 20.0], dtype=np.float32) dims = np.array([4.0, 1.5, 1.8], dtype=np.float32) yaw = 0.2 corners = compute_3d_box_corners(center, dims, yaw, face_type=-1).astype(np.float32) face_center = face_center_from_corners(corners, 0).astype(np.float32) side_center = face_center_from_corners(corners, 3).astype(np.float32) edge_points_3d, edge_points_2d = project_face_bottom_edge(corners, 0, calib, num_samples=5) assert edge_points_3d is not None and edge_points_2d is not None attrs = { "center": center, "depth": float(center[2]), "dims": dims, "yaw": yaw, "visible_face_type": 0, "face_center": face_center, "corners_3d": corners, } decoded = { "face_center_2d": project_3d_to_2d(face_center[None, :], calib)[0], "face_color": (0, 0, 255), "visible_face_types": (0, 3), "edge_points_2d": edge_points_2d, } record = make_record( sample_index=0, roi_name="roi0", image_path=Path("frame.png"), label_path=Path("frame.txt"), cls_name="car", gt_index=0, pred_index=0, gt_box=np.array([100.0, 120.0, 220.0, 260.0], dtype=np.float32), pred_box=np.array([100.0, 120.0, 220.0, 260.0], dtype=np.float32), match_iou=1.0, prediction={"cls_id": 0, "confidence": 0.95}, gt_attrs=attrs, pred_attrs=attrs, gt_decoded=decoded, pred_decoded=decoded, gt_visible_faces=[(0, np.zeros(8, dtype=np.float32)), (3, np.zeros(8, dtype=np.float32))], gt_visible_yaw=yaw, pred_edge_visible_yaw=yaw, is_cut_object_flag=False, position_eligible=True, yaw_compare_max_lateral_dist_m=5.0, pred_yaw_compare_face_types=(0,), pred_yaw_compare_valid=False, ) assert record["visible_face_count"] == 2 assert record["has_side_face_visible"] is True assert record["yaw_compare_visible_face_count"] == 1 assert record["yaw_compare_has_side_face_visible"] is False assert record["yaw_compare_visible_faces"] == "front" assert record["yaw_compare_face_bucket"] == "front_rear_only" assert record["yaw_compare_pred_valid"] is False def test_interval_label_supports_metric_units(): assert interval_label(5.0, 1.0, unit="deg") == "[5,6)deg" assert interval_label(0.5, 0.5, unit="m") == "[0.5,1.0)m" def test_select_interval_visual_records_round_robins_high_error_bins_first(): stores = make_interval_visual_reservoirs() add_rng = random.Random(0) for value in (5.2, 5.4, 6.2, 6.4, 7.2, 7.4): add_interval_visual_record( stores, value=value, record={"value": value}, bin_width=1.0, per_bin_capacity=10, rng=add_rng, ) selected = select_interval_visual_records(stores, max_total=5, rng=random.Random(1), reverse=True) assert list(sorted(selected.keys(), reverse=True)) == [7.0, 6.0, 5.0] assert sum(len(records) for records in selected.values()) == 5 assert len(selected[7.0]) == 2 assert len(selected[6.0]) == 2 assert len(selected[5.0]) == 1