diff --git a/pipeline/2_Multiview.py b/pipeline/2_Multiview.py index 712a981..84ea3b5 100644 --- a/pipeline/2_Multiview.py +++ b/pipeline/2_Multiview.py @@ -149,9 +149,9 @@ class ObservationQualityConfig: sharpness_ref: float = 2500.0 homography_ref: float = 0.18 - # factor f in min(1, q + f) - # f = 1 -> factor disabled / neutral - # f = 0 -> factor fully active + # factor f scales the effect of each quality indicator: + # f = 1 -> indicator is fully active + # f = 0 -> indicator is ignored (neutral weight = 1) size_factor: float = 1.0 aspect_factor: float = 1.0 border_factor: float = 1.0 @@ -341,9 +341,12 @@ def compute_marker_world_corners(marker: Dict[str, Any], link_transforms: Dict[s # ----------------------------------------------------------------------------- def quality_factor(q: float, f: float) -> float: - # Saturating factor in [0, 1]. - # f = 1.0 -> ignore this q-indicator completely. - return clamp01(q + f) + # Interpret f in [0, 1] as the per-indicator influence. + # f = 1.0 -> indicator is fully active; q is applied. + # f = 0.0 -> indicator is ignored and contributes a neutral weight of 1.0. + q = clamp01(q) + f = clamp01(f) + return 1.0 - f + f * q def projective_homography_quality(image_points_px: np.ndarray, image_shape: Tuple[int, int], ref: float) -> float: diff --git a/pipeline/2_Multiview_ersteVersion.py b/pipeline/2_Multiview_ersteVersion.py new file mode 100644 index 0000000..59c3b1e --- /dev/null +++ b/pipeline/2_Multiview_ersteVersion.py @@ -0,0 +1,706 @@ +#!/usr/bin/env python3 + +""" +============================================================ +STEP 2b — Simultane Multiview-Optimierung für Roboterpose +============================================================ + +Ziel: + Aus mehreren ArUco-Detektionsdateien die gemeinsame + Roboterpose (x,y,z,a,b,c,e) schätzen und jede Kamera-Pose + sowie Marker-Weltpositionen ausgeben. + +Eingabe: + --robot ../robot.json + --detections render_1a_aruco_detection.json render_1b_aruco_detection.json ... + --outDir . + +Ausgabe: + multiview_pose.json + +Hinweis: + Dieses Skript verwendet die Markerpositionen aus robot.json + als kinematische Constraints und optimiert gleichzeitig: + - Roboterzustand (x,y,z,a,b,c,e) + - Kameraextrinsische Parameter pro Bild + +""" + +import argparse +import datetime +import json +import math +import os +import time +from pathlib import Path +from typing import Any, Dict, List, Tuple + +import cv2 +import numpy as np +from scipy.optimize import least_squares + +STATE_KEYS = ["x", "y", "z", "a", "b", "c", "e"] + + +# ------------------------------------------------------------------ +# JSON helpers +# ------------------------------------------------------------------ + +def load_json(path: str) -> Dict[str, Any]: + with open(path, 'r', encoding='utf-8') as f: + return json.load(f) + + +def save_json(data: Dict[str, Any], path: Path) -> None: + with open(path, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2) + + +# ------------------------------------------------------------------ +# robot.json helpers +# ------------------------------------------------------------------ + +def resolve_scalar(value: Any, default: float = 0.0) -> float: + if value is None: + return default + if isinstance(value, (int, float)): + return float(value) + try: + return float(str(value).strip()) + except ValueError: + return default + + +def resolve_vector(value: Any, default_len: int = 3) -> Tuple[float, ...]: + if value is None: + return tuple(0.0 for _ in range(default_len)) + if isinstance(value, (int, float, str)): + return (resolve_scalar(value),) + tuple(0.0 for _ in range(default_len - 1)) + if isinstance(value, (list, tuple)): + resolved = [resolve_scalar(v) for v in value] + if len(resolved) < default_len: + resolved.extend([0.0] * (default_len - len(resolved))) + return tuple(resolved[:default_len]) + return tuple(0.0 for _ in range(default_len)) + + +def parse_metric_scale(robot: Dict[str, Any]) -> float: + rendering_info = robot.get('renderingInfo', {}) or {} + metric = rendering_info.get('metric', 'mm') + return 0.001 if str(metric).strip().lower() == 'mm' else 1.0 + + +def normalize_axis(axis: Any) -> np.ndarray: + vec = np.asarray(axis, dtype=np.float64) + if vec.shape != (3,): + vec = vec.reshape(-1)[:3] + norm = np.linalg.norm(vec) + return vec / max(norm, 1e-9) + + +def euler_deg_to_matrix(euler_deg: Any) -> np.ndarray: + x_deg, y_deg, z_deg = resolve_vector(euler_deg, 3) + x = math.radians(x_deg) + y = math.radians(y_deg) + z = math.radians(z_deg) + + cx = math.cos(x) + sx = math.sin(x) + cy = math.cos(y) + sy = math.sin(y) + cz = math.cos(z) + sz = math.sin(z) + + Rx = np.array([ + [1.0, 0.0, 0.0], + [0.0, cx, -sx], + [0.0, sx, cx] + ], dtype=np.float64) + + Ry = np.array([ + [cy, 0.0, sy], + [0.0, 1.0, 0.0], + [-sy, 0.0, cy] + ], dtype=np.float64) + + Rz = np.array([ + [cz, -sz, 0.0], + [sz, cz, 0.0], + [0.0, 0.0, 1.0] + ], dtype=np.float64) + + return Rz @ Ry @ Rx + + +def transform_from_translation_rotation(translation: Any, rotation_deg: Any) -> np.ndarray: + T = np.eye(4, dtype=np.float64) + pos = np.asarray(resolve_vector(translation, 3), dtype=np.float64) + T[:3, 3] = pos + T[:3, :3] = euler_deg_to_matrix(rotation_deg) + return T + + +def axis_angle_matrix(axis: Any, angle_deg: float) -> np.ndarray: + axis_vec = normalize_axis(axis) + theta = math.radians(angle_deg) + kx, ky, kz = axis_vec + c = math.cos(theta) + s = math.sin(theta) + v = 1.0 - c + R = np.array([ + [kx * kx * v + c, kx * ky * v - kz * s, kx * kz * v + ky * s], + [ky * kx * v + kz * s, ky * ky * v + c, ky * kz * v - kx * s], + [kz * kx * v - ky * s, kz * ky * v + kx * s, kz * kz * v + c] + ], dtype=np.float64) + T = np.eye(4, dtype=np.float64) + T[:3, :3] = R + return T + + +# ------------------------------------------------------------------ +# Kinematics and marker extraction +# ------------------------------------------------------------------ + +def extract_markers(robot: Dict[str, Any], scale: float) -> Dict[int, Dict[str, Any]]: + markers = {} + links = robot.get('links', {}) or {} + marker_defaults = (robot.get('renderingInfo', {}) or {}).get('markerDefaults', {}) or {} + default_size_mm = float(marker_defaults.get('size', 25.0)) + + for link_name, link_info in links.items(): + for marker in link_info.get('markers', []) or []: + marker_id = int(marker.get('id', -1)) + if marker_id < 0: + continue + + pos = resolve_vector(marker.get('position', [0, 0, 0]), 3) + size_mm = float(marker.get('size', default_size_mm)) + markers[marker_id] = { + 'marker_id': marker_id, + 'link_name': link_name, + 'position_m': np.asarray([pos[0] * scale, pos[1] * scale, pos[2] * scale], dtype=np.float64), + 'normal': normalize_axis(resolve_vector(marker.get('normal', [0, 0, 1]), 3)), + 'spin_deg': float(marker.get('spin', 0.0)), + 'size_m': size_mm * scale, + } + + return markers + + +def marker_plane_axes(normal: np.ndarray, spin_deg: float) -> Tuple[np.ndarray, np.ndarray]: + n = normalize_axis(normal) + candidate = np.array((0.0, 0.0, 1.0), dtype=np.float64) + if abs(np.dot(n, candidate)) > 0.99: + candidate = np.array((1.0, 0.0, 0.0), dtype=np.float64) + + x_dir = np.cross(candidate, n) + x_dir /= max(np.linalg.norm(x_dir), 1e-9) + y_dir = np.cross(n, x_dir) + + if abs(spin_deg) > 1e-6: + theta = math.radians(spin_deg) + cos_t = math.cos(theta) + sin_t = math.sin(theta) + x_rot = x_dir * cos_t + np.cross(n, x_dir) * sin_t + n * np.dot(n, x_dir) * (1.0 - cos_t) + y_rot = y_dir * cos_t + np.cross(n, y_dir) * sin_t + n * np.dot(n, y_dir) * (1.0 - cos_t) + return x_rot, y_rot + + return x_dir, y_dir + + +def marker_object_corners(marker: Dict[str, Any]) -> np.ndarray: + half = marker['size_m'] * 0.5 + x_dir, y_dir = marker_plane_axes(marker['normal'], marker['spin_deg']) + corners = np.stack([ + -x_dir * half + y_dir * half, + x_dir * half + y_dir * half, + x_dir * half - y_dir * half, + -x_dir * half - y_dir * half + ], axis=0) + return marker['position_m'].reshape(1, 3) + corners + + +def build_link_chain(robot: Dict[str, Any]) -> List[str]: + links = robot.get('links', {}) or {} + ordered: List[str] = [] + remaining = set(links.keys()) + + while remaining: + progress = False + for name in list(remaining): + parent = links[name].get('parent') + if not parent or parent in ordered: + ordered.append(name) + remaining.remove(name) + progress = True + if not progress: + raise RuntimeError('Cycle detected in robot link tree or missing parent link') + return ordered + + +def compute_link_transforms(robot: Dict[str, Any], state: Dict[str, float], scale: float) -> Dict[str, np.ndarray]: + links = robot.get('links', {}) or {} + ordered_links = build_link_chain(robot) + transforms: Dict[str, np.ndarray] = {} + + for link_name in ordered_links: + link_info = links[link_name] or {} + parent_name = link_info.get('parent') + parent_transform = transforms[parent_name] if parent_name else np.eye(4, dtype=np.float64) + + mount_translation = np.asarray(resolve_vector(link_info.get('mountPosition', [0, 0, 0]), 3), dtype=np.float64) * scale + mount = transform_from_translation_rotation( + mount_translation, + link_info.get('mountRotation', [0, 0, 0]) + ) + + joint_info = link_info.get('jointToParent', {}) or {} + joint_origin = np.asarray(resolve_vector(joint_info.get('origin', [0, 0, 0]), 3), dtype=np.float64) * scale + joint = transform_from_translation_rotation( + joint_origin, + joint_info.get('rotation', [0, 0, 0]) + ) + + motion = np.eye(4, dtype=np.float64) + joint_type = str(joint_info.get('type', 'fixed')).strip().lower() + control_var = str(joint_info.get('variable', joint_info.get('control', ''))).strip().lower() + axis = resolve_vector(joint_info.get('axis', [1, 0, 0]), 3) + + if joint_type == 'linear': + motion[:3, 3] = normalize_axis(axis) * state.get(control_var, 0.0) * scale + elif joint_type == 'revolute': + motion = axis_angle_matrix(axis, state.get(control_var, 0.0)) + + transforms[link_name] = parent_transform @ mount @ joint @ motion + + return transforms + + +def compute_marker_world_position(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + link_transform = link_transforms[marker['link_name']] + local = np.ones(4, dtype=np.float64) + local[:3] = marker['position_m'] + world = link_transform @ local + return world[:3] + + +# ------------------------------------------------------------------ +# Camera / observation helpers +# ------------------------------------------------------------------ + +def load_intrinsics(detection_json: Dict[str, Any]) -> Tuple[np.ndarray, np.ndarray]: + cam = detection_json['camera'] + K = np.asarray(cam['camera_matrix'], dtype=np.float64) + D = np.asarray(cam.get('distortion_coefficients', [0, 0, 0, 0, 0]), dtype=np.float64).reshape(-1, 1) + return K, D + + +def collect_views_and_observations( + detection_files: List[str], + robot_markers: Dict[int, Dict[str, Any]] +) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]: + views: List[Dict[str, Any]] = [] + observations: List[Dict[str, Any]] = [] + + for idx, det_path in enumerate(detection_files): + detection_json = load_json(det_path) + K, D = load_intrinsics(detection_json) + views.append({ + 'index': idx, + 'source_file': os.path.abspath(det_path), + 'camera_id': detection_json.get('camera', {}).get('camera_id', f'cam{idx+1}'), + 'image_file': detection_json.get('image', {}).get('image_file'), + 'K': K, + 'D': D + }) + + for det in detection_json.get('detections', []) or []: + marker_id = int(det.get('marker_id', -1)) + if marker_id < 0 or marker_id not in robot_markers: + continue + + image_points = det.get('image_points_px') + if isinstance(image_points, list) and len(image_points) == 4: + image_points = np.asarray(image_points, dtype=np.float64) + else: + center = resolve_vector(det.get('center_px', [0, 0]), 2) + image_points = np.asarray([center], dtype=np.float64) + + confidence = float(det.get('confidence', 1.0)) + marker = robot_markers[marker_id] + observations.append({ + 'view_index': idx, + 'marker_id': marker_id, + 'marker_link_corners': marker_object_corners(marker), + 'image_points_px': image_points, + 'confidence': max(0.01, min(1.0, confidence)) + }) + + if len(views) == 0: + raise RuntimeError('No valid detection views found') + + if len(observations) == 0: + raise RuntimeError('No marker observations matched robot.json markers') + + return views, observations + + +def compute_marker_world_corners(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + link_transform = link_transforms[marker['link_name']] + local = marker_object_corners(marker) + homogeneous = np.concatenate([local, np.ones((local.shape[0], 1), dtype=np.float64)], axis=1) + world = (link_transform @ homogeneous.T).T + return world[:, :3] + + +def initial_camera_guess( + view: Dict[str, Any], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + default_state: Dict[str, float], + scale: float, + robot: Dict[str, Any] +) -> Tuple[np.ndarray, np.ndarray]: + object_points = [] + image_points = [] + + link_transforms = compute_link_transforms(robot, default_state, scale) + + for obs in observations: + if obs['view_index'] != view['index']: + continue + marker = robot_markers[obs['marker_id']] + object_points.append(compute_marker_world_corners(marker, link_transforms)) + image_points.append(obs['image_points_px']) + + if len(object_points) == 0: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + object_points = np.vstack(object_points) + image_points = np.vstack(image_points) + + if object_points.shape[0] < 4: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + success, rvec, tvec = cv2.solvePnP( + object_points, + image_points, + view['K'], + view['D'], + flags=cv2.SOLVEPNP_ITERATIVE + ) + + if not success: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + return rvec, tvec + + +def project_points( + points_3d: np.ndarray, + rvec: np.ndarray, + tvec: np.ndarray, + K: np.ndarray, + D: np.ndarray +) -> np.ndarray: + projected, _ = cv2.projectPoints(points_3d, rvec, tvec, K, D) + return projected.reshape(-1, 2) + + +# ------------------------------------------------------------------ +# Optimization +# ------------------------------------------------------------------ + +def pack_parameters(robot_state: Dict[str, float], camera_params: List[Tuple[np.ndarray, np.ndarray]]) -> np.ndarray: + state_vec = np.asarray([robot_state[k] for k in STATE_KEYS], dtype=np.float64) + cams = [] + for rvec, tvec in camera_params: + cams.append(rvec.reshape(3)) + cams.append(tvec.reshape(3)) + return np.concatenate([state_vec] + cams) + + +def unpack_parameters(params: np.ndarray, n_views: int) -> Tuple[Dict[str, float], List[Tuple[np.ndarray, np.ndarray]]]: + robot_state = {STATE_KEYS[i]: float(params[i]) for i in range(len(STATE_KEYS))} + camera_params = [] + offset = len(STATE_KEYS) + for _ in range(n_views): + rvec = params[offset:offset + 3].reshape(3, 1) + tvec = params[offset + 3:offset + 6].reshape(3, 1) + camera_params.append((rvec, tvec)) + offset += 6 + return robot_state, camera_params + + +def residuals_for_parameters( + params: np.ndarray, + views: List[Dict[str, Any]], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + robot: Dict[str, Any], + scale: float, + default_state: Dict[str, float] +) -> np.ndarray: + robot_state, camera_params = unpack_parameters(params, len(views)) + link_transforms = compute_link_transforms(robot, robot_state, scale) + + residuals = [] + for obs in observations: + marker = robot_markers[obs['marker_id']] + world_corners = compute_marker_world_corners(marker, link_transforms) + rvec, tvec = camera_params[obs['view_index']] + proj = project_points(world_corners, rvec, tvec, views[obs['view_index']]['K'], views[obs['view_index']]['D']) + diffs = proj - obs['image_points_px'] + weight = math.sqrt(obs['confidence']) + residuals.extend((diffs * weight).reshape(-1)) + + for key in STATE_KEYS: + diff = robot_state[key] - default_state.get(key, 0.0) + if key in ('x', 'y', 'z', 'e'): + w = 0.001 + else: + w = 0.01 + residuals.append(diff * w) + + return np.asarray(residuals, dtype=np.float64) + + +def estimate_uncertainty(result: Any, n_params: int) -> np.ndarray: + if result.jac is None: + return np.full(n_params, float('nan'), dtype=np.float64) + J = result.jac + m, n = J.shape + JTJ = J.T @ J + try: + cov = np.linalg.pinv(JTJ) + except np.linalg.LinAlgError: + cov = np.linalg.pinv(JTJ + np.eye(n) * 1e-9) + residuals = result.fun + dof = max(1, m - n) + sigma2 = float(np.sum(residuals ** 2) / dof) + cov *= sigma2 + return np.sqrt(np.diag(cov)) + + +# ------------------------------------------------------------------ +# Output assembly +# ------------------------------------------------------------------ + +def camera_position_world(rvec: np.ndarray, tvec: np.ndarray) -> np.ndarray: + R, _ = cv2.Rodrigues(rvec) + return (-R.T @ tvec).reshape(3) + + +def build_output( + robot_state: Dict[str, float], + state_uncertainty: np.ndarray, + views: List[Dict[str, Any]], + camera_params: List[Tuple[np.ndarray, np.ndarray]], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + scale: float, + robot: Dict[str, Any], + robot_json_path: str +) -> Dict[str, Any]: + link_transforms = compute_link_transforms(robot, robot_state, scale) + + marker_summary: Dict[int, Dict[str, Any]] = {} + for marker_id, marker in robot_markers.items(): + marker_summary[marker_id] = { + 'marker_id': marker_id, + 'link_name': marker['link_name'], + 'position_world_m': compute_marker_world_position(marker, link_transforms).tolist(), + 'size_m': marker['size_m'], + 'observation_count': 0, + 'mean_confidence': None, + 'mean_reprojection_error_px': None, + 'observations': [] + } + + per_marker_errors: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + per_marker_confidences: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + + link_transforms = compute_link_transforms(robot, robot_state, scale) + for obs in observations: + marker_id = obs['marker_id'] + marker = robot_markers[marker_id] + object_points_m = compute_marker_world_corners(marker, link_transforms) + rvec, tvec = camera_params[obs['view_index']] + proj = project_points(object_points_m, rvec, tvec, views[obs['view_index']]['K'], views[obs['view_index']]['D']) + diffs = proj - obs['image_points_px'] + errors = np.linalg.norm(diffs, axis=1) + repro_error = float(np.mean(errors)) + per_marker_errors[marker_id].extend(errors.tolist()) + per_marker_confidences[marker_id].append(obs['confidence']) + marker_summary[marker_id]['observation_count'] += 1 + marker_summary[marker_id]['observations'].append({ + 'view_index': obs['view_index'], + 'source_file': views[obs['view_index']]['source_file'], + 'image_file': views[obs['view_index']]['image_file'], + 'confidence': obs['confidence'], + 'mean_reprojection_error_px': repro_error, + 'corner_reprojection_errors_px': errors.tolist() + }) + + for marker_id, summary in marker_summary.items(): + if summary['observation_count'] > 0: + summary['mean_confidence'] = float(np.mean(per_marker_confidences[marker_id])) + summary['mean_reprojection_error_px'] = float(np.mean(per_marker_errors[marker_id])) + + camera_outputs = [] + for idx, view in enumerate(views): + rvec, tvec = camera_params[idx] + cam_pos = camera_position_world(rvec, tvec) + observed_count = sum(1 for obs in observations if obs['view_index'] == idx) + camera_outputs.append({ + 'view_index': idx, + 'source_file': view['source_file'], + 'camera_id': view['camera_id'], + 'camera_position_world_m': cam_pos.tolist(), + 'rvec': rvec.reshape(-1).tolist(), + 'tvec': tvec.reshape(-1).tolist(), + 'intrinsics': { + 'camera_matrix': view['K'].tolist(), + 'distortion_coefficients': view['D'].reshape(-1).tolist() + }, + 'observation_count': observed_count + }) + + robot_pose_output = { + 'state': {k: float(robot_state[k]) for k in STATE_KEYS}, + 'uncertainty': { + 'x_mm': float(state_uncertainty[0]), + 'y_mm': float(state_uncertainty[1]), + 'z_mm': float(state_uncertainty[2]), + 'a_deg': float(state_uncertainty[3]), + 'b_deg': float(state_uncertainty[4]), + 'c_deg': float(state_uncertainty[5]), + 'e_mm': float(state_uncertainty[6]) + }, + 'confidence': { + 'x': float(math.exp(-state_uncertainty[0] / 10.0)), + 'y': float(math.exp(-state_uncertainty[1] / 10.0)), + 'z': float(math.exp(-state_uncertainty[2] / 10.0)), + 'a': float(math.exp(-state_uncertainty[3] / 10.0)), + 'b': float(math.exp(-state_uncertainty[4] / 10.0)), + 'c': float(math.exp(-state_uncertainty[5] / 10.0)), + 'e': float(math.exp(-state_uncertainty[6] / max(1.0, state_uncertainty[6]))) + } + } + + return { + 'schema_version': '1.0', + 'created_utc': datetime.datetime.utcnow().isoformat() + 'Z', + 'source_robot_json': os.path.abspath(robot_json_path), + 'source_detections': [view['source_file'] for view in views], + 'robot_pose': robot_pose_output, + 'camera_poses': camera_outputs, + 'marker_positions': list(marker_summary.values()) + } + + +# ------------------------------------------------------------------ +# Main +# ------------------------------------------------------------------ + +def main() -> None: + parser = argparse.ArgumentParser(description='Multiview optimization of robot pose and camera extrinsics') + parser.add_argument('--robot', required=True, help='Path to robot.json') + parser.add_argument('--detections', required=True, nargs='+', help='List of detection JSON files') + parser.add_argument('--outDir', required=True, help='Output directory') + parser.add_argument('--write-summary', action='store_true', help='Write summary file') + parser.add_argument('--max-iter', type=int, default=500, help='Maximum optimizer iterations') + args = parser.parse_args() + + os.makedirs(args.outDir, exist_ok=True) + + robot_json_path = os.path.abspath(args.robot) + robot = load_json(robot_json_path) + scale = parse_metric_scale(robot) + + default_state = { + k: float(robot.get('defaultPosition', {}).get(k, 0.0) or 0.0) + for k in STATE_KEYS + } + + robot_markers = extract_markers(robot, scale) + views, observations = collect_views_and_observations(args.detections, robot_markers) + + camera_guesses = [] + for view in views: + rvec, tvec = initial_camera_guess(view, observations, robot_markers, default_state, scale, robot) + camera_guesses.append((rvec, tvec)) + + x0 = pack_parameters(default_state, camera_guesses) + + progress = { + 'iter': 0, + 'last_cost': None, + 'last_print': time.time(), + 'prev_x': x0.copy() + } + + def progress_callback(xk: np.ndarray) -> None: + progress['iter'] += 1 + now = time.time() + if progress['iter'] == 1 or now - progress['last_print'] >= 1.0: + res = residuals_for_parameters(xk, views, observations, robot_markers, robot, scale, default_state) + cost = 0.5 * float(np.dot(res, res)) + delta_cost = None + convergence = '' + if progress['last_cost'] is not None: + delta_cost = cost - progress['last_cost'] + if abs(delta_cost) < 1e-3: + convergence = ' stable' + elif delta_cost < 0: + convergence = ' improving' + else: + convergence = ' worsening' + step_norm = float(np.linalg.norm(xk - progress['prev_x'])) + print( + f'[Multiview] iter={progress["iter"]:4d} cost={cost:.4f}' + + (f' delta={delta_cost:.4g}' if delta_cost is not None else '') + + f' step={step_norm:.4g}' + + convergence + ) + progress['last_cost'] = cost + progress['last_print'] = now + progress['prev_x'] = xk.copy() + + result = least_squares( + residuals_for_parameters, + x0, + args=(views, observations, robot_markers, robot, scale, default_state), + jac='2-point', + method='trf', + loss='soft_l1', + f_scale=1.0, + max_nfev=args.max_iter, + callback=progress_callback + ) + + robot_state, camera_params = unpack_parameters(result.x, len(views)) + uncertainties = estimate_uncertainty(result, len(result.x)) + + output = build_output(robot_state, uncertainties[:len(STATE_KEYS)], views, camera_params, observations, robot_markers, scale, robot, robot_json_path) + + out_path = Path(args.outDir) / 'multiview_pose.json' + save_json(output, out_path) + + print(f'Saved: {out_path}') + if args.write_summary: + summary_path = Path(args.outDir) / 'multiview_pose_summary.json' + summary = { + 'final_cost': float(result.cost), + 'status': int(result.status), + 'message': result.message, + 'robot_state': output['robot_pose'], + 'camera_count': len(views), + 'marker_count': len(robot_markers) + } + save_json(summary, summary_path) + print(f'Saved: {summary_path}') + + +if __name__ == '__main__': + main() diff --git a/pipeline/2_Multiview_neu.py b/pipeline/2_Multiview_neu.py new file mode 100644 index 0000000..84ea3b5 --- /dev/null +++ b/pipeline/2_Multiview_neu.py @@ -0,0 +1,1158 @@ +#!/usr/bin/env python3 +""" +Phase 1 — robust multiview robot pose estimation from aruco_detection.json + robot.json + +This version keeps the original kinematic model and optimizer structure, but changes: +- observation weighting to a saturating factor model: min(1, q + f) +- quality indicators are normalized to 0..1 +- blur/sharpness is supported but disabled by default (f=1) +- homography skew quality is added +- summary is built from the final output, so values stay consistent +- duplicate marker ids are warned about instead of being silently overwritten + +Input: + --robot robot.json + --detections render_1a_aruco_detection.json ... + --outDir output + +Output: + multiview_pose.json + multiview_pose_summary.json (optional) +""" + +import argparse +import datetime as _dt +import json +import math +import os +import time +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Dict, List, Tuple, Optional + +import cv2 +import numpy as np +from scipy.optimize import least_squares + +STATE_KEYS = ["x", "y", "z", "a", "b", "c", "e"] + + +# ----------------------------------------------------------------------------- +# Small helpers +# ----------------------------------------------------------------------------- + +def clamp01(x: float) -> float: + return float(max(0.0, min(1.0, x))) + + +def load_json(path: str) -> Dict[str, Any]: + with open(path, "r", encoding="utf-8") as f: + return json.load(f) + + +def save_json(data: Dict[str, Any], path: Path) -> None: + with open(path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2) + + +def resolve_scalar(value: Any, default: float = 0.0) -> float: + if value is None: + return default + if isinstance(value, (int, float)): + return float(value) + try: + return float(str(value).strip()) + except Exception: + return default + + +def resolve_vector(value: Any, default_len: int = 3) -> Tuple[float, ...]: + if value is None: + return tuple(0.0 for _ in range(default_len)) + if isinstance(value, (int, float, str)): + return (resolve_scalar(value),) + tuple(0.0 for _ in range(default_len - 1)) + if isinstance(value, (list, tuple)): + resolved = [resolve_scalar(v) for v in value] + if len(resolved) < default_len: + resolved.extend([0.0] * (default_len - len(resolved))) + return tuple(resolved[:default_len]) + return tuple(0.0 for _ in range(default_len)) + + +def parse_metric_scale(robot: Dict[str, Any]) -> float: + rendering_info = robot.get("renderingInfo", {}) or {} + metric = str(rendering_info.get("metric", "mm")).strip().lower() + return 0.001 if metric == "mm" else 1.0 + + +def normalize_axis(axis: Any) -> np.ndarray: + vec = np.asarray(axis, dtype=np.float64).reshape(-1)[:3] + norm = np.linalg.norm(vec) + if norm < 1e-12: + return np.array([1.0, 0.0, 0.0], dtype=np.float64) + return vec / norm + + +def euler_deg_to_matrix(euler_deg: Any) -> np.ndarray: + x_deg, y_deg, z_deg = resolve_vector(euler_deg, 3) + x = math.radians(x_deg) + y = math.radians(y_deg) + z = math.radians(z_deg) + + cx = math.cos(x) + sx = math.sin(x) + cy = math.cos(y) + sy = math.sin(y) + cz = math.cos(z) + sz = math.sin(z) + + Rx = np.array([[1.0, 0.0, 0.0], [0.0, cx, -sx], [0.0, sx, cx]], dtype=np.float64) + Ry = np.array([[cy, 0.0, sy], [0.0, 1.0, 0.0], [-sy, 0.0, cy]], dtype=np.float64) + Rz = np.array([[cz, -sz, 0.0], [sz, cz, 0.0], [0.0, 0.0, 1.0]], dtype=np.float64) + return Rz @ Ry @ Rx + + +def transform_from_translation_rotation(translation: Any, rotation_deg: Any) -> np.ndarray: + T = np.eye(4, dtype=np.float64) + T[:3, 3] = np.asarray(resolve_vector(translation, 3), dtype=np.float64) + T[:3, :3] = euler_deg_to_matrix(rotation_deg) + return T + + +def axis_angle_matrix(axis: Any, angle_deg: float) -> np.ndarray: + axis_vec = normalize_axis(axis) + theta = math.radians(angle_deg) + kx, ky, kz = axis_vec + c = math.cos(theta) + s = math.sin(theta) + v = 1.0 - c + R = np.array([ + [kx * kx * v + c, kx * ky * v - kz * s, kx * kz * v + ky * s], + [ky * kx * v + kz * s, ky * ky * v + c, ky * kz * v - kx * s], + [kz * kx * v - ky * s, kz * ky * v + kx * s, kz * kz * v + c], + ], dtype=np.float64) + T = np.eye(4, dtype=np.float64) + T[:3, :3] = R + return T + + +# ----------------------------------------------------------------------------- +# Optional quality configuration +# ----------------------------------------------------------------------------- + +@dataclass +class ObservationQualityConfig: + # q indicators are normalized to 0..1 + size_ref_px: float = 50.0 + border_ref_px: float = 120.0 + center_ref_norm: float = 1.0 + sharpness_ref: float = 2500.0 + homography_ref: float = 0.18 + + # factor f scales the effect of each quality indicator: + # f = 1 -> indicator is fully active + # f = 0 -> indicator is ignored (neutral weight = 1) + size_factor: float = 1.0 + aspect_factor: float = 1.0 + border_factor: float = 1.0 + center_factor: float = 1.0 + sharpness_factor: float = 1.0 + homography_factor: float = 1.0 + + # Placeholders for later phases + normal_visibility_factor: float = 1.0 + spin_factor: float = 1.0 + + # Keep a tiny floor for weights so the optimizer remains numerically stable + weight_floor: float = 0.01 + + +def _load_nested_quality_config(src: Dict[str, Any]) -> Dict[str, Any]: + if not isinstance(src, dict): + return {} + for key in ("multiview_quality", "multiviewQuality", "quality_config", "multiview"): + v = src.get(key) + if isinstance(v, dict): + return v + return {} + + +def load_quality_config(robot: Dict[str, Any]) -> ObservationQualityConfig: + cfg = ObservationQualityConfig() + candidates = [] + candidates.append(_load_nested_quality_config(robot)) + candidates.append(_load_nested_quality_config(robot.get("vision_config", {}) or {})) + + for src in candidates: + if not src: + continue + for field_name in cfg.__dataclass_fields__.keys(): + if field_name in src: + setattr(cfg, field_name, resolve_scalar(src.get(field_name), getattr(cfg, field_name))) + return cfg + + +# ----------------------------------------------------------------------------- +# Marker extraction and kinematics +# ----------------------------------------------------------------------------- + +class ConstraintResult: + def __init__(self, name: str, enabled: bool, reason: str = ""): + self.name = name + self.enabled = enabled + self.reason = reason + self.residuals = [] + + def __str__(self) -> str: + status = "✓ ENABLED" if self.enabled else "✗ DISABLED" + return f"{self.name:40s} {status:12s} {self.reason}" + + +def build_link_chain(robot: Dict[str, Any]) -> List[str]: + links = robot.get("links", {}) or {} + ordered: List[str] = [] + remaining = set(links.keys()) + while remaining: + progress = False + for name in list(remaining): + parent = links[name].get("parent") + if not parent or parent in ordered: + ordered.append(name) + remaining.remove(name) + progress = True + if not progress: + raise RuntimeError("Cycle detected in robot link tree or missing parent link") + return ordered + + +def extract_markers(robot: Dict[str, Any], scale: float) -> Dict[int, Dict[str, Any]]: + markers: Dict[int, Dict[str, Any]] = {} + links = robot.get("links", {}) or {} + marker_defaults = (robot.get("renderingInfo", {}) or {}).get("markerDefaults", {}) or {} + default_size_mm = float(marker_defaults.get("size", 25.0)) + + for link_name, link_info in links.items(): + for marker in link_info.get("markers", []) or []: + marker_id = int(marker.get("id", -1)) + if marker_id < 0: + continue + if marker_id in markers: + # Duplicate ids exist in the provided robot.json. Keep the first entry and warn. + print(f"[WARN] Duplicate marker id {marker_id} on link '{link_name}'. Ignoring this duplicate entry.") + continue + + pos = resolve_vector(marker.get("position", [0, 0, 0]), 3) + size_mm = float(marker.get("size", default_size_mm)) + markers[marker_id] = { + "marker_id": marker_id, + "link_name": link_name, + "position_m": np.asarray([pos[0] * scale, pos[1] * scale, pos[2] * scale], dtype=np.float64), + "normal": normalize_axis(resolve_vector(marker.get("normal", [0, 0, 1]), 3)), + "spin_deg": float(marker.get("spin", 0.0)), + "size_m": size_mm * scale, + } + + return markers + + +def compute_link_transforms(robot: Dict[str, Any], state: Dict[str, float], scale: float) -> Dict[str, np.ndarray]: + links = robot.get("links", {}) or {} + ordered_links = build_link_chain(robot) + transforms: Dict[str, np.ndarray] = {} + + for link_name in ordered_links: + link_info = links[link_name] or {} + parent_name = link_info.get("parent") + parent_transform = transforms[parent_name] if parent_name else np.eye(4, dtype=np.float64) + + mount_translation = np.asarray(resolve_vector(link_info.get("mountPosition", [0, 0, 0]), 3), dtype=np.float64) * scale + mount = transform_from_translation_rotation(mount_translation, link_info.get("mountRotation", [0, 0, 0])) + + joint_info = link_info.get("jointToParent", {}) or {} + joint_origin = np.asarray(resolve_vector(joint_info.get("origin", [0, 0, 0]), 3), dtype=np.float64) * scale + joint = transform_from_translation_rotation(joint_origin, joint_info.get("rotation", [0, 0, 0])) + + motion = np.eye(4, dtype=np.float64) + joint_type = str(joint_info.get("type", "fixed")).strip().lower() + control_var = str(joint_info.get("variable", joint_info.get("control", ""))).strip().lower() + axis = resolve_vector(joint_info.get("axis", [1, 0, 0]), 3) + + if joint_type == "linear": + motion[:3, 3] = normalize_axis(axis) * state.get(control_var, 0.0) * scale + elif joint_type == "revolute": + motion = axis_angle_matrix(axis, state.get(control_var, 0.0)) + + transforms[link_name] = parent_transform @ mount @ joint @ motion + + return transforms + + +def compute_marker_world_position(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + link_transform = link_transforms[marker["link_name"]] + local = np.ones(4, dtype=np.float64) + local[:3] = marker["position_m"] + world = link_transform @ local + return world[:3] + + +def marker_plane_axes(normal: np.ndarray, spin_deg: float) -> Tuple[np.ndarray, np.ndarray]: + n = normalize_axis(normal) + candidate = np.array((0.0, 0.0, 1.0), dtype=np.float64) + if abs(np.dot(n, candidate)) > 0.99: + candidate = np.array((1.0, 0.0, 0.0), dtype=np.float64) + + x_dir = np.cross(candidate, n) + x_dir /= max(np.linalg.norm(x_dir), 1e-9) + y_dir = np.cross(n, x_dir) + + if abs(spin_deg) > 1e-9: + theta = math.radians(spin_deg) + cos_t = math.cos(theta) + sin_t = math.sin(theta) + x_rot = x_dir * cos_t + np.cross(n, x_dir) * sin_t + n * np.dot(n, x_dir) * (1.0 - cos_t) + y_rot = y_dir * cos_t + np.cross(n, y_dir) * sin_t + n * np.dot(n, y_dir) * (1.0 - cos_t) + return x_rot, y_rot + + return x_dir, y_dir + + +def marker_object_corners(marker: Dict[str, Any]) -> np.ndarray: + half = marker["size_m"] * 0.5 + x_dir, y_dir = marker_plane_axes(marker["normal"], marker["spin_deg"]) + corners = np.stack([ + -x_dir * half + y_dir * half, + x_dir * half + y_dir * half, + x_dir * half - y_dir * half, + -x_dir * half - y_dir * half, + ], axis=0) + return marker["position_m"].reshape(1, 3) + corners + + +def compute_marker_world_corners(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + link_transform = link_transforms[marker["link_name"]] + local = marker_object_corners(marker) + homogeneous = np.concatenate([local, np.ones((local.shape[0], 1), dtype=np.float64)], axis=1) + world = (link_transform @ homogeneous.T).T + return world[:, :3] + + +# ----------------------------------------------------------------------------- +# Quality model +# ----------------------------------------------------------------------------- + +def quality_factor(q: float, f: float) -> float: + # Interpret f in [0, 1] as the per-indicator influence. + # f = 1.0 -> indicator is fully active; q is applied. + # f = 0.0 -> indicator is ignored and contributes a neutral weight of 1.0. + q = clamp01(q) + f = clamp01(f) + return 1.0 - f + f * q + + +def projective_homography_quality(image_points_px: np.ndarray, image_shape: Tuple[int, int], ref: float) -> float: + if image_points_px is None or len(image_points_px) != 4: + return 1.0 + + h, w = image_shape + if h <= 0 or w <= 0: + return 1.0 + + src = np.array([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]], dtype=np.float32) + dst = np.asarray(image_points_px, dtype=np.float32).copy() + dst[:, 0] /= float(w) + dst[:, 1] /= float(h) + + try: + H = cv2.getPerspectiveTransform(src, dst).astype(np.float64) + if abs(H[2, 2]) > 1e-12: + H = H / H[2, 2] + proj_strength = float(abs(H[2, 0]) + abs(H[2, 1])) + q = 1.0 / (1.0 + proj_strength / max(ref, 1e-6)) + return clamp01(q) + except Exception: + return 1.0 + + +def compute_observation_quality( + det: Dict[str, Any], + image_shape: Tuple[int, int], + cfg: ObservationQualityConfig, +) -> Dict[str, Any]: + quality = det.get("quality", {}) or {} + geometry = quality.get("geometry", {}) or {} + sharpness = quality.get("sharpness", {}) or {} + + edge_lengths = quality.get("edge_lengths_px", []) or [] + edge_lengths = [float(x) for x in edge_lengths if x is not None] + mean_edge_px = float(np.mean(edge_lengths)) if len(edge_lengths) else math.sqrt(max(float(quality.get("area_px", 0.0)), 0.0)) + + edge_ratio = float(quality.get("edge_ratio", 1.0) or 1.0) + distance_to_border_px = float(geometry.get("distance_to_border_px", 0.0) or 0.0) + distance_to_center_norm = float(geometry.get("distance_to_center_norm", 1.0) or 1.0) + laplacian_var = float(sharpness.get("laplacian_var", 0.0) or 0.0) + + # q in 0..1 + q_size = clamp01(mean_edge_px / max(cfg.size_ref_px, 1e-6)) + q_aspect = clamp01(2.0 / (1.0 + max(edge_ratio, 1e-6))) + q_border = clamp01(distance_to_border_px / max(cfg.border_ref_px, 1e-6)) + q_center = clamp01(1.0 - (distance_to_center_norm / max(cfg.center_ref_norm, 1e-6))) + q_sharpness = clamp01(laplacian_var / max(cfg.sharpness_ref, 1e-6)) + q_homography = projective_homography_quality(np.asarray(det.get("image_points_px", []), dtype=np.float64), image_shape, cfg.homography_ref) + + factor_map = { + "size": quality_factor(q_size, cfg.size_factor), + "aspect": quality_factor(q_aspect, cfg.aspect_factor), + "border": quality_factor(q_border, cfg.border_factor), + "center": quality_factor(q_center, cfg.center_factor), + "sharpness": quality_factor(q_sharpness, cfg.sharpness_factor), + "homography": quality_factor(q_homography, cfg.homography_factor), + } + + # Currently not active in phase 1, but already supported for later phases. + # They default to f=1, which makes them neutral. + q_normal_visibility = 1.0 + q_spin = 1.0 + factor_map["normal_visibility"] = quality_factor(q_normal_visibility, cfg.normal_visibility_factor) + factor_map["spin"] = quality_factor(q_spin, cfg.spin_factor) + + weight_multiplier = 1.0 + for v in factor_map.values(): + weight_multiplier *= float(v) + + # Conservative default: if no factor is activated in robot.json, + # this remains effectively neutral. + + detector_confidence = clamp01(float(det.get("confidence", 1.0) or 1.0)) + weighted_confidence = detector_confidence * weight_multiplier + weighted_confidence = max(cfg.weight_floor, min(1.0, weighted_confidence)) + + return { + "detector_confidence": detector_confidence, + "weighted_confidence": weighted_confidence, + "q": { + "size": q_size, + "aspect": q_aspect, + "border": q_border, + "center": q_center, + "sharpness": q_sharpness, + "homography": q_homography, + "normal_visibility": q_normal_visibility, + "spin": q_spin, + }, + "factor": factor_map, + "weight_multiplier": weight_multiplier, + "raw": { + "mean_edge_px": mean_edge_px, + "edge_ratio": edge_ratio, + "distance_to_border_px": distance_to_border_px, + "distance_to_center_norm": distance_to_center_norm, + "laplacian_var": laplacian_var, + }, + } + + +# ----------------------------------------------------------------------------- +# Constraints (kept from the existing approach) +# ----------------------------------------------------------------------------- + + +def validate_constraints(robot: Dict[str, Any], robot_markers: Dict[int, Dict[str, Any]]) -> Dict[str, ConstraintResult]: + results = {} + + rigid_body_result = ConstraintResult("RigidBodyDistances", False) + try: + rigid_body_count = 0 + for link_name in ["Arm1", "Ellbow", "Arm2"]: + link_markers = [m for m in robot_markers.values() if m["link_name"] == link_name] + if len(link_markers) >= 2: + rigid_body_count += 1 + if rigid_body_count >= 2: + rigid_body_result.enabled = True + rigid_body_result.reason = f"Found {rigid_body_count} links with 2+ markers each" + else: + rigid_body_result.reason = "Not enough rigid links with multiple markers" + except Exception as e: + rigid_body_result.reason = f"Error: {str(e)}" + results["RigidBodyDistances"] = rigid_body_result + + inter_link_x_result = ConstraintResult("InterLinkXDistances", False) + try: + links_with_markers = set(m["link_name"] for m in robot_markers.values()) + x_rotated_links = [] + for link_name in ["Arm1", "Ellbow"]: + if link_name in links_with_markers: + link_markers = [m for m in robot_markers.values() if m["link_name"] == link_name] + if len(link_markers) >= 1: + x_rotated_links.append(link_name) + if len(x_rotated_links) >= 2: + inter_link_x_result.enabled = True + inter_link_x_result.reason = f"Found {len(x_rotated_links)} X-rotation links: {', '.join(x_rotated_links)}" + else: + inter_link_x_result.reason = "Not enough X-rotation links" + except Exception as e: + inter_link_x_result.reason = f"Error: {str(e)}" + results["InterLinkXDistances"] = inter_link_x_result + + arm2_sina_result = ConstraintResult("Arm2SinADependency", True, "Sanity check only (not enforced)") + try: + arm2_markers = [m for m in robot_markers.values() if m["link_name"] == "Arm2"] + if len(arm2_markers) >= 2: + z_values = set(float(m["position_m"][2]) for m in arm2_markers) + if len(z_values) > 1: + arm2_sina_result.enabled = True + arm2_sina_result.reason = "Multiple Z-values detected; sin(a) dependency confirmed" + else: + arm2_sina_result.enabled = False + arm2_sina_result.reason = "No Z-variation in Arm2 markers (cannot use sin(a) constraint)" + else: + arm2_sina_result.enabled = False + arm2_sina_result.reason = "Not enough Arm2 markers" + except Exception as e: + arm2_sina_result.reason = f"Error: {str(e)}" + results["Arm2SinADependency"] = arm2_sina_result + + return results + + +def compute_soft_constraint_residuals( + robot_state: Dict[str, float], + robot_markers: Dict[int, Dict[str, Any]], + link_transforms: Dict[str, np.ndarray], + robot: Dict[str, Any], + enabled_constraints: Dict[str, ConstraintResult], +) -> List[float]: + residuals = [] + weight_scale = 0.1 + + if enabled_constraints["RigidBodyDistances"].enabled: + for link_name in ["Arm1", "Ellbow", "Arm2"]: + link_markers = [m for m in robot_markers.values() if m["link_name"] == link_name] + if len(link_markers) < 2: + continue + for i in range(len(link_markers)): + for j in range(i + 1, len(link_markers)): + m_i = link_markers[i] + m_j = link_markers[j] + pos_i = compute_marker_world_position(m_i, link_transforms) + pos_j = compute_marker_world_position(m_j, link_transforms) + dist_world = np.linalg.norm(pos_i - pos_j) + dist_local = np.linalg.norm(m_i["position_m"] - m_j["position_m"]) + error = dist_world - dist_local + residuals.append(error * weight_scale * 0.1) + + if enabled_constraints["InterLinkXDistances"].enabled: + arm1_markers = [m for m in robot_markers.values() if m["link_name"] == "Arm1"] + ellbow_markers = [m for m in robot_markers.values() if m["link_name"] == "Ellbow"] + if len(arm1_markers) >= 1 and len(ellbow_markers) >= 1: + m_arm1 = arm1_markers[0] + m_ellbow = ellbow_markers[0] + pos_arm1 = compute_marker_world_position(m_arm1, link_transforms) + pos_ellbow = compute_marker_world_position(m_ellbow, link_transforms) + x_diff_world = pos_ellbow[0] - pos_arm1[0] + x_diff_ref = m_ellbow["position_m"][0] - m_arm1["position_m"][0] + residuals.append((x_diff_world - x_diff_ref) * weight_scale) + + return residuals + + +# ----------------------------------------------------------------------------- +# Camera / observation helpers +# ----------------------------------------------------------------------------- + + +def load_intrinsics(detection_json: Dict[str, Any]) -> Tuple[np.ndarray, np.ndarray]: + cam = detection_json["camera"] + K = np.asarray(cam["camera_matrix"], dtype=np.float64) + D = np.asarray(cam.get("distortion_coefficients", [0, 0, 0, 0, 0]), dtype=np.float64).reshape(-1, 1) + return K, D + + +def detection_image_shape(detection_json: Dict[str, Any]) -> Tuple[int, int]: + image = detection_json.get("image", {}) or {} + h = int(image.get("height_px", detection_json.get("height_px", 720)) or 720) + w = int(image.get("width_px", detection_json.get("width_px", 1280)) or 1280) + return h, w + + +def collect_views_and_observations( + detection_files: List[str], + robot_markers: Dict[int, Dict[str, Any]], + quality_cfg: ObservationQualityConfig, +) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]: + views: List[Dict[str, Any]] = [] + observations: List[Dict[str, Any]] = [] + + for idx, det_path in enumerate(detection_files): + detection_json = load_json(det_path) + K, D = load_intrinsics(detection_json) + image_shape = detection_image_shape(detection_json) + + views.append({ + "index": idx, + "source_file": os.path.abspath(det_path), + "camera_id": detection_json.get("camera", {}).get("camera_id", f"cam{idx+1}"), + "image_file": detection_json.get("image", {}).get("image_file"), + "image_shape": image_shape, + "K": K, + "D": D, + }) + + for det in detection_json.get("detections", []) or []: + if str(det.get("type", "aruco")).lower() != "aruco": + continue + marker_id = int(det.get("marker_id", -1)) + if marker_id < 0 or marker_id not in robot_markers: + continue + + image_points = det.get("image_points_px") + if not (isinstance(image_points, list) and len(image_points) == 4): + # Phase 1 uses full marker corners only. + continue + + image_points = np.asarray(image_points, dtype=np.float64) + marker = robot_markers[marker_id] + obs_quality = compute_observation_quality(det, image_shape, quality_cfg) + + observations.append({ + "view_index": idx, + "marker_id": marker_id, + "marker_link_corners": marker_object_corners(marker), + "image_points_px": image_points, + "confidence_base": obs_quality["detector_confidence"], + "confidence": obs_quality["weighted_confidence"], + "quality": obs_quality, + "raw_detection": det, + }) + + if len(views) == 0: + raise RuntimeError("No valid detection views found") + if len(observations) == 0: + raise RuntimeError("No marker observations matched robot.json markers") + return views, observations + + +def initial_camera_guess( + view: Dict[str, Any], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + default_state: Dict[str, float], + scale: float, + robot: Dict[str, Any], +) -> Tuple[np.ndarray, np.ndarray]: + object_points = [] + image_points = [] + link_transforms = compute_link_transforms(robot, default_state, scale) + + for obs in observations: + if obs["view_index"] != view["index"]: + continue + marker = robot_markers[obs["marker_id"]] + object_points.append(compute_marker_world_corners(marker, link_transforms)) + image_points.append(obs["image_points_px"]) + + if len(object_points) == 0: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + object_points = np.vstack(object_points) + image_points = np.vstack(image_points) + + if object_points.shape[0] < 4: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + success, rvec, tvec = cv2.solvePnP( + object_points, + image_points, + view["K"], + view["D"], + flags=cv2.SOLVEPNP_ITERATIVE, + ) + + if not success: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + return rvec, tvec + + +def project_points(points_3d: np.ndarray, rvec: np.ndarray, tvec: np.ndarray, K: np.ndarray, D: np.ndarray) -> np.ndarray: + projected, _ = cv2.projectPoints(points_3d, rvec, tvec, K, D) + return projected.reshape(-1, 2) + + +# ----------------------------------------------------------------------------- +# Optimization +# ----------------------------------------------------------------------------- + + +def pack_parameters(robot_state: Dict[str, float], camera_params: List[Tuple[np.ndarray, np.ndarray]]) -> np.ndarray: + state_vec = np.asarray([robot_state[k] for k in STATE_KEYS], dtype=np.float64) + cams = [] + for rvec, tvec in camera_params: + cams.append(rvec.reshape(3)) + cams.append(tvec.reshape(3)) + return np.concatenate([state_vec] + cams) + + +def unpack_parameters(params: np.ndarray, n_views: int) -> Tuple[Dict[str, float], List[Tuple[np.ndarray, np.ndarray]]]: + robot_state = {STATE_KEYS[i]: float(params[i]) for i in range(len(STATE_KEYS))} + camera_params = [] + offset = len(STATE_KEYS) + for _ in range(n_views): + rvec = params[offset:offset + 3].reshape(3, 1) + tvec = params[offset + 3:offset + 6].reshape(3, 1) + camera_params.append((rvec, tvec)) + offset += 6 + return robot_state, camera_params + + +def residuals_for_parameters( + params: np.ndarray, + views: List[Dict[str, Any]], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + robot: Dict[str, Any], + scale: float, + default_state: Dict[str, float], + enabled_constraints: Dict[str, ConstraintResult], +) -> np.ndarray: + robot_state, camera_params = unpack_parameters(params, len(views)) + link_transforms = compute_link_transforms(robot, robot_state, scale) + + residuals = [] + + for obs in observations: + marker = robot_markers[obs["marker_id"]] + world_corners = compute_marker_world_corners(marker, link_transforms) + rvec, tvec = camera_params[obs["view_index"]] + proj = project_points(world_corners, rvec, tvec, views[obs["view_index"]]["K"], views[obs["view_index"]]["D"]) + diffs = proj - obs["image_points_px"] + weight = math.sqrt(max(float(obs["confidence"]), 1e-9)) + residuals.extend((diffs * weight).reshape(-1)) + + for key in STATE_KEYS: + diff = robot_state[key] - default_state.get(key, 0.0) + w = 0.001 if key in ("x", "y", "z", "e") else 0.01 + residuals.append(diff * w) + + residuals.extend(compute_soft_constraint_residuals(robot_state, robot_markers, link_transforms, robot, enabled_constraints)) + + return np.asarray(residuals, dtype=np.float64) + + +def estimate_uncertainty(result: Any, n_params: int) -> np.ndarray: + if result.jac is None: + return np.full(n_params, float("nan"), dtype=np.float64) + J = result.jac + m, n = J.shape + JTJ = J.T @ J + try: + cov = np.linalg.pinv(JTJ) + except np.linalg.LinAlgError: + cov = np.linalg.pinv(JTJ + np.eye(n) * 1e-9) + residuals = result.fun + dof = max(1, m - n) + sigma2 = float(np.sum(residuals ** 2) / dof) + cov *= sigma2 + return np.sqrt(np.diag(cov)) + + +def camera_position_world(rvec: np.ndarray, tvec: np.ndarray) -> np.ndarray: + R, _ = cv2.Rodrigues(rvec) + return (-R.T @ tvec).reshape(3) + + +# ----------------------------------------------------------------------------- +# Output building +# ----------------------------------------------------------------------------- + + +def build_output( + robot_state: Dict[str, float], + state_uncertainty: np.ndarray, + views: List[Dict[str, Any]], + camera_params: List[Tuple[np.ndarray, np.ndarray]], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + scale: float, + robot: Dict[str, Any], + robot_json_path: str, + quality_cfg: ObservationQualityConfig, + final_cost: Optional[float] = None, + solver_status: Optional[int] = None, + solver_message: Optional[str] = None, +) -> Dict[str, Any]: + link_transforms = compute_link_transforms(robot, robot_state, scale) + + marker_summary: Dict[int, Dict[str, Any]] = {} + for marker_id, marker in robot_markers.items(): + marker_summary[marker_id] = { + "marker_id": marker_id, + "link_name": marker["link_name"], + "position_world_m": compute_marker_world_position(marker, link_transforms).tolist(), + "size_m": marker["size_m"], + "observation_count": 0, + "mean_confidence": None, + "mean_detector_confidence": None, + "mean_reprojection_error_px": None, + "observations": [], + } + + per_marker_errors: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + per_marker_confidences: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + per_marker_detector_conf: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + + for obs in observations: + marker_id = obs["marker_id"] + marker = robot_markers[marker_id] + object_points_m = compute_marker_world_corners(marker, link_transforms) + rvec, tvec = camera_params[obs["view_index"]] + proj = project_points(object_points_m, rvec, tvec, views[obs["view_index"]]["K"], views[obs["view_index"]]["D"]) + diffs = proj - obs["image_points_px"] + errors = np.linalg.norm(diffs, axis=1) + repro_error = float(np.mean(errors)) + per_marker_errors[marker_id].extend(errors.tolist()) + per_marker_confidences[marker_id].append(float(obs["confidence"])) + per_marker_detector_conf[marker_id].append(float(obs["confidence_base"])) + marker_summary[marker_id]["observation_count"] += 1 + marker_summary[marker_id]["observations"].append({ + "view_index": obs["view_index"], + "source_file": views[obs["view_index"]]["source_file"], + "image_file": views[obs["view_index"]]["image_file"], + "confidence_detector": float(obs["confidence_base"]), + "confidence_weighted": float(obs["confidence"]), + "quality": obs["quality"], + "mean_reprojection_error_px": repro_error, + "corner_reprojection_errors_px": errors.tolist(), + }) + + for marker_id, summary in marker_summary.items(): + if summary["observation_count"] > 0: + summary["mean_confidence"] = float(np.mean(per_marker_confidences[marker_id])) + summary["mean_detector_confidence"] = float(np.mean(per_marker_detector_conf[marker_id])) + summary["mean_reprojection_error_px"] = float(np.mean(per_marker_errors[marker_id])) + + camera_outputs = [] + for idx, view in enumerate(views): + rvec, tvec = camera_params[idx] + cam_pos = camera_position_world(rvec, tvec) + observed_count = sum(1 for obs in observations if obs["view_index"] == idx) + camera_outputs.append({ + "view_index": idx, + "source_file": view["source_file"], + "camera_id": view["camera_id"], + "camera_position_world_m": cam_pos.tolist(), + "rvec": rvec.reshape(-1).tolist(), + "tvec": tvec.reshape(-1).tolist(), + "intrinsics": { + "camera_matrix": view["K"].tolist(), + "distortion_coefficients": view["D"].reshape(-1).tolist(), + }, + "observation_count": observed_count, + }) + + robot_pose_output = { + "state": {k: float(robot_state[k]) for k in STATE_KEYS}, + "uncertainty": { + "x_mm": float(state_uncertainty[0]), + "y_mm": float(state_uncertainty[1]), + "z_mm": float(state_uncertainty[2]), + "a_deg": float(state_uncertainty[3]), + "b_deg": float(state_uncertainty[4]), + "c_deg": float(state_uncertainty[5]), + "e_mm": float(state_uncertainty[6]), + }, + "confidence": { + "x": float(math.exp(-state_uncertainty[0] / 10.0)) if np.isfinite(state_uncertainty[0]) else 0.0, + "y": float(math.exp(-state_uncertainty[1] / 10.0)) if np.isfinite(state_uncertainty[1]) else 0.0, + "z": float(math.exp(-state_uncertainty[2] / 10.0)) if np.isfinite(state_uncertainty[2]) else 0.0, + "a": float(math.exp(-state_uncertainty[3] / 10.0)) if np.isfinite(state_uncertainty[3]) else 0.0, + "b": float(math.exp(-state_uncertainty[4] / 10.0)) if np.isfinite(state_uncertainty[4]) else 0.0, + "c": float(math.exp(-state_uncertainty[5] / 10.0)) if np.isfinite(state_uncertainty[5]) else 0.0, + "e": float(math.exp(-state_uncertainty[6] / max(1.0, state_uncertainty[6]))) if np.isfinite(state_uncertainty[6]) else 0.0, + }, + } + + all_conf = np.asarray([obs["confidence"] for obs in observations], dtype=np.float64) + all_det_conf = np.asarray([obs["confidence_base"] for obs in observations], dtype=np.float64) + all_q_size = np.asarray([obs["quality"]["q"]["size"] for obs in observations], dtype=np.float64) + all_q_aspect = np.asarray([obs["quality"]["q"]["aspect"] for obs in observations], dtype=np.float64) + all_q_border = np.asarray([obs["quality"]["q"]["border"] for obs in observations], dtype=np.float64) + all_q_homography = np.asarray([obs["quality"]["q"]["homography"] for obs in observations], dtype=np.float64) + + all_errors = [] + for marker in marker_summary.values(): + if marker["mean_reprojection_error_px"] is not None: + all_errors.append(marker["mean_reprojection_error_px"]) + + statistics = { + "observation_count": len(observations), + "camera_count": len(views), + "marker_count": len(robot_markers), + "observed_marker_count": int(sum(1 for m in marker_summary.values() if m["observation_count"] > 0)), + "mean_detector_confidence": float(np.mean(all_det_conf)) if len(all_det_conf) else None, + "mean_weighted_confidence": float(np.mean(all_conf)) if len(all_conf) else None, + "mean_reprojection_error_px": float(np.mean(all_errors)) if len(all_errors) else None, + "quality_means": { + "size": float(np.mean(all_q_size)) if len(all_q_size) else None, + "aspect": float(np.mean(all_q_aspect)) if len(all_q_aspect) else None, + "border": float(np.mean(all_q_border)) if len(all_q_border) else None, + "homography": float(np.mean(all_q_homography)) if len(all_q_homography) else None, + }, + "quality_config": { + "size_ref_px": quality_cfg.size_ref_px, + "border_ref_px": quality_cfg.border_ref_px, + "center_ref_norm": quality_cfg.center_ref_norm, + "sharpness_ref": quality_cfg.sharpness_ref, + "homography_ref": quality_cfg.homography_ref, + "size_factor": quality_cfg.size_factor, + "aspect_factor": quality_cfg.aspect_factor, + "border_factor": quality_cfg.border_factor, + "center_factor": quality_cfg.center_factor, + "sharpness_factor": quality_cfg.sharpness_factor, + "homography_factor": quality_cfg.homography_factor, + }, + } + + output = { + "schema_version": "1.0", + "created_utc": _dt.datetime.utcnow().isoformat() + "Z", + "source_robot_json": os.path.abspath(robot_json_path), + "source_detections": [view["source_file"] for view in views], + "robot_pose": robot_pose_output, + "camera_poses": camera_outputs, + "marker_positions": list(marker_summary.values()), + "statistics": statistics, + "solver": { + "final_cost": final_cost, + "status": solver_status, + "message": solver_message, + }, + } + return output + + +def build_summary(output: Dict[str, Any]) -> Dict[str, Any]: + return { + "schema_version": output.get("schema_version"), + "created_utc": output.get("created_utc"), + "source_robot_json": output.get("source_robot_json"), + "source_detections": output.get("source_detections"), + "solver": output.get("solver", {}), + "robot_pose": output.get("robot_pose"), + "statistics": output.get("statistics", {}), + } + + +# ----------------------------------------------------------------------------- +# Diagnostics +# ----------------------------------------------------------------------------- + + +def print_constraint_sanity_check( + robot_state: Dict[str, float], + robot_markers: Dict[int, Dict[str, Any]], + link_transforms: Dict[str, np.ndarray], + robot: Dict[str, Any], + enabled_constraints: Dict[str, ConstraintResult], + scale: float, +) -> None: + print("\n" + "=" * 70) + print("CONSTRAINT SANITY CHECKS (after optimization)") + print("=" * 70) + + if enabled_constraints["RigidBodyDistances"].enabled: + print("\n1. RIGID BODY DISTANCES") + for link_name in ["Arm1", "Ellbow", "Arm2"]: + link_markers = [m for m in robot_markers.values() if m["link_name"] == link_name] + if len(link_markers) < 2: + continue + max_error = 0.0 + for i in range(len(link_markers)): + for j in range(i + 1, len(link_markers)): + m_i = link_markers[i] + m_j = link_markers[j] + pos_i = compute_marker_world_position(m_i, link_transforms) + pos_j = compute_marker_world_position(m_j, link_transforms) + dist_world = np.linalg.norm(pos_i - pos_j) + dist_local = np.linalg.norm(m_i["position_m"] - m_j["position_m"]) + max_error = max(max_error, abs(dist_world - dist_local)) + status = "✓" if max_error < 1.0 else "⚠" if max_error < 5.0 else "✗" + print(f" {link_name:10s}: max_error = {max_error:.3f} mm {status}") + + if enabled_constraints["InterLinkXDistances"].enabled: + print("\n2. INTER-LINK X-DISTANCES") + arm1_markers = [m for m in robot_markers.values() if m["link_name"] == "Arm1"] + ellbow_markers = [m for m in robot_markers.values() if m["link_name"] == "Ellbow"] + if len(arm1_markers) >= 1 and len(ellbow_markers) >= 1: + m_arm1 = arm1_markers[0] + m_ellbow = ellbow_markers[0] + pos_arm1 = compute_marker_world_position(m_arm1, link_transforms) + pos_ellbow = compute_marker_world_position(m_ellbow, link_transforms) + x_diff_world = pos_ellbow[0] - pos_arm1[0] + x_diff_ref = m_ellbow["position_m"][0] - m_arm1["position_m"][0] + error = abs(x_diff_world - x_diff_ref) + status = "✓" if error < 1.0 else "⚠" if error < 5.0 else "✗" + print(f" Arm1 <-> Ellbow: error = {error:.3f} mm {status}") + + if enabled_constraints["Arm2SinADependency"].enabled: + print("\n3. ARM2 sin(a) DEPENDENCY (sanity check)") + arm2_markers = [m for m in robot_markers.values() if m["link_name"] == "Arm2"] + if len(arm2_markers) >= 2: + a_rad = math.radians(robot_state["a"]) + sin_a = math.sin(a_rad) + cos_a = math.cos(a_rad) + max_error = 0.0 + # This remains only a qualitative check. + for m in arm2_markers: + pos_world = compute_marker_world_position(m, link_transforms) + x_world = pos_world[0] + x_local = m["position_m"][0] + z_local = m["position_m"][2] + x_expected = (90.0 * scale) + x_local * cos_a - z_local * sin_a + max_error = max(max_error, abs(x_world - x_expected)) + status = "✓" if max_error < 5.0 else "⚠" + print(f" X-consistency with sin(a): max_error = {max_error:.3f} mm {status}") + print(" (Note: this is a consistency check, not a hard constraint)") + + print("=" * 70) + + +# ----------------------------------------------------------------------------- +# Main +# ----------------------------------------------------------------------------- + + +def main() -> None: + parser = argparse.ArgumentParser(description="Multiview optimization of robot pose and camera extrinsics") + parser.add_argument("--robot", required=True, help="Path to robot.json") + parser.add_argument("--detections", required=True, nargs="+", help="List of detection JSON files") + parser.add_argument("--outDir", required=True, help="Output directory") + parser.add_argument("--write-summary", action="store_true", help="Write summary file") + parser.add_argument("--max-iter", type=int, default=500, help="Maximum optimizer iterations") + args = parser.parse_args() + + os.makedirs(args.outDir, exist_ok=True) + + robot_json_path = os.path.abspath(args.robot) + robot = load_json(robot_json_path) + scale = parse_metric_scale(robot) + quality_cfg = load_quality_config(robot) + + default_state = {k: float(robot.get("defaultPosition", {}).get(k, 0.0) or 0.0) for k in STATE_KEYS} + robot_markers = extract_markers(robot, scale) + + print("\n" + "=" * 70) + print("CONSTRAINT VALIDATION") + print("=" * 70) + enabled_constraints = validate_constraints(robot, robot_markers) + for _, result in enabled_constraints.items(): + print(result) + print("=" * 70) + + views, observations = collect_views_and_observations(args.detections, robot_markers, quality_cfg) + + print("\n" + "=" * 70) + print("OBSERVATION QUALITY SUMMARY") + print("=" * 70) + print(f"Total observations: {len(observations)}") + print() + + quality_by_marker: Dict[int, List[Dict[str, Any]]] = {} + for obs in observations: + quality_by_marker.setdefault(obs["marker_id"], []).append(obs["quality"]) + + print(f"{'Marker':>8} {'Link':>12} {'Count':>6} {'Avg Size':>10} {'Avg Aspec':>10} {'Avg Hmg.':>10} {'Avg Conf.':>10}") + print("-" * 74) + for marker_id in sorted(quality_by_marker.keys()): + marker = robot_markers[marker_id] + qlist = quality_by_marker[marker_id] + avg_size = float(np.mean([q["q"]["size"] for q in qlist])) + avg_aspect = float(np.mean([q["q"]["aspect"] for q in qlist])) + avg_homog = float(np.mean([q["q"]["homography"] for q in qlist])) + obs_for_marker = [o for o in observations if o["marker_id"] == marker_id] + avg_conf = float(np.mean([o["confidence"] for o in obs_for_marker])) + print(f"{marker_id:8d} {marker['link_name']:>12} {len(qlist):6d} {avg_size:10.3f} {avg_aspect:10.3f} {avg_homog:10.3f} {avg_conf:10.3f}") + print("=" * 70) + + camera_guesses = [] + for view in views: + rvec, tvec = initial_camera_guess(view, observations, robot_markers, default_state, scale, robot) + camera_guesses.append((rvec, tvec)) + + x0 = pack_parameters(default_state, camera_guesses) + + progress = { + "iter": 0, + "last_cost": None, + "last_print": time.time(), + "prev_x": x0.copy(), + } + + def progress_callback(xk: np.ndarray) -> None: + progress["iter"] += 1 + now = time.time() + if progress["iter"] == 1 or now - progress["last_print"] >= 1.0: + res = residuals_for_parameters(xk, views, observations, robot_markers, robot, scale, default_state, enabled_constraints) + cost = 0.5 * float(np.dot(res, res)) + delta_cost = None + convergence = "" + if progress["last_cost"] is not None: + delta_cost = cost - progress["last_cost"] + if abs(delta_cost) < 1e-3: + convergence = " stable" + elif delta_cost < 0: + convergence = " improving" + else: + convergence = " worsening" + step_norm = float(np.linalg.norm(xk - progress["prev_x"])) + print(f'[Multiview] iter={progress["iter"]:4d} cost={cost:.4f}' + (f' delta={delta_cost:.4g}' if delta_cost is not None else "") + f' step={step_norm:.4g}' + convergence) + progress["last_cost"] = cost + progress["last_print"] = now + progress["prev_x"] = xk.copy() + + result = least_squares( + residuals_for_parameters, + x0, + args=(views, observations, robot_markers, robot, scale, default_state, enabled_constraints), + jac="2-point", + method="trf", + loss="soft_l1", + f_scale=1.0, + max_nfev=args.max_iter, + callback=progress_callback, + ) + + robot_state, camera_params = unpack_parameters(result.x, len(views)) + uncertainties = estimate_uncertainty(result, len(result.x)) + + link_transforms = compute_link_transforms(robot, robot_state, scale) + print_constraint_sanity_check(robot_state, robot_markers, link_transforms, robot, enabled_constraints, scale) + + output = build_output( + robot_state, + uncertainties[:len(STATE_KEYS)], + views, + camera_params, + observations, + robot_markers, + scale, + robot, + robot_json_path, + quality_cfg, + final_cost=float(result.cost), + solver_status=int(result.status), + solver_message=str(result.message), + ) + + out_path = Path(args.outDir) / "multiview_pose.json" + save_json(output, out_path) + print(f"Saved: {out_path}") + + if args.write_summary: + summary_path = Path(args.outDir) / "multiview_pose_summary.json" + summary = build_summary(output) + save_json(summary, summary_path) + print(f"Saved: {summary_path}") + + +if __name__ == "__main__": + main() diff --git a/pipeline/2_Multiview_ohne_confidence.py b/pipeline/2_Multiview_ohne_confidence.py new file mode 100644 index 0000000..666bc1d --- /dev/null +++ b/pipeline/2_Multiview_ohne_confidence.py @@ -0,0 +1,971 @@ +#!/usr/bin/env python3 + +""" +============================================================ +STEP 2b — Simultane Multiview-Optimierung für Roboterpose +============================================================ + +Ziel: + Aus mehreren ArUco-Detektionsdateien die gemeinsame + Roboterpose (x,y,z,a,b,c,e) schätzen und jede Kamera-Pose + sowie Marker-Weltpositionen ausgeben. + +Eingabe: + --robot ../robot.json + --detections render_1a_aruco_detection.json render_1b_aruco_detection.json ... + --outDir . + +Ausgabe: + multiview_pose.json + +Hinweis: + Dieses Skript verwendet die Markerpositionen aus robot.json + als kinematische Constraints und optimiert gleichzeitig: + - Roboterzustand (x,y,z,a,b,c,e) + - Kameraextrinsische Parameter pro Bild + +""" + +import argparse +import datetime +import json +import math +import os +import time +from pathlib import Path +from typing import Any, Dict, List, Tuple + +import cv2 +import numpy as np +from scipy.optimize import least_squares + +STATE_KEYS = ["x", "y", "z", "a", "b", "c", "e"] + +# ------------------------------------------------------------------ +# Constraint definitions and validation +# ------------------------------------------------------------------ + +class ConstraintResult: + """Result of validating/applying a single constraint""" + def __init__(self, name: str, enabled: bool, reason: str = ""): + self.name = name + self.enabled = enabled + self.reason = reason + self.residuals = [] + + def __str__(self) -> str: + status = "✓ ENABLED" if self.enabled else "✗ DISABLED" + return f"{self.name:40s} {status:12s} {self.reason}" + + +def validate_constraints(robot: Dict[str, Any], robot_markers: Dict[int, Dict[str, Any]]) -> Dict[str, ConstraintResult]: + """ + Validate which constraints can be applied based on robot geometry. + Returns a dict of constraint_name -> ConstraintResult + """ + results = {} + + # --- Constraint 1: Rigid body distances within each link --- + rigid_body_result = ConstraintResult("RigidBodyDistances", False) + try: + rigid_body_count = 0 + for link_name in ['Arm1', 'Ellbow', 'Arm2']: + link_markers = [m for m in robot_markers.values() if m['link_name'] == link_name] + if len(link_markers) >= 2: + rigid_body_count += 1 + if rigid_body_count >= 2: + rigid_body_result.enabled = True + rigid_body_result.reason = f"Found {rigid_body_count} links with 2+ markers each" + else: + rigid_body_result.reason = "Not enough rigid links with multiple markers" + except Exception as e: + rigid_body_result.reason = f"Error: {str(e)}" + results['RigidBodyDistances'] = rigid_body_result + + # --- Constraint 2: Fixed X-distances between links (rotation around X-axis) --- + inter_link_x_result = ConstraintResult("InterLinkXDistances", False) + try: + links_with_markers = set(m['link_name'] for m in robot_markers.values()) + x_rotated_links = [] + for link_name in ['Arm1', 'Ellbow']: + if link_name in links_with_markers: + link_markers = [m for m in robot_markers.values() if m['link_name'] == link_name] + if len(link_markers) >= 1: + x_rotated_links.append(link_name) + if len(x_rotated_links) >= 2: + inter_link_x_result.enabled = True + inter_link_x_result.reason = f"Found {len(x_rotated_links)} X-rotation links: {', '.join(x_rotated_links)}" + else: + inter_link_x_result.reason = "Not enough X-rotation links" + except Exception as e: + inter_link_x_result.reason = f"Error: {str(e)}" + results['InterLinkXDistances'] = inter_link_x_result + + # --- Sanity check (not a hard constraint): Arm2 sin(a) dependency --- + arm2_sina_result = ConstraintResult("Arm2SinADependency", True, "Sanity check only (not enforced)") + try: + arm2_markers = [m for m in robot_markers.values() if m['link_name'] == 'Arm2'] + if len(arm2_markers) >= 2: + z_values = set(m['position_m'][2] for m in arm2_markers) + if len(z_values) > 1: + arm2_sina_result.enabled = True + arm2_sina_result.reason = "Multiple Z-values detected; sin(a) dependency confirmed" + else: + arm2_sina_result.enabled = False + arm2_sina_result.reason = "No Z-variation in Arm2 markers (cannot use sin(a) constraint)" + else: + arm2_sina_result.enabled = False + arm2_sina_result.reason = "Not enough Arm2 markers" + except Exception as e: + arm2_sina_result.reason = f"Error: {str(e)}" + results['Arm2SinADependency'] = arm2_sina_result + + return results + + +# ------------------------------------------------------------------ +# JSON helpers +# ------------------------------------------------------------------ + +def load_json(path: str) -> Dict[str, Any]: + with open(path, 'r', encoding='utf-8') as f: + return json.load(f) + + +def save_json(data: Dict[str, Any], path: Path) -> None: + with open(path, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2) + + +# ------------------------------------------------------------------ +# robot.json helpers +# ------------------------------------------------------------------ + +def resolve_scalar(value: Any, default: float = 0.0) -> float: + if value is None: + return default + if isinstance(value, (int, float)): + return float(value) + try: + return float(str(value).strip()) + except ValueError: + return default + + +def resolve_vector(value: Any, default_len: int = 3) -> Tuple[float, ...]: + if value is None: + return tuple(0.0 for _ in range(default_len)) + if isinstance(value, (int, float, str)): + return (resolve_scalar(value),) + tuple(0.0 for _ in range(default_len - 1)) + if isinstance(value, (list, tuple)): + resolved = [resolve_scalar(v) for v in value] + if len(resolved) < default_len: + resolved.extend([0.0] * (default_len - len(resolved))) + return tuple(resolved[:default_len]) + return tuple(0.0 for _ in range(default_len)) + + +def parse_metric_scale(robot: Dict[str, Any]) -> float: + rendering_info = robot.get('renderingInfo', {}) or {} + metric = rendering_info.get('metric', 'mm') + return 0.001 if str(metric).strip().lower() == 'mm' else 1.0 + + +def normalize_axis(axis: Any) -> np.ndarray: + vec = np.asarray(axis, dtype=np.float64) + if vec.shape != (3,): + vec = vec.reshape(-1)[:3] + norm = np.linalg.norm(vec) + return vec / max(norm, 1e-9) + + +def euler_deg_to_matrix(euler_deg: Any) -> np.ndarray: + x_deg, y_deg, z_deg = resolve_vector(euler_deg, 3) + x = math.radians(x_deg) + y = math.radians(y_deg) + z = math.radians(z_deg) + + cx = math.cos(x) + sx = math.sin(x) + cy = math.cos(y) + sy = math.sin(y) + cz = math.cos(z) + sz = math.sin(z) + + Rx = np.array([ + [1.0, 0.0, 0.0], + [0.0, cx, -sx], + [0.0, sx, cx] + ], dtype=np.float64) + + Ry = np.array([ + [cy, 0.0, sy], + [0.0, 1.0, 0.0], + [-sy, 0.0, cy] + ], dtype=np.float64) + + Rz = np.array([ + [cz, -sz, 0.0], + [sz, cz, 0.0], + [0.0, 0.0, 1.0] + ], dtype=np.float64) + + return Rz @ Ry @ Rx + + +def transform_from_translation_rotation(translation: Any, rotation_deg: Any) -> np.ndarray: + T = np.eye(4, dtype=np.float64) + pos = np.asarray(resolve_vector(translation, 3), dtype=np.float64) + T[:3, 3] = pos + T[:3, :3] = euler_deg_to_matrix(rotation_deg) + return T + + +def axis_angle_matrix(axis: Any, angle_deg: float) -> np.ndarray: + axis_vec = normalize_axis(axis) + theta = math.radians(angle_deg) + kx, ky, kz = axis_vec + c = math.cos(theta) + s = math.sin(theta) + v = 1.0 - c + R = np.array([ + [kx * kx * v + c, kx * ky * v - kz * s, kx * kz * v + ky * s], + [ky * kx * v + kz * s, ky * ky * v + c, ky * kz * v - kx * s], + [kz * kx * v - ky * s, kz * ky * v + kx * s, kz * kz * v + c] + ], dtype=np.float64) + T = np.eye(4, dtype=np.float64) + T[:3, :3] = R + return T + + +# ------------------------------------------------------------------ +# Kinematics and marker extraction +# ------------------------------------------------------------------ + +def extract_markers(robot: Dict[str, Any], scale: float) -> Dict[int, Dict[str, Any]]: + markers = {} + links = robot.get('links', {}) or {} + marker_defaults = (robot.get('renderingInfo', {}) or {}).get('markerDefaults', {}) or {} + default_size_mm = float(marker_defaults.get('size', 25.0)) + + for link_name, link_info in links.items(): + for marker in link_info.get('markers', []) or []: + marker_id = int(marker.get('id', -1)) + if marker_id < 0: + continue + + pos = resolve_vector(marker.get('position', [0, 0, 0]), 3) + size_mm = float(marker.get('size', default_size_mm)) + markers[marker_id] = { + 'marker_id': marker_id, + 'link_name': link_name, + 'position_m': np.asarray([pos[0] * scale, pos[1] * scale, pos[2] * scale], dtype=np.float64), + 'normal': normalize_axis(resolve_vector(marker.get('normal', [0, 0, 1]), 3)), + 'spin_deg': float(marker.get('spin', 0.0)), + 'size_m': size_mm * scale, + } + + return markers + + +def marker_plane_axes(normal: np.ndarray, spin_deg: float) -> Tuple[np.ndarray, np.ndarray]: + n = normalize_axis(normal) + candidate = np.array((0.0, 0.0, 1.0), dtype=np.float64) + if abs(np.dot(n, candidate)) > 0.99: + candidate = np.array((1.0, 0.0, 0.0), dtype=np.float64) + + x_dir = np.cross(candidate, n) + x_dir /= max(np.linalg.norm(x_dir), 1e-9) + y_dir = np.cross(n, x_dir) + + if abs(spin_deg) > 1e-6: + theta = math.radians(spin_deg) + cos_t = math.cos(theta) + sin_t = math.sin(theta) + x_rot = x_dir * cos_t + np.cross(n, x_dir) * sin_t + n * np.dot(n, x_dir) * (1.0 - cos_t) + y_rot = y_dir * cos_t + np.cross(n, y_dir) * sin_t + n * np.dot(n, y_dir) * (1.0 - cos_t) + return x_rot, y_rot + + return x_dir, y_dir + + +def marker_object_corners(marker: Dict[str, Any]) -> np.ndarray: + half = marker['size_m'] * 0.5 + x_dir, y_dir = marker_plane_axes(marker['normal'], marker['spin_deg']) + corners = np.stack([ + -x_dir * half + y_dir * half, + x_dir * half + y_dir * half, + x_dir * half - y_dir * half, + -x_dir * half - y_dir * half + ], axis=0) + return marker['position_m'].reshape(1, 3) + corners + + +def build_link_chain(robot: Dict[str, Any]) -> List[str]: + links = robot.get('links', {}) or {} + ordered: List[str] = [] + remaining = set(links.keys()) + + while remaining: + progress = False + for name in list(remaining): + parent = links[name].get('parent') + if not parent or parent in ordered: + ordered.append(name) + remaining.remove(name) + progress = True + if not progress: + raise RuntimeError('Cycle detected in robot link tree or missing parent link') + return ordered + + +def compute_link_transforms(robot: Dict[str, Any], state: Dict[str, float], scale: float) -> Dict[str, np.ndarray]: + links = robot.get('links', {}) or {} + ordered_links = build_link_chain(robot) + transforms: Dict[str, np.ndarray] = {} + + for link_name in ordered_links: + link_info = links[link_name] or {} + parent_name = link_info.get('parent') + parent_transform = transforms[parent_name] if parent_name else np.eye(4, dtype=np.float64) + + mount_translation = np.asarray(resolve_vector(link_info.get('mountPosition', [0, 0, 0]), 3), dtype=np.float64) * scale + mount = transform_from_translation_rotation( + mount_translation, + link_info.get('mountRotation', [0, 0, 0]) + ) + + joint_info = link_info.get('jointToParent', {}) or {} + joint_origin = np.asarray(resolve_vector(joint_info.get('origin', [0, 0, 0]), 3), dtype=np.float64) * scale + joint = transform_from_translation_rotation( + joint_origin, + joint_info.get('rotation', [0, 0, 0]) + ) + + motion = np.eye(4, dtype=np.float64) + joint_type = str(joint_info.get('type', 'fixed')).strip().lower() + control_var = str(joint_info.get('variable', joint_info.get('control', ''))).strip().lower() + axis = resolve_vector(joint_info.get('axis', [1, 0, 0]), 3) + + if joint_type == 'linear': + motion[:3, 3] = normalize_axis(axis) * state.get(control_var, 0.0) * scale + elif joint_type == 'revolute': + motion = axis_angle_matrix(axis, state.get(control_var, 0.0)) + + transforms[link_name] = parent_transform @ mount @ joint @ motion + + return transforms + + +def compute_marker_world_position(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + link_transform = link_transforms[marker['link_name']] + local = np.ones(4, dtype=np.float64) + local[:3] = marker['position_m'] + world = link_transform @ local + return world[:3] + + +# ------------------------------------------------------------------ +# Camera / observation helpers +# ------------------------------------------------------------------ + +def load_intrinsics(detection_json: Dict[str, Any]) -> Tuple[np.ndarray, np.ndarray]: + cam = detection_json['camera'] + K = np.asarray(cam['camera_matrix'], dtype=np.float64) + D = np.asarray(cam.get('distortion_coefficients', [0, 0, 0, 0, 0]), dtype=np.float64).reshape(-1, 1) + return K, D + + +def collect_views_and_observations( + detection_files: List[str], + robot_markers: Dict[int, Dict[str, Any]] +) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]: + views: List[Dict[str, Any]] = [] + observations: List[Dict[str, Any]] = [] + + for idx, det_path in enumerate(detection_files): + detection_json = load_json(det_path) + K, D = load_intrinsics(detection_json) + views.append({ + 'index': idx, + 'source_file': os.path.abspath(det_path), + 'camera_id': detection_json.get('camera', {}).get('camera_id', f'cam{idx+1}'), + 'image_file': detection_json.get('image', {}).get('image_file'), + 'K': K, + 'D': D + }) + + for det in detection_json.get('detections', []) or []: + marker_id = int(det.get('marker_id', -1)) + if marker_id < 0 or marker_id not in robot_markers: + continue + + image_points = det.get('image_points_px') + if isinstance(image_points, list) and len(image_points) == 4: + image_points = np.asarray(image_points, dtype=np.float64) + else: + center = resolve_vector(det.get('center_px', [0, 0]), 2) + image_points = np.asarray([center], dtype=np.float64) + + confidence = float(det.get('confidence', 1.0)) + marker = robot_markers[marker_id] + observations.append({ + 'view_index': idx, + 'marker_id': marker_id, + 'marker_link_corners': marker_object_corners(marker), + 'image_points_px': image_points, + 'confidence': max(0.01, min(1.0, confidence)) + }) + + if len(views) == 0: + raise RuntimeError('No valid detection views found') + + if len(observations) == 0: + raise RuntimeError('No marker observations matched robot.json markers') + + return views, observations + + +def compute_marker_world_corners(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + link_transform = link_transforms[marker['link_name']] + local = marker_object_corners(marker) + homogeneous = np.concatenate([local, np.ones((local.shape[0], 1), dtype=np.float64)], axis=1) + world = (link_transform @ homogeneous.T).T + return world[:, :3] + + +def initial_camera_guess( + view: Dict[str, Any], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + default_state: Dict[str, float], + scale: float, + robot: Dict[str, Any] +) -> Tuple[np.ndarray, np.ndarray]: + object_points = [] + image_points = [] + + link_transforms = compute_link_transforms(robot, default_state, scale) + + for obs in observations: + if obs['view_index'] != view['index']: + continue + marker = robot_markers[obs['marker_id']] + object_points.append(compute_marker_world_corners(marker, link_transforms)) + image_points.append(obs['image_points_px']) + + if len(object_points) == 0: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + object_points = np.vstack(object_points) + image_points = np.vstack(image_points) + + if object_points.shape[0] < 4: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + success, rvec, tvec = cv2.solvePnP( + object_points, + image_points, + view['K'], + view['D'], + flags=cv2.SOLVEPNP_ITERATIVE + ) + + if not success: + return np.zeros((3, 1), dtype=np.float64), np.array([[0.0], [0.0], [1.0]], dtype=np.float64) + + return rvec, tvec + + +def project_points( + points_3d: np.ndarray, + rvec: np.ndarray, + tvec: np.ndarray, + K: np.ndarray, + D: np.ndarray +) -> np.ndarray: + projected, _ = cv2.projectPoints(points_3d, rvec, tvec, K, D) + return projected.reshape(-1, 2) + + +def compute_soft_constraint_residuals( + robot_state: Dict[str, float], + robot_markers: Dict[int, Dict[str, Any]], + link_transforms: Dict[str, np.ndarray], + robot: Dict[str, Any], + enabled_constraints: Dict[str, ConstraintResult] +) -> List[float]: + """ + Compute residuals from soft constraints (kinematic consistency, rigid body distances). + Returns a list of constraint residuals to append to the total residual vector. + """ + residuals = [] + weight_scale = 0.1 # Weight for soft constraints relative to reprojection errors + + # Constraint 1: Rigid body distances within each link + if enabled_constraints['RigidBodyDistances'].enabled: + for link_name in ['Arm1', 'Ellbow', 'Arm2']: + link_markers = [m for m in robot_markers.values() if m['link_name'] == link_name] + if len(link_markers) < 2: + continue + + # Compute all pairwise distances in world coords + for i in range(len(link_markers)): + for j in range(i + 1, len(link_markers)): + m_i = link_markers[i] + m_j = link_markers[j] + + pos_i = compute_marker_world_position(m_i, link_transforms) + pos_j = compute_marker_world_position(m_j, link_transforms) + + dist_world = np.linalg.norm(pos_i - pos_j) + + # Reference distance in local coords + dist_local = np.linalg.norm(m_i['position_m'] - m_j['position_m']) + + # Residual: difference should be zero (rigid body) + error = dist_world - dist_local + residuals.append(error * weight_scale * 0.1) # Very soft weight + + # Constraint 2: Fixed X-distances between links (Arm1 <-> Ellbow) + if enabled_constraints['InterLinkXDistances'].enabled: + arm1_markers = [m for m in robot_markers.values() if m['link_name'] == 'Arm1'] + ellbow_markers = [m for m in robot_markers.values() if m['link_name'] == 'Ellbow'] + + if len(arm1_markers) >= 1 and len(ellbow_markers) >= 1: + # Get first marker from each link + m_arm1 = arm1_markers[0] + m_ellbow = ellbow_markers[0] + + pos_arm1 = compute_marker_world_position(m_arm1, link_transforms) + pos_ellbow = compute_marker_world_position(m_ellbow, link_transforms) + + # X-distance in world should match reference (relative position) + # Since both rotate around X-axis at different points, we check consistency + x_diff_world = pos_ellbow[0] - pos_arm1[0] + x_diff_ref = m_ellbow['position_m'][0] - m_arm1['position_m'][0] + + error = x_diff_world - x_diff_ref + residuals.append(error * weight_scale) + + return residuals + + +def compute_marker_world_position(marker: Dict[str, Any], link_transforms: Dict[str, np.ndarray]) -> np.ndarray: + """Compute the world position of a marker given current link transforms.""" + link_transform = link_transforms[marker['link_name']] + local_pos = np.concatenate([marker['position_m'], [1.0]]) + world_pos = (link_transform @ local_pos)[:3] + return world_pos + + +# ------------------------------------------------------------------ +# Optimization +# ------------------------------------------------------------------ + +def pack_parameters(robot_state: Dict[str, float], camera_params: List[Tuple[np.ndarray, np.ndarray]]) -> np.ndarray: + state_vec = np.asarray([robot_state[k] for k in STATE_KEYS], dtype=np.float64) + cams = [] + for rvec, tvec in camera_params: + cams.append(rvec.reshape(3)) + cams.append(tvec.reshape(3)) + return np.concatenate([state_vec] + cams) + + +def unpack_parameters(params: np.ndarray, n_views: int) -> Tuple[Dict[str, float], List[Tuple[np.ndarray, np.ndarray]]]: + robot_state = {STATE_KEYS[i]: float(params[i]) for i in range(len(STATE_KEYS))} + camera_params = [] + offset = len(STATE_KEYS) + for _ in range(n_views): + rvec = params[offset:offset + 3].reshape(3, 1) + tvec = params[offset + 3:offset + 6].reshape(3, 1) + camera_params.append((rvec, tvec)) + offset += 6 + return robot_state, camera_params + + +def residuals_for_parameters( + params: np.ndarray, + views: List[Dict[str, Any]], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + robot: Dict[str, Any], + scale: float, + default_state: Dict[str, float], + enabled_constraints: Dict[str, ConstraintResult] +) -> np.ndarray: + robot_state, camera_params = unpack_parameters(params, len(views)) + link_transforms = compute_link_transforms(robot, robot_state, scale) + + residuals = [] + + # Reprojection residuals (primary observation) + for obs in observations: + marker = robot_markers[obs['marker_id']] + world_corners = compute_marker_world_corners(marker, link_transforms) + rvec, tvec = camera_params[obs['view_index']] + proj = project_points(world_corners, rvec, tvec, views[obs['view_index']]['K'], views[obs['view_index']]['D']) + diffs = proj - obs['image_points_px'] + weight = math.sqrt(obs['confidence']) + residuals.extend((diffs * weight).reshape(-1)) + + # Weak priors on robot state + for key in STATE_KEYS: + diff = robot_state[key] - default_state.get(key, 0.0) + if key in ('x', 'y', 'z', 'e'): + w = 0.001 + else: + w = 0.01 + residuals.append(diff * w) + + # Soft constraints (kinematic consistency, rigid body constraints) + soft_constraint_residuals = compute_soft_constraint_residuals( + robot_state, robot_markers, link_transforms, robot, enabled_constraints + ) + residuals.extend(soft_constraint_residuals) + + return np.asarray(residuals, dtype=np.float64) + + + +def estimate_uncertainty(result: Any, n_params: int) -> np.ndarray: + if result.jac is None: + return np.full(n_params, float('nan'), dtype=np.float64) + J = result.jac + m, n = J.shape + JTJ = J.T @ J + try: + cov = np.linalg.pinv(JTJ) + except np.linalg.LinAlgError: + cov = np.linalg.pinv(JTJ + np.eye(n) * 1e-9) + residuals = result.fun + dof = max(1, m - n) + sigma2 = float(np.sum(residuals ** 2) / dof) + cov *= sigma2 + return np.sqrt(np.diag(cov)) + + +def print_constraint_sanity_check( + robot_state: Dict[str, float], + robot_markers: Dict[int, Dict[str, Any]], + link_transforms: Dict[str, np.ndarray], + robot: Dict[str, Any], + enabled_constraints: Dict[str, ConstraintResult] +) -> None: + """ + Print sanity checks for all constraints to verify the optimization result. + """ + print("\n" + "=" * 70) + print("CONSTRAINT SANITY CHECKS (after optimization)") + print("=" * 70) + + # Check 1: Rigid body distances + if enabled_constraints['RigidBodyDistances'].enabled: + print("\n1. RIGID BODY DISTANCES") + for link_name in ['Arm1', 'Ellbow', 'Arm2']: + link_markers = [m for m in robot_markers.values() if m['link_name'] == link_name] + if len(link_markers) < 2: + continue + + max_error = 0.0 + for i in range(len(link_markers)): + for j in range(i + 1, len(link_markers)): + m_i = link_markers[i] + m_j = link_markers[j] + + pos_i = compute_marker_world_position(m_i, link_transforms) + pos_j = compute_marker_world_position(m_j, link_transforms) + + dist_world = np.linalg.norm(pos_i - pos_j) + dist_local = np.linalg.norm(m_i['position_m'] - m_j['position_m']) + error = abs(dist_world - dist_local) + max_error = max(max_error, error) + + status = "✓" if max_error < 1.0 else "⚠" if max_error < 5.0 else "✗" + print(f" {link_name:10s}: max_error = {max_error:.3f} mm {status}") + + # Check 2: Inter-link X distances + if enabled_constraints['InterLinkXDistances'].enabled: + print("\n2. INTER-LINK X-DISTANCES") + arm1_markers = [m for m in robot_markers.values() if m['link_name'] == 'Arm1'] + ellbow_markers = [m for m in robot_markers.values() if m['link_name'] == 'Ellbow'] + + if len(arm1_markers) >= 1 and len(ellbow_markers) >= 1: + m_arm1 = arm1_markers[0] + m_ellbow = ellbow_markers[0] + + pos_arm1 = compute_marker_world_position(m_arm1, link_transforms) + pos_ellbow = compute_marker_world_position(m_ellbow, link_transforms) + + x_diff_world = pos_ellbow[0] - pos_arm1[0] + x_diff_ref = m_ellbow['position_m'][0] - m_arm1['position_m'][0] + error = abs(x_diff_world - x_diff_ref) + + status = "✓" if error < 1.0 else "⚠" if error < 5.0 else "✗" + print(f" Arm1 <-> Ellbow: error = {error:.3f} mm {status}") + + # Check 3: Arm2 sin(a) dependency + if enabled_constraints['Arm2SinADependency'].enabled: + print("\n3. ARM2 sin(a) DEPENDENCY (sanity check)") + arm2_markers = [m for m in robot_markers.values() if m['link_name'] == 'Arm2'] + if len(arm2_markers) >= 2: + # Check that markers with different Z values have different X spreads + a_rad = math.radians(robot_state['a']) + sin_a = math.sin(a_rad) + cos_a = math.cos(a_rad) + + z_variations = {} + for m in arm2_markers: + z_local = m['position_m'][2] + x_local = m['position_m'][0] + pos_world = compute_marker_world_position(m, link_transforms) + x_world = pos_world[0] + + # Expected: x_world = 90 + x_local * cos(a) - z_local * sin(a) + x_expected = 90 * (robot.get('renderingInfo', {}).get('metric', 'mm') == 'mm' and 0.09 or 0.09) + x_local * cos_a - z_local * sin_a + x_error = abs(x_world - x_expected) + + if z_local not in z_variations: + z_variations[z_local] = [] + z_variations[z_local].append(x_error) + + max_error = max(max(errors) for errors in z_variations.values()) if z_variations else 0.0 + status = "✓" if max_error < 5.0 else "⚠" if max_error < 10.0 else "⚠" + print(f" X-consistency with sin(a): max_error = {max_error:.3f} mm {status}") + print(f" (Note: this is a consistency check, not a hard constraint)") + + print("=" * 70) + + +def camera_position_world(rvec: np.ndarray, tvec: np.ndarray) -> np.ndarray: + R, _ = cv2.Rodrigues(rvec) + return (-R.T @ tvec).reshape(3) + + +def build_output( + robot_state: Dict[str, float], + state_uncertainty: np.ndarray, + views: List[Dict[str, Any]], + camera_params: List[Tuple[np.ndarray, np.ndarray]], + observations: List[Dict[str, Any]], + robot_markers: Dict[int, Dict[str, Any]], + scale: float, + robot: Dict[str, Any], + robot_json_path: str +) -> Dict[str, Any]: + link_transforms = compute_link_transforms(robot, robot_state, scale) + + marker_summary: Dict[int, Dict[str, Any]] = {} + for marker_id, marker in robot_markers.items(): + marker_summary[marker_id] = { + 'marker_id': marker_id, + 'link_name': marker['link_name'], + 'position_world_m': compute_marker_world_position(marker, link_transforms).tolist(), + 'size_m': marker['size_m'], + 'observation_count': 0, + 'mean_confidence': None, + 'mean_reprojection_error_px': None, + 'observations': [] + } + + per_marker_errors: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + per_marker_confidences: Dict[int, List[float]] = {mid: [] for mid in marker_summary} + + link_transforms = compute_link_transforms(robot, robot_state, scale) + for obs in observations: + marker_id = obs['marker_id'] + marker = robot_markers[marker_id] + object_points_m = compute_marker_world_corners(marker, link_transforms) + rvec, tvec = camera_params[obs['view_index']] + proj = project_points(object_points_m, rvec, tvec, views[obs['view_index']]['K'], views[obs['view_index']]['D']) + diffs = proj - obs['image_points_px'] + errors = np.linalg.norm(diffs, axis=1) + repro_error = float(np.mean(errors)) + per_marker_errors[marker_id].extend(errors.tolist()) + per_marker_confidences[marker_id].append(obs['confidence']) + marker_summary[marker_id]['observation_count'] += 1 + marker_summary[marker_id]['observations'].append({ + 'view_index': obs['view_index'], + 'source_file': views[obs['view_index']]['source_file'], + 'image_file': views[obs['view_index']]['image_file'], + 'confidence': obs['confidence'], + 'mean_reprojection_error_px': repro_error, + 'corner_reprojection_errors_px': errors.tolist() + }) + + for marker_id, summary in marker_summary.items(): + if summary['observation_count'] > 0: + summary['mean_confidence'] = float(np.mean(per_marker_confidences[marker_id])) + summary['mean_reprojection_error_px'] = float(np.mean(per_marker_errors[marker_id])) + + camera_outputs = [] + for idx, view in enumerate(views): + rvec, tvec = camera_params[idx] + cam_pos = camera_position_world(rvec, tvec) + observed_count = sum(1 for obs in observations if obs['view_index'] == idx) + camera_outputs.append({ + 'view_index': idx, + 'source_file': view['source_file'], + 'camera_id': view['camera_id'], + 'camera_position_world_m': cam_pos.tolist(), + 'rvec': rvec.reshape(-1).tolist(), + 'tvec': tvec.reshape(-1).tolist(), + 'intrinsics': { + 'camera_matrix': view['K'].tolist(), + 'distortion_coefficients': view['D'].reshape(-1).tolist() + }, + 'observation_count': observed_count + }) + + robot_pose_output = { + 'state': {k: float(robot_state[k]) for k in STATE_KEYS}, + 'uncertainty': { + 'x_mm': float(state_uncertainty[0]), + 'y_mm': float(state_uncertainty[1]), + 'z_mm': float(state_uncertainty[2]), + 'a_deg': float(state_uncertainty[3]), + 'b_deg': float(state_uncertainty[4]), + 'c_deg': float(state_uncertainty[5]), + 'e_mm': float(state_uncertainty[6]) + }, + 'confidence': { + 'x': float(math.exp(-state_uncertainty[0] / 10.0)), + 'y': float(math.exp(-state_uncertainty[1] / 10.0)), + 'z': float(math.exp(-state_uncertainty[2] / 10.0)), + 'a': float(math.exp(-state_uncertainty[3] / 10.0)), + 'b': float(math.exp(-state_uncertainty[4] / 10.0)), + 'c': float(math.exp(-state_uncertainty[5] / 10.0)), + 'e': float(math.exp(-state_uncertainty[6] / max(1.0, state_uncertainty[6]))) + } + } + + return { + 'schema_version': '1.0', + 'created_utc': datetime.datetime.utcnow().isoformat() + 'Z', + 'source_robot_json': os.path.abspath(robot_json_path), + 'source_detections': [view['source_file'] for view in views], + 'robot_pose': robot_pose_output, + 'camera_poses': camera_outputs, + 'marker_positions': list(marker_summary.values()) + } + + +# ------------------------------------------------------------------ +# Main +# ------------------------------------------------------------------ + +def main() -> None: + parser = argparse.ArgumentParser(description='Multiview optimization of robot pose and camera extrinsics') + parser.add_argument('--robot', required=True, help='Path to robot.json') + parser.add_argument('--detections', required=True, nargs='+', help='List of detection JSON files') + parser.add_argument('--outDir', required=True, help='Output directory') + parser.add_argument('--write-summary', action='store_true', help='Write summary file') + parser.add_argument('--max-iter', type=int, default=500, help='Maximum optimizer iterations') + args = parser.parse_args() + + os.makedirs(args.outDir, exist_ok=True) + + robot_json_path = os.path.abspath(args.robot) + robot = load_json(robot_json_path) + scale = parse_metric_scale(robot) + + default_state = { + k: float(robot.get('defaultPosition', {}).get(k, 0.0) or 0.0) + for k in STATE_KEYS + } + + robot_markers = extract_markers(robot, scale) + + # Validate constraints + print("\n" + "=" * 70) + print("CONSTRAINT VALIDATION") + print("=" * 70) + enabled_constraints = validate_constraints(robot, robot_markers) + for constraint_name, result in enabled_constraints.items(): + print(result) + print("=" * 70) + + views, observations = collect_views_and_observations(args.detections, robot_markers) + + camera_guesses = [] + for view in views: + rvec, tvec = initial_camera_guess(view, observations, robot_markers, default_state, scale, robot) + camera_guesses.append((rvec, tvec)) + + x0 = pack_parameters(default_state, camera_guesses) + + progress = { + 'iter': 0, + 'last_cost': None, + 'last_print': time.time(), + 'prev_x': x0.copy() + } + + def progress_callback(xk: np.ndarray) -> None: + progress['iter'] += 1 + now = time.time() + if progress['iter'] == 1 or now - progress['last_print'] >= 1.0: + res = residuals_for_parameters(xk, views, observations, robot_markers, robot, scale, default_state, enabled_constraints) + cost = 0.5 * float(np.dot(res, res)) + delta_cost = None + convergence = '' + if progress['last_cost'] is not None: + delta_cost = cost - progress['last_cost'] + if abs(delta_cost) < 1e-3: + convergence = ' stable' + elif delta_cost < 0: + convergence = ' improving' + else: + convergence = ' worsening' + step_norm = float(np.linalg.norm(xk - progress['prev_x'])) + print( + f'[Multiview] iter={progress["iter"]:4d} cost={cost:.4f}' + + (f' delta={delta_cost:.4g}' if delta_cost is not None else '') + + f' step={step_norm:.4g}' + + convergence + ) + progress['last_cost'] = cost + progress['last_print'] = now + progress['prev_x'] = xk.copy() + + result = least_squares( + residuals_for_parameters, + x0, + args=(views, observations, robot_markers, robot, scale, default_state, enabled_constraints), + jac='2-point', + method='trf', + loss='soft_l1', + f_scale=1.0, + max_nfev=args.max_iter, + callback=progress_callback + ) + + robot_state, camera_params = unpack_parameters(result.x, len(views)) + uncertainties = estimate_uncertainty(result, len(result.x)) + + # Print constraint sanity checks + link_transforms = compute_link_transforms(robot, robot_state, scale) + print_constraint_sanity_check(robot_state, robot_markers, link_transforms, robot, enabled_constraints) + + output = build_output(robot_state, uncertainties[:len(STATE_KEYS)], views, camera_params, observations, robot_markers, scale, robot, robot_json_path) + + out_path = Path(args.outDir) / 'multiview_pose.json' + save_json(output, out_path) + + print(f'Saved: {out_path}') + if args.write_summary: + summary_path = Path(args.outDir) / 'multiview_pose_summary.json' + summary = { + 'final_cost': float(result.cost), + 'status': int(result.status), + 'message': result.message, + 'robot_state': output['robot_pose'], + 'camera_count': len(views), + 'marker_count': len(robot_markers) + } + save_json(summary, summary_path) + print(f'Saved: {summary_path}') + + +if __name__ == '__main__': + main() diff --git a/pipeline/__pycache__/2_Multiview.cpython-311.pyc b/pipeline/__pycache__/2_Multiview.cpython-311.pyc index 141feee..92ecbda 100644 Binary files a/pipeline/__pycache__/2_Multiview.cpython-311.pyc and b/pipeline/__pycache__/2_Multiview.cpython-311.pyc differ diff --git a/pipeline/multiview_pose.json b/pipeline/multiview_pose.json index 7942ef2..11a79d5 100644 --- a/pipeline/multiview_pose.json +++ b/pipeline/multiview_pose.json @@ -1,36 +1,36 @@ { "schema_version": "1.0", - "created_utc": "2026-05-28T20:33:16.813434Z", - "source_robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\robot.json", + "created_utc": "2026-05-28T21:18:54.942233Z", + "source_robot_json": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\robot.json", "source_detections": [ - "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", - "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", - "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json" + "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json" ], "robot_pose": { "state": { - "x": 216.09132484852927, - "y": 39.690843564316594, - "z": -55.07137540784025, - "a": -131.24664072646647, - "b": 22.00000000000524, - "c": 91.0000000000042, - "e": 9.999999999997005 + "x": 100.21525656040845, + "y": 29.397626553503173, + "z": -36.04825291833897, + "a": -120.21337951359496, + "b": 22.00000000000008, + "c": 90.99999999999989, + "e": 10.000000000000258 }, "uncertainty": { - "x_mm": 225.298670975141, - "y_mm": 594.8766035835473, - "z_mm": 259.0225242970393, - "a_deg": 1077.9536617200663, - "b_deg": 12207.30048251762, - "c_deg": 12207.300378181952, - "e_mm": 122073.0039182515 + "x_mm": 17194.235819424397, + "y_mm": 6014.1408132596725, + "z_mm": 3621.298501957444, + "a_deg": 8796.009134059024, + "b_deg": 12562.017200522667, + "c_deg": 12562.017199380893, + "e_mm": 125620.17196327279 }, "confidence": { - "x": 1.6421130086210916e-10, - "y": 1.4616297196124474e-26, - "z": 5.6337127678067286e-12, - "a": 1.531324732033841e-47, + "x": 0.0, + "y": 6.444409678452354e-262, + "z": 5.358019964976179e-158, + "a": 0.0, "b": 0.0, "c": 0.0, "e": 0.36787944117144233 @@ -39,22 +39,22 @@ "camera_poses": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "camera_id": "cam1", "camera_position_world_m": [ - -38.34617352837666, - -74.24635979425081, - -20.188423219708135 + -16.343352953589292, + -63.12937932142545, + -42.02161528801491 ], "rvec": [ - 111.52327474141508, - -126.11068340719217, - 44.203270370543855 + 118.44192782487391, + -119.13238841589752, + 44.062625605263676 ], "tvec": [ - 0.46738739070887664, - 3.5663317158792367, - -85.89287645773129 + 0.4631129054169859, + 3.1298682546353254, + -77.51276876640009 ], "intrinsics": { "camera_matrix": [ @@ -86,22 +86,22 @@ }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "camera_id": "cam1", "camera_position_world_m": [ - -18.749065173061467, - 50.58295606304779, - -8.605729054607524 + -57.84264421184561, + 32.9115287367793, + 4.0804577977879966 ], "rvec": [ - 0.329953779441624, - 1.990640379537416, - 1.5517306914240998 + -0.8564265551247701, + 6.744826532647081, + 4.65580193037499 ], "tvec": [ - -1.9764953616377263, - 2.0849863370638175, - -54.55243128918203 + -2.6186145648975523, + 2.5499603647238676, + -66.57500213254504 ], "intrinsics": { "camera_matrix": [ @@ -133,22 +133,22 @@ }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "camera_id": "cam1", "camera_position_world_m": [ - 0.2728534702741987, - -0.6585880592537502, - 0.4418986748635548 + 0.3512702688674852, + -1.2406150586644955, + 0.23747342372270985 ], "rvec": [ - 2.1894889099532713, - -0.20366077493465337, - -0.3361765800667276 + -4.448618579992061, + -0.5683334688730436, + 0.6217033179458588 ], "tvec": [ - -0.13776092296131418, - 0.016095933671670594, - 0.8271786602074209 + 0.020309498830570788, + 0.02559958355628428, + 1.3106648458431038 ], "intrinsics": { "camera_matrix": [ @@ -190,40 +190,40 @@ ], "size_m": 0.025, "observation_count": 3, - "mean_confidence": 0.6997700579082148, + "mean_confidence": 0.6882418402751833, "mean_detector_confidence": 0.6997700579082148, - "mean_reprojection_error_px": 348.3808535157419, + "mean_reprojection_error_px": 441.0426420373767, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.5673043275049208, - "confidence_weighted": 0.5673043275049208, + "confidence_weighted": 0.556048533067895, "quality": { "detector_confidence": 0.5673043275049208, - "weighted_confidence": 0.5673043275049208, + "weighted_confidence": 0.556048533067895, "q": { "size": 0.8108224868774414, "aspect": 0.9096486158109359, "border": 0.2833333333333333, - "center": 0.2385730743408203, + "center": 0.0, "sharpness": 1.0, "homography": 0.9999983069718208, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, - "border": 1.0, - "center": 1.0, + "size": 0.9981082248687744, + "aspect": 0.9990964861581093, + "border": 0.9928333333333333, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9999999830697182, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9801591599229813, "raw": { "mean_edge_px": 40.54112434387207, "edge_ratio": 1.1986511772098227, @@ -232,44 +232,44 @@ "laplacian_var": 3797.5312506581813 } }, - "mean_reprojection_error_px": 587.0995139995744, + "mean_reprojection_error_px": 585.2466131635871, "corner_reprojection_errors_px": [ - 612.7534949573636, - 568.3181566115126, - 561.4573585579957, - 605.8690458714257 + 610.9384647476247, + 566.4528099051602, + 559.5701708238369, + 604.0250071777266 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.7813266383036261, - "confidence_weighted": 0.7813266383036261, + "confidence_weighted": 0.7686240953581938, "quality": { "detector_confidence": 0.7813266383036261, - "weighted_confidence": 0.7813266383036261, + "weighted_confidence": 0.7686240953581938, "q": { "size": 0.7824347686767578, "aspect": 0.8792155830729744, "border": 1.0, - "center": 0.49675697088241577, + "center": 0.0, "sharpness": 0.9904164099455028, "homography": 0.7145588675251666, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9978243476867675, + "aspect": 0.9987921558307298, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.999904164099455, + "homography": 0.9971455886752516, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9837423398579991, "raw": { "mean_edge_px": 39.12173843383789, "edge_ratio": 1.274754950327127, @@ -278,44 +278,44 @@ "laplacian_var": 2476.0410248637572 } }, - "mean_reprojection_error_px": 427.8772796416253, + "mean_reprojection_error_px": 432.8261187281506, "corner_reprojection_errors_px": [ - 446.3587605969117, - 404.1867109578964, - 408.4069136534603, - 452.55673335823275 + 451.23541594327764, + 408.7849241393045, + 413.4238931097967, + 457.8602417202238 ] }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.7506792079160973, - "confidence_weighted": 0.7506792079160973, + "confidence_weighted": 0.740052892399461, "quality": { "detector_confidence": 0.7506792079160973, - "weighted_confidence": 0.7506792079160973, + "weighted_confidence": 0.740052892399461, "q": { "size": 0.8434026336669922, "aspect": 0.8575862494073492, "border": 1.0, - "center": 0.6442468464374542, + "center": 0.0, "sharpness": 1.0, "homography": 0.8786678750976363, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9984340263366699, + "aspect": 0.9985758624940735, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9987866787509764, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9858443987730322, "raw": { "mean_edge_px": 42.17013168334961, "edge_ratio": 1.3321269451115116, @@ -324,12 +324,12 @@ "laplacian_var": 2842.0926549741707 } }, - "mean_reprojection_error_px": 30.16576690602588, + "mean_reprojection_error_px": 305.0551942203927, "corner_reprojection_errors_px": [ - 36.22778096708586, - 21.548187717111936, - 42.84248647061261, - 20.044612469293106 + 336.8958377277025, + 282.2427865676158, + 272.7772202436447, + 328.3049323426078 ] } ] @@ -344,40 +344,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.6412317666518965, + "mean_confidence": 0.6305246964757232, "mean_detector_confidence": 0.6412317666518965, - "mean_reprojection_error_px": 213.51155158837116, + "mean_reprojection_error_px": 211.60483046120936, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.6412317666518965, - "confidence_weighted": 0.6412317666518965, + "confidence_weighted": 0.6305246964757232, "quality": { "detector_confidence": 0.6412317666518965, - "weighted_confidence": 0.6412317666518965, + "weighted_confidence": 0.6305246964757232, "q": { "size": 0.6744685745239258, "aspect": 0.9460729944417767, "border": 1.0, - "center": 0.7332987189292908, + "center": 0.0, "sharpness": 1.0, "homography": 0.7016198391981602, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9967446857452392, + "aspect": 0.9994607299444178, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9970161983919816, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9833023397576218, "raw": { "mean_edge_px": 33.72342872619629, "edge_ratio": 1.1140017860673477, @@ -386,12 +386,12 @@ "laplacian_var": 3165.7184033540047 } }, - "mean_reprojection_error_px": 213.51155158837116, + "mean_reprojection_error_px": 211.60483046120936, "corner_reprojection_errors_px": [ - 236.74653013262179, - 201.34252196509405, - 190.76098744554534, - 225.1961668102236 + 234.98916143435187, + 199.5386782266223, + 188.70294650504465, + 223.18853567881862 ] } ] @@ -406,40 +406,40 @@ ], "size_m": 0.025, "observation_count": 2, - "mean_confidence": 0.8108527003549935, + "mean_confidence": 0.7997306526656554, "mean_detector_confidence": 0.8108527003549935, - "mean_reprojection_error_px": 159.0807109791299, + "mean_reprojection_error_px": 157.11052614310307, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.7952557920267838, - "confidence_weighted": 0.7952557920267838, + "confidence_weighted": 0.7849458403437536, "quality": { "detector_confidence": 0.7952557920267838, - "weighted_confidence": 0.7952557920267838, + "weighted_confidence": 0.7849458403437536, "q": { "size": 0.7146316909790039, "aspect": 0.9859016728248396, "border": 1.0, - "center": 0.786280557513237, + "center": 0.0, "sharpness": 1.0, "homography": 1.0, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.99714631690979, + "aspect": 0.9998590167282484, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, "homography": 1.0, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9870356786000208, "raw": { "mean_edge_px": 35.731584548950195, "edge_ratio": 1.0285998645985972, @@ -448,44 +448,44 @@ "laplacian_var": 3704.0260869185627 } }, - "mean_reprojection_error_px": 202.87090079707735, + "mean_reprojection_error_px": 200.42541542932048, "corner_reprojection_errors_px": [ - 216.05481694083824, - 182.3251487108743, - 191.11678207445826, - 221.98685546213872 + 213.57305595230443, + 179.84901855319694, + 188.742976102597, + 219.5366111091836 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.826449608683203, - "confidence_weighted": 0.826449608683203, + "confidence_weighted": 0.8145154649875572, "quality": { "detector_confidence": 0.826449608683203, - "weighted_confidence": 0.826449608683203, + "weighted_confidence": 0.8145154649875572, "q": { "size": 0.8409605407714844, "aspect": 0.9049793706370471, "border": 1.0, - "center": 0.9083917960524559, + "center": 0.0, "sharpness": 0.8049029197222222, "homography": 1.0, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9984096054077148, + "aspect": 0.9990497937063705, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, + "center": 0.99, + "sharpness": 0.9980490291972222, "homography": 1.0, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9855597442720546, "raw": { "mean_edge_px": 42.04802703857422, "edge_ratio": 1.2099951279465397, @@ -494,12 +494,12 @@ "laplacian_var": 2012.2572993055553 } }, - "mean_reprojection_error_px": 115.2905211611824, + "mean_reprojection_error_px": 113.79563685688566, "corner_reprojection_errors_px": [ - 102.14384765398431, - 92.14591665858303, - 129.81168442827544, - 137.0606359038868 + 100.764594616081, + 90.3700880410387, + 128.18921061659032, + 135.8586541538326 ] } ] @@ -514,40 +514,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.6041252446922665, + "mean_confidence": 0.5924337979452556, "mean_detector_confidence": 0.6041252446922665, - "mean_reprojection_error_px": 338.5476435670504, + "mean_reprojection_error_px": 175.5030184777268, "observations": [ { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.6041252446922665, - "confidence_weighted": 0.6041252446922665, + "confidence_weighted": 0.5924337979452556, "quality": { "detector_confidence": 0.6041252446922665, - "weighted_confidence": 0.6041252446922665, + "weighted_confidence": 0.5924337979452556, "q": { "size": 0.9836519622802734, "aspect": 0.7532145593882991, "border": 1.0, - "center": 0.32276880741119385, + "center": 0.0, "sharpness": 0.5256355772646303, "homography": 0.7899472530560614, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9998365196228027, + "aspect": 0.997532145593883, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9952563557726463, + "homography": 0.9978994725305605, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.980647313036941, "raw": { "mean_edge_px": 49.18259811401367, "edge_ratio": 1.655285901037602, @@ -556,12 +556,12 @@ "laplacian_var": 1314.0889431615756 } }, - "mean_reprojection_error_px": 338.5476435670504, + "mean_reprojection_error_px": 175.5030184777268, "corner_reprojection_errors_px": [ - 334.40236466141283, - 319.8057940927665, - 346.37370249262483, - 353.6087130213974 + 174.74636916466218, + 153.27311517519206, + 183.05906730414804, + 190.93352226690504 ] } ] @@ -576,40 +576,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.6280424706698967, + "mean_confidence": 0.6179064007574118, "mean_detector_confidence": 0.6280424706698967, - "mean_reprojection_error_px": 100.412293994181, + "mean_reprojection_error_px": 98.18080189388743, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.6280424706698967, - "confidence_weighted": 0.6280424706698967, + "confidence_weighted": 0.6179064007574118, "quality": { "detector_confidence": 0.6280424706698967, - "weighted_confidence": 0.6280424706698967, + "weighted_confidence": 0.6179064007574118, "q": { "size": 0.6625362014770508, "aspect": 0.9537163525948422, "border": 1.0, - "center": 0.9434776194393635, + "center": 0.0, "sharpness": 1.0, "homography": 0.7625645902124035, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9966253620147705, + "aspect": 0.9995371635259485, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.997625645902124, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9838608527514494, "raw": { "mean_edge_px": 33.12681007385254, "edge_ratio": 1.0970595655180506, @@ -618,12 +618,12 @@ "laplacian_var": 2848.9886204705635 } }, - "mean_reprojection_error_px": 100.412293994181, + "mean_reprojection_error_px": 98.18080189388743, "corner_reprojection_errors_px": [ - 95.36403494262059, - 79.9557213035894, - 108.22499615920151, - 118.10442357131254 + 92.6502159223099, + 77.77959676707061, + 106.52467862737805, + 115.76871625879116 ] } ] @@ -638,40 +638,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.33820423087105295, + "mean_confidence": 0.33185586633646474, "mean_detector_confidence": 0.33820423087105295, - "mean_reprojection_error_px": 276.15167212095713, + "mean_reprojection_error_px": 278.58790262226194, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.33820423087105295, - "confidence_weighted": 0.33820423087105295, + "confidence_weighted": 0.33185586633646474, "quality": { "detector_confidence": 0.33820423087105295, - "weighted_confidence": 0.33820423087105295, + "weighted_confidence": 0.33185586633646474, "q": { "size": 0.5361141967773437, "aspect": 0.8936906729306451, "border": 0.9833333333333333, - "center": 0.5868735313415527, + "center": 0.0, "sharpness": 1.0, "homography": 0.6985669093200941, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, - "border": 1.0, - "center": 1.0, + "size": 0.9953611419677735, + "aspect": 0.9989369067293065, + "border": 0.9998333333333334, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.996985669093201, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9812291983508372, "raw": { "mean_edge_px": 26.805709838867188, "edge_ratio": 1.2379107901411548, @@ -680,12 +680,12 @@ "laplacian_var": 4112.338450277431 } }, - "mean_reprojection_error_px": 276.15167212095713, + "mean_reprojection_error_px": 278.58790262226194, "corner_reprojection_errors_px": [ - 257.9111382626554, - 282.35364104879613, - 294.3934037418535, - 269.9485054305234 + 260.5220487854409, + 284.9566681230145, + 296.68536419274807, + 272.18752938784417 ] } ] @@ -700,40 +700,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.28724459014346065, + "mean_confidence": 0.2820948444008322, "mean_detector_confidence": 0.28724459014346065, - "mean_reprojection_error_px": 426.6190397265363, + "mean_reprojection_error_px": 428.543316908284, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.28724459014346065, - "confidence_weighted": 0.28724459014346065, + "confidence_weighted": 0.2820948444008322, "quality": { "detector_confidence": 0.28724459014346065, - "weighted_confidence": 0.28724459014346065, + "weighted_confidence": 0.2820948444008322, "q": { "size": 0.5248580741882324, "aspect": 0.839187418386558, "border": 0.8333333333333334, - "center": 0.4003753066062927, + "center": 0.0, "sharpness": 1.0, "homography": 0.9999815099800249, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, - "border": 1.0, - "center": 1.0, + "size": 0.9952485807418823, + "aspect": 0.9983918741838655, + "border": 0.9983333333333333, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9999998150998003, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9820719139042569, "raw": { "mean_edge_px": 26.24290370941162, "edge_ratio": 1.383257847031654, @@ -742,12 +742,12 @@ "laplacian_var": 5067.414824476962 } }, - "mean_reprojection_error_px": 426.6190397265363, + "mean_reprojection_error_px": 428.543316908284, "corner_reprojection_errors_px": [ - 406.15079651506966, - 428.05267082059254, - 446.9579519399622, - 425.3147396305208 + 408.1250357795538, + 430.13216881859233, + 448.84097211823865, + 427.0750909167511 ] } ] @@ -762,40 +762,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.27228561618555186, + "mean_confidence": 0.2656859333164099, "mean_detector_confidence": 0.27228561618555186, - "mean_reprojection_error_px": 374.50255105417807, + "mean_reprojection_error_px": 376.9955122102373, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.27228561618555186, - "confidence_weighted": 0.27228561618555186, + "confidence_weighted": 0.2656859333164099, "quality": { "detector_confidence": 0.27228561618555186, - "weighted_confidence": 0.27228561618555186, + "weighted_confidence": 0.2656859333164099, "q": { "size": 0.5014523983001709, "aspect": 0.8554115971298921, "border": 0.5, - "center": 0.4565395712852478, + "center": 0.0, "sharpness": 1.0, "homography": 0.6975670005943979, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, - "border": 1.0, - "center": 1.0, + "size": 0.9950145239830017, + "aspect": 0.998554115971299, + "border": 0.995, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.996975670005944, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9757619114751748, "raw": { "mean_edge_px": 25.072619915008545, "edge_ratio": 1.3380557461583085, @@ -804,12 +804,12 @@ "laplacian_var": 4016.6321593416924 } }, - "mean_reprojection_error_px": 374.50255105417807, + "mean_reprojection_error_px": 376.9955122102373, "corner_reprojection_errors_px": [ - 357.4436839806056, - 379.04037742345474, - 391.88854109463733, - 369.63760171801465 + 360.06398388824374, + 381.6816681569444, + 394.27105560686095, + 371.9653411889002 ] } ] @@ -824,40 +824,40 @@ ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.35596573288593486, + "mean_confidence": 0.3494362969135403, "mean_detector_confidence": 0.35596573288593486, - "mean_reprojection_error_px": 330.11805773797414, + "mean_reprojection_error_px": 331.82951948750804, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.35596573288593486, - "confidence_weighted": 0.35596573288593486, + "confidence_weighted": 0.3494362969135403, "quality": { "detector_confidence": 0.35596573288593486, - "weighted_confidence": 0.35596573288593486, + "weighted_confidence": 0.3494362969135403, "q": { "size": 0.5561128711700439, "aspect": 0.8721453879265322, "border": 1.0, - "center": 0.5334544777870178, + "center": 0.0, "sharpness": 1.0, "homography": 0.726899391813532, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9955611287117004, + "aspect": 0.9987214538792654, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9972689939181353, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9816571221070685, "raw": { "mean_edge_px": 27.805643558502197, "edge_ratio": 1.2931956388084183, @@ -866,12 +866,12 @@ "laplacian_var": 3793.153007417641 } }, - "mean_reprojection_error_px": 330.11805773797414, + "mean_reprojection_error_px": 331.82951948750804, "corner_reprojection_errors_px": [ - 308.2113330466644, - 332.08999978676184, - 351.98742228618335, - 328.1834758322872 + 309.97533094447215, + 333.9867434221059, + 353.66344926865025, + 329.6925543148037 ] } ] @@ -880,46 +880,46 @@ "marker_id": 198, "link_name": "Arm1", "position_world_m": [ - 0.21609132484852928, - -0.10076769046005479, - 0.12911573319834646 + 0.10021525656040844, + -0.12221709509972764, + 0.10903202128450216 ], "size_m": 0.025, "observation_count": 2, - "mean_confidence": 0.16652042240877096, + "mean_confidence": 0.1628904920977715, "mean_detector_confidence": 0.16652042240877096, - "mean_reprojection_error_px": 243.66958450030666, + "mean_reprojection_error_px": 245.0843876652231, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.20150745250271476, - "confidence_weighted": 0.20150745250271476, + "confidence_weighted": 0.19749969171522036, "quality": { "detector_confidence": 0.20150745250271476, - "weighted_confidence": 0.20150745250271476, + "weighted_confidence": 0.19749969171522036, "q": { "size": 0.6339855194091797, "aspect": 0.7539930512070505, "border": 1.0, - "center": 0.6189768612384796, + "center": 0.0, "sharpness": 1.0, "homography": 0.6098583763162305, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9963398551940917, + "aspect": 0.9975399305120705, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9960985837631623, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9801111038935872, "raw": { "mean_edge_px": 31.699275970458984, "edge_ratio": 1.652544339497884, @@ -928,44 +928,44 @@ "laplacian_var": 3972.096222043203 } }, - "mean_reprojection_error_px": 248.654861221765, + "mean_reprojection_error_px": 248.07751803913456, "corner_reprojection_errors_px": [ - 274.50699319923274, - 246.03321812358865, - 223.2084648682347, - 250.8707686960039 + 273.96976726259226, + 245.4724112741704, + 222.59090992086755, + 250.2769836989081 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.13153339231482716, - "confidence_weighted": 0.13153339231482716, + "confidence_weighted": 0.12828129248032266, "quality": { "detector_confidence": 0.13153339231482716, - "weighted_confidence": 0.13153339231482716, + "weighted_confidence": 0.12828129248032266, "q": { "size": 0.6576880264282227, "aspect": 0.42738020051250675, "border": 0.5916666666666667, - "center": 0.6157204806804657, + "center": 0.0, "sharpness": 0.9362022578647182, "homography": 0.8917140926962271, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, - "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "size": 0.9965768802642823, + "aspect": 0.994273802005125, + "border": 0.9959166666666667, + "center": 0.99, + "sharpness": 0.9993620225786471, + "homography": 0.9989171409269623, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9752754811742362, "raw": { "mean_edge_px": 32.88440132141113, "edge_ratio": 3.6796739708616246, @@ -974,12 +974,12 @@ "laplacian_var": 2340.5056446617955 } }, - "mean_reprojection_error_px": 238.6843077788483, + "mean_reprojection_error_px": 242.0912572913116, "corner_reprojection_errors_px": [ - 255.20670426390527, - 233.9309789087676, - 221.28127646869942, - 244.318271474021 + 258.3749702118821, + 237.59562364753367, + 224.8980425891153, + 247.4963927167153 ] } ] @@ -988,46 +988,46 @@ "marker_id": 229, "link_name": "Arm1", "position_world_m": [ - 0.21609132484852928, - -0.1700228368607847, - 0.18659376984725667 + 0.10021525656040844, + -0.2006281682211539, + 0.15321011101172263 ], "size_m": 0.025, "observation_count": 2, - "mean_confidence": 0.2274747191640703, + "mean_confidence": 0.22245621469865084, "mean_detector_confidence": 0.2274747191640703, - "mean_reprojection_error_px": 172.23377000525875, + "mean_reprojection_error_px": 173.6079280482102, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.26810902547334975, - "confidence_weighted": 0.26810902547334975, + "confidence_weighted": 0.2630164795315655, "quality": { "detector_confidence": 0.26810902547334975, - "weighted_confidence": 0.26810902547334975, + "weighted_confidence": 0.2630164795315655, "q": { "size": 0.6824631023406983, "aspect": 0.7938768481947832, "border": 1.0, - "center": 0.733243316411972, + "center": 0.0, "sharpness": 0.9086003975826067, "homography": 0.7035912150387432, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.996824631023407, + "aspect": 0.9979387684819478, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.999086003975826, + "homography": 0.9970359121503874, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9810056900069167, "raw": { "mean_edge_px": 34.12315511703491, "edge_ratio": 1.5192824359947652, @@ -1036,44 +1036,44 @@ "laplacian_var": 2271.5009939565166 } }, - "mean_reprojection_error_px": 155.22297984485186, + "mean_reprojection_error_px": 154.45285855459778, "corner_reprojection_errors_px": [ - 179.66512440166122, - 156.3996648998681, - 130.99743974604678, - 153.82969033183136 + 178.89833200454908, + 155.66332803657198, + 130.23647076368366, + 153.01330341358639 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.18684041285479083, - "confidence_weighted": 0.18684041285479083, + "confidence_weighted": 0.18189594986573623, "quality": { "detector_confidence": 0.18684041285479083, - "weighted_confidence": 0.18684041285479083, + "weighted_confidence": 0.18189594986573623, "q": { "size": 0.7395829486846924, "aspect": 0.44796521997625727, "border": 1.0, - "center": 0.6955729424953461, + "center": 0.0, "sharpness": 0.5568649165432099, "homography": 0.5823463065693475, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9973958294868469, + "aspect": 0.9944796521997625, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9955686491654321, + "homography": 0.9958234630656935, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9735364372540894, "raw": { "mean_edge_px": 36.97914743423462, "edge_ratio": 3.4646323214690695, @@ -1082,12 +1082,12 @@ "laplacian_var": 1392.1622913580247 } }, - "mean_reprojection_error_px": 189.24456016566566, + "mean_reprojection_error_px": 192.76299754182264, "corner_reprojection_errors_px": [ - 210.91668755526047, - 180.02751146800094, - 165.080603015969, - 200.95343862343222 + 214.02378857320852, + 184.04050020559077, + 168.9825131053272, + 204.00518828316393 ] } ] @@ -1096,9 +1096,9 @@ "marker_id": 242, "link_name": "Arm1", "position_world_m": [ - 0.21609132484852928, - -0.21472797647660377, - 0.13272865598002226 + 0.10021525656040844, + -0.23498890467565872, + 0.09222372080616886 ], "size_m": 0.025, "observation_count": 0, @@ -1111,46 +1111,46 @@ "marker_id": 243, "link_name": "Arm1", "position_world_m": [ - 0.21609132484852928, - -0.21930796360231145, - 0.182013782721549 + 0.10021525656040844, + -0.2483017315511832, + 0.13989728413619817 ], "size_m": 0.025, "observation_count": 3, - "mean_confidence": 0.9174550709990235, + "mean_confidence": 0.903504284314228, "mean_detector_confidence": 0.9174550709990235, - "mean_reprojection_error_px": 76.42176737251886, + "mean_reprojection_error_px": 81.5029264885797, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.8899728634608616, - "confidence_weighted": 0.8899728634608616, + "confidence_weighted": 0.8780472636948905, "quality": { "detector_confidence": 0.8899728634608616, - "weighted_confidence": 0.8899728634608616, + "weighted_confidence": 0.8780472636948905, "q": { "size": 0.8810945701599121, "aspect": 0.9417837479752699, "border": 1.0, - "center": 0.8596725612878799, + "center": 0.0, "sharpness": 1.0, "homography": 0.8333271723300208, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9988109457015991, + "aspect": 0.9994178374797527, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9983332717233002, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9866000411297984, "raw": { "mean_edge_px": 44.054728507995605, "edge_ratio": 1.1236297656439467, @@ -1159,28 +1159,28 @@ "laplacian_var": 2678.6956247003295 } }, - "mean_reprojection_error_px": 77.81290659108863, + "mean_reprojection_error_px": 76.87929689884885, "corner_reprojection_errors_px": [ - 100.17650566852666, - 71.07480085005695, - 49.77846871424659, - 90.22185113152435 + 99.14225948732798, + 70.2117506861392, + 48.833911722956465, + 89.3292656989718 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.9132502955127223, - "confidence_weighted": 0.9132502955127223, + "confidence_weighted": 0.8990944567220429, "quality": { "detector_confidence": 0.9132502955127223, - "weighted_confidence": 0.9132502955127223, + "weighted_confidence": 0.8990944567220429, "q": { "size": 1.0, "aspect": 0.9546584653922503, "border": 1.0, - "center": 0.8345897197723389, + "center": 0.0, "sharpness": 0.5809177986450728, "homography": 0.9082012101971718, "normal_visibility": 1.0, @@ -1188,15 +1188,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9995465846539225, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9958091779864507, + "homography": 0.9990820121019717, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9844994971693583, "raw": { "mean_edge_px": 55.26974582672119, "edge_ratio": 1.0949900645130086, @@ -1205,28 +1205,28 @@ "laplacian_var": 1452.2944966126818 } }, - "mean_reprojection_error_px": 122.71205765924921, + "mean_reprojection_error_px": 123.84143010803572, "corner_reprojection_errors_px": [ - 157.5892876335061, - 109.93561027893956, - 83.96066221414912, - 139.36267051040204 + 159.2946943920584, + 112.54406878360543, + 84.16105909185964, + 139.36589816461947 ] }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.9491420540234864, - "confidence_weighted": 0.9491420540234864, + "confidence_weighted": 0.9333711325257503, "quality": { "detector_confidence": 0.9491420540234864, - "weighted_confidence": 0.9491420540234864, + "weighted_confidence": 0.9333711325257503, "q": { "size": 1.0, "aspect": 0.9739075220959238, "border": 1.0, - "center": 0.8123328536748886, + "center": 0.0, "sharpness": 0.43477113518953137, "homography": 0.9224349218355518, "normal_visibility": 1.0, @@ -1234,15 +1234,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9997390752209593, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9943477113518953, + "homography": 0.9992243492183555, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9833840240974658, "raw": { "mean_edge_px": 75.11714553833008, "edge_ratio": 1.0535830709016873, @@ -1251,12 +1251,12 @@ "laplacian_var": 1086.9278379738284 } }, - "mean_reprojection_error_px": 28.740337867218727, + "mean_reprojection_error_px": 43.788052458854565, "corner_reprojection_errors_px": [ - 13.91523395008655, - 28.107202384113876, - 48.80100478346, - 24.137910351214487 + 66.92563132518778, + 41.81087505439111, + 17.311321747071958, + 49.104381708767434 ] } ] @@ -1265,7 +1265,7 @@ "marker_id": 244, "link_name": "Ellbow", "position_world_m": [ - 0.3410913248485293, + 0.22521525656040844, 0.0, 0.0 ], @@ -1280,9 +1280,9 @@ "marker_id": 245, "link_name": "Ellbow", "position_world_m": [ - 0.3060913248485293, - 0.009282998148214212, - -0.03374649530514616 + 0.19021525656040844, + 0.004053519626182114, + -0.03476447869075785 ], "size_m": 0.025, "observation_count": 0, @@ -1295,46 +1295,46 @@ "marker_id": 246, "link_name": "Ellbow", "position_world_m": [ - 0.3060913248485293, - -0.009282998148214212, - 0.03374649530514616 + 0.19021525656040844, + -0.004053519626182114, + 0.03476447869075785 ], "size_m": 0.025, "observation_count": 3, - "mean_confidence": 0.6792447690577089, + "mean_confidence": 0.6682660968032644, "mean_detector_confidence": 0.6792447690577089, - "mean_reprojection_error_px": 112.48128522376857, + "mean_reprojection_error_px": 161.1324352664503, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.8015179238063419, - "confidence_weighted": 0.8015179238063419, + "confidence_weighted": 0.7895911927962278, "quality": { "detector_confidence": 0.8015179238063419, - "weighted_confidence": 0.8015179238063419, + "weighted_confidence": 0.7895911927962278, "q": { "size": 0.7650188636779786, "aspect": 0.9580747137765034, "border": 1.0, - "center": 0.7408380806446075, + "center": 0.0, "sharpness": 1.0, "homography": 0.7832604752816245, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9976501886367798, + "aspect": 0.999580747137765, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9978326047528162, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9851198199617608, "raw": { "mean_edge_px": 38.250943183898926, "edge_ratio": 1.0875198679615226, @@ -1343,28 +1343,28 @@ "laplacian_var": 3236.7051337367984 } }, - "mean_reprojection_error_px": 133.93671094067233, + "mean_reprojection_error_px": 134.6218442755581, "corner_reprojection_errors_px": [ - 134.92477269026298, - 152.54499570886057, - 136.3819175139715, - 111.89515784959431 + 135.7150033827045, + 153.20493069778522, + 136.97402164430275, + 112.59342137743992 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.7581700566520715, - "confidence_weighted": 0.7581700566520715, + "confidence_weighted": 0.7467269698455701, "quality": { "detector_confidence": 0.7581700566520715, - "weighted_confidence": 0.7581700566520715, + "weighted_confidence": 0.7467269698455701, "q": { "size": 1.0, "aspect": 0.8624536105407097, "border": 1.0, - "center": 0.6523004770278931, + "center": 0.0, "sharpness": 0.7134050632712029, "homography": 0.9089132203508788, "normal_visibility": 1.0, @@ -1372,15 +1372,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9986245361054071, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.997134050632712, + "homography": 0.9990891322035088, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9849069655203322, "raw": { "mean_edge_px": 50.77022838592529, "edge_ratio": 1.3189653049815784, @@ -1389,28 +1389,28 @@ "laplacian_var": 1783.5126581780073 } }, - "mean_reprojection_error_px": 163.5949522441255, + "mean_reprojection_error_px": 166.1189645701224, "corner_reprojection_errors_px": [ - 164.9348955776692, - 195.44647967290177, - 166.50970828513942, - 127.48872544079168 + 167.75756135019049, + 198.24116321049402, + 168.6490336545454, + 129.8281000652596 ] }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.4780463267147134, - "confidence_weighted": 0.4780463267147134, + "confidence_weighted": 0.46848012776799536, "quality": { "detector_confidence": 0.4780463267147134, - "weighted_confidence": 0.4780463267147134, + "weighted_confidence": 0.46848012776799536, "q": { "size": 1.0, "aspect": 0.6468624400661076, "border": 1.0, - "center": 0.468610942363739, + "center": 0.0, "sharpness": 0.6283678308439046, "homography": 0.7101453224803067, "normal_visibility": 1.0, @@ -1418,15 +1418,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9964686244006611, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.996283678308439, + "homography": 0.997101453224803, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9799889709174003, "raw": { "mean_edge_px": 59.82627487182617, "edge_ratio": 2.0918474719224776, @@ -1435,12 +1435,12 @@ "laplacian_var": 1570.9195771097613 } }, - "mean_reprojection_error_px": 39.91219248650781, + "mean_reprojection_error_px": 182.65649695367037, "corner_reprojection_errors_px": [ - 41.72658331078573, - 33.04479526975366, - 66.19011920628998, - 18.687272159201875 + 186.41931794153945, + 204.89340651658281, + 185.29874269593594, + 154.01452066062325 ] } ] @@ -1449,46 +1449,46 @@ "marker_id": 247, "link_name": "Ellbow", "position_world_m": [ - 0.26859132484852927, - -0.009282998148214212, - 0.03374649530514616 + 0.15271525656040844, + -0.004053519626182114, + 0.03476447869075785 ], "size_m": 0.025, "observation_count": 3, - "mean_confidence": 0.7117000257529918, + "mean_confidence": 0.7010103986241017, "mean_detector_confidence": 0.7117000257529918, - "mean_reprojection_error_px": 102.31904563726128, + "mean_reprojection_error_px": 146.47131004262607, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.8796777163094818, - "confidence_weighted": 0.8796777163094818, + "confidence_weighted": 0.8670496997853304, "quality": { "detector_confidence": 0.8796777163094818, - "weighted_confidence": 0.8796777163094818, + "weighted_confidence": 0.8670496997853304, "q": { "size": 0.7921941375732422, "aspect": 0.9657885238796377, "border": 1.0, - "center": 0.7714440822601318, + "center": 0.0, "sharpness": 1.0, "homography": 0.8015391946807702, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9979219413757324, + "aspect": 0.9996578852387964, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9980153919468077, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9856447238687257, "raw": { "mean_edge_px": 39.60970687866211, "edge_ratio": 1.0708467232203849, @@ -1497,28 +1497,28 @@ "laplacian_var": 4202.582433286217 } }, - "mean_reprojection_error_px": 112.21393223629931, + "mean_reprojection_error_px": 112.65188559107314, "corner_reprojection_errors_px": [ - 128.20833066079467, - 129.7787908831529, - 100.21730102185268, - 90.65130637939703 + 128.71700121736973, + 130.18085487709857, + 100.60148705412828, + 91.10819921569595 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.7448005120854795, - "confidence_weighted": 0.7448005120854795, + "confidence_weighted": 0.7340842516844052, "quality": { "detector_confidence": 0.7448005120854795, - "weighted_confidence": 0.7448005120854795, + "weighted_confidence": 0.7340842516844052, "q": { "size": 1.0, "aspect": 0.8537371543928008, "border": 1.0, - "center": 0.7152222096920013, + "center": 0.0, "sharpness": 0.8698383110697441, "homography": 0.8325296434913341, "normal_visibility": 1.0, @@ -1526,15 +1526,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.998537371543928, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9986983831106975, + "homography": 0.9983252964349133, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9856119051649572, "raw": { "mean_edge_px": 51.05013561248779, "edge_ratio": 1.3426413969560103, @@ -1543,28 +1543,28 @@ "laplacian_var": 2174.5957776743603 } }, - "mean_reprojection_error_px": 133.70775260569667, + "mean_reprojection_error_px": 136.19499595934474, "corner_reprojection_errors_px": [ - 153.58015251204978, - 156.00959760114938, - 114.82745208859265, - 110.41380822099482 + 156.16137047168513, + 158.6202327519144, + 117.10218236400607, + 112.89619824977336 ] }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.5106218488640142, - "confidence_weighted": 0.5106218488640142, + "confidence_weighted": 0.5018972444025696, "quality": { "detector_confidence": 0.5106218488640142, - "weighted_confidence": 0.5106218488640142, + "weighted_confidence": 0.5018972444025696, "q": { "size": 1.0, "aspect": 0.6760419217397143, "border": 1.0, - "center": 0.5872762501239777, + "center": 0.0, "sharpness": 0.9265392364192184, "homography": 0.6801291688207284, "normal_visibility": 1.0, @@ -1572,15 +1572,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9967604192173971, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9992653923641922, + "homography": 0.9968012916882073, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9829137658702729, "raw": { "mean_edge_px": 58.36018657684326, "edge_ratio": 1.958396418454695, @@ -1589,12 +1589,12 @@ "laplacian_var": 2316.348091048046 } }, - "mean_reprojection_error_px": 61.03545206978789, + "mean_reprojection_error_px": 190.5670485774603, "corner_reprojection_errors_px": [ - 81.11386344556932, - 67.01512262029568, - 55.69321608125353, - 40.319606132033016 + 210.72653639156906, + 204.3452514096146, + 172.84658735917168, + 174.349819149486 ] } ] @@ -1603,46 +1603,46 @@ "marker_id": 124, "link_name": "Arm2", "position_world_m": [ - 0.18116461496794556, - -0.10738107374625039, - -0.03191480750403911 + 0.06637262457056678, + -0.11021173982435686, + -0.0218443050905359 ], "size_m": 0.025, "observation_count": 2, - "mean_confidence": 0.4106676690676095, + "mean_confidence": 0.4015628677453015, "mean_detector_confidence": 0.4106676690676095, - "mean_reprojection_error_px": 260.0804359426223, + "mean_reprojection_error_px": 259.7297501072294, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.34091855704160245, - "confidence_weighted": 0.34091855704160245, + "confidence_weighted": 0.33488305339370045, "quality": { "detector_confidence": 0.34091855704160245, - "weighted_confidence": 0.34091855704160245, + "weighted_confidence": 0.33488305339370045, "q": { "size": 0.7142756080627441, "aspect": 0.7379840018220383, "border": 1.0, - "center": 0.8538652509450912, + "center": 0.0, "sharpness": 1.0, "homography": 0.7675736815140904, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9971427560806274, + "aspect": 0.9973798400182203, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9976757368151409, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9822963475491728, "raw": { "mean_edge_px": 35.71378040313721, "edge_ratio": 1.7100858488288635, @@ -1651,28 +1651,28 @@ "laplacian_var": 3569.5639450778804 } }, - "mean_reprojection_error_px": 133.7951322833782, + "mean_reprojection_error_px": 134.91037554166337, "corner_reprojection_errors_px": [ - 119.77684898897931, - 102.66323049904321, - 148.05883888894743, - 164.6816107565428 + 120.9873933400657, + 103.67198851474541, + 149.06804198829764, + 165.91407832354471 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.4804167810936165, - "confidence_weighted": 0.4804167810936165, + "confidence_weighted": 0.46824268209690245, "quality": { "detector_confidence": 0.4804167810936165, - "weighted_confidence": 0.4804167810936165, + "weighted_confidence": 0.46824268209690245, "q": { "size": 1.0, "aspect": 0.9604332717578841, "border": 0.21666666666666667, - "center": 0.49520277976989746, + "center": 0.0, "sharpness": 0.5040158791602892, "homography": 0.7617971982706998, "normal_visibility": 1.0, @@ -1680,15 +1680,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, - "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "aspect": 0.9996043327175789, + "border": 0.9921666666666666, + "center": 0.99, + "sharpness": 0.9950401587916029, + "homography": 0.997617971982707, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9746592969358792, "raw": { "mean_edge_px": 61.16414737701416, "edge_ratio": 1.0823934976132112, @@ -1697,12 +1697,12 @@ "laplacian_var": 1260.039697900723 } }, - "mean_reprojection_error_px": 386.36573960186644, + "mean_reprojection_error_px": 384.5491246727954, "corner_reprojection_errors_px": [ - 336.07046868011287, - 377.8751921124279, - 434.5865464648627, - 396.9307511500621 + 334.3673362766447, + 376.12029027919453, + 432.6602329793538, + 395.04863915598855 ] } ] @@ -1711,46 +1711,46 @@ "marker_id": 122, "link_name": "Arm2", "position_world_m": [ - 0.2391668855143965, - -0.11496847136439253, - -0.004332331022756229 + 0.11782801799927344, + -0.11474921044648306, + 0.017070715755537844 ], "size_m": 0.025, "observation_count": 3, - "mean_confidence": 0.5690911450460799, + "mean_confidence": 0.5578116149791655, "mean_detector_confidence": 0.5690911450460799, - "mean_reprojection_error_px": 156.68910851305085, + "mean_reprojection_error_px": 185.0724839723273, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.18665602922528673, - "confidence_weighted": 0.18665602922528673, + "confidence_weighted": 0.18263714689166236, "quality": { "detector_confidence": 0.18665602922528673, - "weighted_confidence": 0.18665602922528673, + "weighted_confidence": 0.18263714689166236, "q": { "size": 0.7027967643737792, "aspect": 0.654945658590568, "border": 1.0, - "center": 0.720594972372055, + "center": 0.0, "sharpness": 0.9331720780648362, "homography": 0.539630944261658, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9970279676437378, + "aspect": 0.9965494565859057, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9993317207806484, + "homography": 0.9953963094426166, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9784690462434849, "raw": { "mean_edge_px": 35.139838218688965, "edge_ratio": 2.0536884606639982, @@ -1759,28 +1759,28 @@ "laplacian_var": 2332.9301951620905 } }, - "mean_reprojection_error_px": 193.48950896029461, + "mean_reprojection_error_px": 194.5564447603344, "corner_reprojection_errors_px": [ - 163.89399315841172, - 190.3342215815896, - 221.39744874765296, - 198.33237235352422 + 164.85878003772754, + 191.48901171235315, + 222.56759495263603, + 199.31039233862094 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.9456847621099602, - "confidence_weighted": 0.9456847621099602, + "confidence_weighted": 0.9281720009504786, "quality": { "detector_confidence": 0.9456847621099602, - "weighted_confidence": 0.9456847621099602, + "weighted_confidence": 0.9281720009504786, "q": { "size": 1.0, "aspect": 0.9720842559145406, "border": 1.0, - "center": 0.6961156129837036, + "center": 0.0, "sharpness": 0.4361118058809464, "homography": 0.7295816020733066, "normal_visibility": 1.0, @@ -1788,15 +1788,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9997208425591454, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9943611180588094, + "homography": 0.997295816020733, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9814813964852218, "raw": { "mean_edge_px": 53.96408939361572, "edge_ratio": 1.0574348240198506, @@ -1805,28 +1805,28 @@ "laplacian_var": 1090.279514702366 } }, - "mean_reprojection_error_px": 181.76476175391187, + "mean_reprojection_error_px": 181.55342368543512, "corner_reprojection_errors_px": [ - 138.7329595472684, - 193.13356440282328, - 223.10719220107293, - 172.0853308644829 + 138.79861947036503, + 193.60467544781787, + 222.68010835264752, + 171.13029147090998 ] }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.5749326438029929, - "confidence_weighted": 0.5749326438029929, + "confidence_weighted": 0.5626256970953559, "quality": { "detector_confidence": 0.5749326438029929, - "weighted_confidence": 0.5749326438029929, + "weighted_confidence": 0.5626256970953559, "q": { "size": 1.0, "aspect": 0.7301044220084257, "border": 1.0, - "center": 0.5485925674438477, + "center": 0.0, "sharpness": 0.34034870646107274, "homography": 0.7735552097414035, "normal_visibility": 1.0, @@ -1834,15 +1834,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9973010442200843, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9934034870646107, + "homography": 0.997735552097414, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9785941069092363, "raw": { "mean_edge_px": 75.16977119445801, "edge_ratio": 1.7393341824971433, @@ -1851,12 +1851,12 @@ "laplacian_var": 850.8717661526819 } }, - "mean_reprojection_error_px": 94.81305482494598, + "mean_reprojection_error_px": 179.10758347121242, "corner_reprojection_errors_px": [ - 53.41451564830506, - 104.51039185970349, - 144.44374195328376, - 76.8835698384916 + 132.65923607725063, + 207.86142341101734, + 235.5981225376692, + 140.31155185891245 ] } ] @@ -1865,9 +1865,9 @@ "marker_id": 218, "link_name": "Arm2", "position_world_m": [ - 0.19301576418266206, - -0.10100909858854287, - -0.05507885712581472 + 0.08260249512154345, + -0.10774345317436712, + -0.043013241363103374 ], "size_m": 0.025, "observation_count": 0, @@ -1880,46 +1880,46 @@ "marker_id": 101, "link_name": "Arm2", "position_world_m": [ - 0.18116461496794556, - -0.1748740643565427, - -0.05048080380046753 + 0.06637262457056678, + -0.17974069720587255, + -0.029951344342900126 ], "size_m": 0.025, "observation_count": 1, - "mean_confidence": 0.3325004465415643, + "mean_confidence": 0.3264687769670023, "mean_detector_confidence": 0.3325004465415643, - "mean_reprojection_error_px": 264.8653586916646, + "mean_reprojection_error_px": 266.6725297371658, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.3325004465415643, - "confidence_weighted": 0.3325004465415643, + "confidence_weighted": 0.3264687769670023, "quality": { "detector_confidence": 0.3325004465415643, - "weighted_confidence": 0.3325004465415643, + "weighted_confidence": 0.3264687769670023, "q": { "size": 0.7345538902282714, "aspect": 0.6782259971718826, "border": 1.0, - "center": 0.6848434209823608, + "center": 0.0, "sharpness": 1.0, "homography": 0.7627185514162481, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9973455389022827, + "aspect": 0.9967822599717188, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9976271855141625, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9818596647394037, "raw": { "mean_edge_px": 36.727694511413574, "edge_ratio": 1.9488695631540953, @@ -1928,12 +1928,12 @@ "laplacian_var": 3563.870814189421 } }, - "mean_reprojection_error_px": 264.8653586916646, + "mean_reprojection_error_px": 266.6725297371658, "corner_reprojection_errors_px": [ - 248.76482349823732, - 232.76864494991185, - 282.02433999470924, - 295.9036263237998 + 250.67737404692798, + 234.4550017828906, + 283.7216101380938, + 297.83613298075073 ] } ] @@ -1942,46 +1942,46 @@ "marker_id": 102, "link_name": "Arm2", "position_world_m": [ - 0.2138000507668149, - -0.18474533510517926, - -0.014595760341876172 + 0.09128210146267585, + -0.18469476841972596, + 0.012536596762424725 ], "size_m": 0.025, "observation_count": 3, - "mean_confidence": 0.8473641170835915, + "mean_confidence": 0.8354983021138915, "mean_detector_confidence": 0.8473641170835915, - "mean_reprojection_error_px": 203.00720872867376, + "mean_reprojection_error_px": 230.53888976377948, "observations": [ { "view_index": 0, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", "confidence_detector": 0.9494437061622057, - "confidence_weighted": 0.9494437061622057, + "confidence_weighted": 0.9376120619964978, "quality": { "detector_confidence": 0.9494437061622057, - "weighted_confidence": 0.9494437061622057, + "weighted_confidence": 0.9376120619964978, "q": { "size": 0.9537287521362304, "aspect": 0.9740662971297988, "border": 1.0, - "center": 0.6450249254703522, + "center": 0.0, "sharpness": 1.0, "homography": 0.8234129943538817, "normal_visibility": 1.0, "spin": 1.0 }, "factor": { - "size": 1.0, - "aspect": 1.0, + "size": 0.9995372875213623, + "aspect": 0.9997406629712979, "border": 1.0, - "center": 1.0, + "center": 0.99, "sharpness": 1.0, - "homography": 1.0, + "homography": 0.9982341299435388, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9875383405156971, "raw": { "mean_edge_px": 47.68643760681152, "edge_ratio": 1.0532483321651058, @@ -1990,28 +1990,28 @@ "laplacian_var": 3935.778766550373 } }, - "mean_reprojection_error_px": 274.81864950073583, + "mean_reprojection_error_px": 276.6085282390233, "corner_reprojection_errors_px": [ - 238.5526540769381, - 266.0117341060898, - 309.2297757901905, - 285.48043402972485 + 240.26917031381674, + 267.8790547795138, + 311.1033048450262, + 287.1825830177366 ] }, { "view_index": 1, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", "confidence_detector": 0.8913851020933449, - "confidence_weighted": 0.8913851020933449, + "confidence_weighted": 0.880139786945703, "quality": { "detector_confidence": 0.8913851020933449, - "weighted_confidence": 0.8913851020933449, + "weighted_confidence": 0.880139786945703, "q": { "size": 1.0, "aspect": 0.9425738852513735, "border": 1.0, - "center": 0.6652068793773651, + "center": 0.0, "sharpness": 0.7931141622847128, "homography": 0.9999959590215692, "normal_visibility": 1.0, @@ -2019,15 +2019,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.9994257388525137, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9979311416228471, + "homography": 0.9999999595902157, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9873844479549488, "raw": { "mean_edge_px": 62.59456253051758, "edge_ratio": 1.1218495773056807, @@ -2036,28 +2036,28 @@ "laplacian_var": 1982.7854057117818 } }, - "mean_reprojection_error_px": 267.48197698933274, + "mean_reprojection_error_px": 265.88170983930263, "corner_reprojection_errors_px": [ - 230.94675676068127, - 248.4628484358831, - 301.9047245920965, - 288.61357816867 + 229.04927984617981, + 247.40709917850447, + 300.4580491614664, + 286.61241117106 ] }, { "view_index": 2, - "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "source_file": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", "confidence_detector": 0.7012635429952238, - "confidence_weighted": 0.7012635429952238, + "confidence_weighted": 0.6887430573994738, "quality": { "detector_confidence": 0.7012635429952238, - "weighted_confidence": 0.7012635429952238, + "weighted_confidence": 0.6887430573994738, "q": { "size": 1.0, "aspect": 0.8244031865405023, "border": 1.0, - "center": 0.6730169951915741, + "center": 0.0, "sharpness": 0.6987050522983833, "homography": 0.6814939272403986, "normal_visibility": 1.0, @@ -2065,15 +2065,15 @@ }, "factor": { "size": 1.0, - "aspect": 1.0, + "aspect": 0.998244031865405, "border": 1.0, - "center": 1.0, - "sharpness": 1.0, - "homography": 1.0, + "center": 0.99, + "sharpness": 0.9969870505229839, + "homography": 0.9968149392724039, "normal_visibility": 1.0, "spin": 1.0 }, - "weight_multiplier": 1.0, + "weight_multiplier": 0.9821458198977909, "raw": { "mean_edge_px": 84.7633228302002, "edge_ratio": 1.4259974156489281, @@ -2082,12 +2082,12 @@ "laplacian_var": 1746.7626307459584 } }, - "mean_reprojection_error_px": 66.72099969595267, + "mean_reprojection_error_px": 149.12643121301247, "corner_reprojection_errors_px": [ - 110.45363721468823, - 54.785346050607366, - 11.647409112989692, - 89.99760640552542 + 100.71621265239685, + 145.42820590819824, + 193.79388723836442, + 156.5674190530904 ] } ] @@ -2096,9 +2096,9 @@ "marker_id": 219, "link_name": "Arm2", "position_world_m": [ - 0.19301576418266206, - -0.20417695566427538, - -0.08345830860749817 + 0.08260249512154345, + -0.21402343088611253, + -0.0554054299345744 ], "size_m": 0.025, "observation_count": 0, @@ -2114,8 +2114,8 @@ "marker_count": 23, "observed_marker_count": 18, "mean_detector_confidence": 0.5871913728875101, - "mean_weighted_confidence": 0.5871913728875101, - "mean_reprojection_error_px": 231.06066327218028, + "mean_weighted_confidence": 0.5774319023193206, + "mean_reprojection_error_px": 236.06726174073253, "quality_means": { "size": 0.8143773112577551, "aspect": 0.834768084426124, @@ -2125,19 +2125,19 @@ "quality_config": { "size_ref_px": 50.0, "border_ref_px": 120.0, - "center_ref_norm": 1.0, + "center_ref_norm": 0.01, "sharpness_ref": 2500.0, "homography_ref": 0.18, - "size_factor": 1.0, - "aspect_factor": 1.0, - "border_factor": 1.0, - "center_factor": 1.0, - "sharpness_factor": 1.0, - "homography_factor": 1.0 + "size_factor": 0.01, + "aspect_factor": 0.01, + "border_factor": 0.01, + "center_factor": 0.01, + "sharpness_factor": 0.01, + "homography_factor": 0.01 } }, "solver": { - "final_cost": 24956.498214769963, + "final_cost": 26976.87543820547, "status": 0, "message": "The maximum number of function evaluations is exceeded." } diff --git a/pipeline/multiview_pose_Weighted.json b/pipeline/multiview_pose_Weighted.json new file mode 100644 index 0000000..4538c77 --- /dev/null +++ b/pipeline/multiview_pose_Weighted.json @@ -0,0 +1,966 @@ +{ + "schema_version": "1.0", + "created_utc": "2026-05-28T21:07:44.288252Z", + "source_robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\robot.json", + "source_detections": [ + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json" + ], + "robot_pose": { + "state": { + "x": 193.66787382210828, + "y": 61.23821620356439, + "z": -119.96654664833596, + "a": -107.97036991399465, + "b": 21.99999999999934, + "c": 91.00000000000014, + "e": 9.999999999999135 + }, + "uncertainty": { + "x_mm": 444.1920850838452, + "y_mm": 2085.804738658986, + "z_mm": 216.50850058940748, + "a_deg": 273.19721127112774, + "b_deg": 9704.418760205353, + "c_deg": 9704.420149983844, + "e_mm": 97044.43203671245 + }, + "confidence": { + "x": 5.116616350285866e-20, + "y": 2.598071909247533e-91, + "z": 3.9550801677927533e-10, + "a": 1.3651987041054823e-12, + "b": 0.0, + "c": 0.0, + "e": 0.36787944117144233 + } + }, + "camera_poses": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + -77.74926115576925, + -73.0492976258425, + -147.8089302398559 + ], + "rvec": [ + -4.597800910443656, + -21.216692970790984, + 5.280603517092184 + ], + "tvec": [ + 1.3186034894317018, + 7.494557764024174, + -182.12830708406332 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 17 + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + 0.0906907584418463, + 0.2776617967661424, + -0.7247751841355033 + ], + "rvec": [ + -0.5104408724728655, + -3.1865020935343082, + -0.7599897453664757 + ], + "tvec": [ + 0.18575285646205408, + 0.031786357242087525, + -0.7583570784256441 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 10 + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + 0.2258549281270687, + -0.3663871310029323, + 0.6799707410888476 + ], + "rvec": [ + -3.4730218301317435, + 0.5992584877895241, + 0.35858647149574585 + ], + "tvec": [ + -0.1367303214358514, + 0.0014859998076042164, + 0.7930402247461223 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 7 + } + ], + "marker_positions": [ + { + "marker_id": 210, + "link_name": "Board", + "position_world_m": [ + 0.02, + -0.02, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.6024643807746477, + "mean_reprojection_error_px": 219.44641687346314, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.5042074435920213, + "mean_reprojection_error_px": 584.8502187266689, + "corner_reprojection_errors_px": [ + 610.6060261840274, + 566.4030412437936, + 559.1036732421863, + 603.2881342366682 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.6639531667043603, + "mean_reprojection_error_px": 43.90181819055642, + "corner_reprojection_errors_px": [ + 30.0527741674556, + 58.738230110803315, + 62.58264430539862, + 24.23362417856814 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.6392325320275614, + "mean_reprojection_error_px": 29.587213703164036, + "corner_reprojection_errors_px": [ + 44.13807594611845, + 1.1413153391747903, + 31.635331629981838, + 41.434131897381064 + ] + } + ] + }, + { + "marker_id": 211, + "link_name": "Board", + "position_world_m": [ + 0.25, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.5607331763105995, + "mean_reprojection_error_px": 215.88919812501328, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.5607331763105995, + "mean_reprojection_error_px": 215.88919812501328, + "corner_reprojection_errors_px": [ + 239.060567969831, + 203.87810525007305, + 193.21032729986996, + 227.40779198027906 + ] + } + ] + }, + { + "marker_id": 215, + "link_name": "Board", + "position_world_m": [ + 0.25, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.6915990015172901, + "mean_reprojection_error_px": 185.82669857910088, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.6816798505186958, + "mean_reprojection_error_px": 206.76829215011884, + "corner_reprojection_errors_px": [ + 220.0957850912882, + 186.544457069329, + 194.82996305260656, + 225.60296338725155 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.7015181525158845, + "mean_reprojection_error_px": 164.88510500808295, + "corner_reprojection_errors_px": [ + 197.75737719196465, + 146.9529114839187, + 132.41058001353588, + 182.41955134291254 + ] + } + ] + }, + { + "marker_id": 214, + "link_name": "Board", + "position_world_m": [ + 0.35000000000000003, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.5223267506441452, + "mean_reprojection_error_px": 430.28505616193627, + "observations": [ + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.5223267506441452, + "mean_reprojection_error_px": 430.28505616193627, + "corner_reprojection_errors_px": [ + 435.27929209106946, + 407.3352893643994, + 427.77239968551254, + 450.7532435067638 + ] + } + ] + }, + { + "marker_id": 208, + "link_name": "Board", + "position_world_m": [ + 0.35000000000000003, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.5511135304821347, + "mean_reprojection_error_px": 104.93132940823983, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.5511135304821347, + "mean_reprojection_error_px": 104.93132940823983, + "corner_reprojection_errors_px": [ + 101.05437746855068, + 84.48184159814882, + 111.54460519378607, + 122.64449337247373 + ] + } + ] + }, + { + "marker_id": 206, + "link_name": "Board", + "position_world_m": [ + 0.65, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.3243040576749168, + "mean_reprojection_error_px": 265.1269045088845, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.3243040576749168, + "mean_reprojection_error_px": 265.1269045088845, + "corner_reprojection_errors_px": [ + 246.4689237594987, + 270.74271590412576, + 283.7439899333724, + 259.551988438541 + ] + } + ] + }, + { + "marker_id": 205, + "link_name": "Board", + "position_world_m": [ + 0.75, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.2813323639079811, + "mean_reprojection_error_px": 414.07105145074036, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.2813323639079811, + "mean_reprojection_error_px": 414.07105145074036, + "corner_reprojection_errors_px": [ + 393.31517220079184, + 414.88055122924146, + 434.6820277122509, + 413.40645466067724 + ] + } + ] + }, + { + "marker_id": 207, + "link_name": "Board", + "position_world_m": [ + 0.75, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.270961511076242, + "mean_reprojection_error_px": 361.40219383857607, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.270961511076242, + "mean_reprojection_error_px": 361.40219383857607, + "corner_reprojection_errors_px": [ + 343.99480245991305, + 365.3864615302313, + 379.1131712173157, + 357.11434014684426 + ] + } + ] + }, + { + "marker_id": 217, + "link_name": "Board", + "position_world_m": [ + 0.65, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.3364649702867649, + "mean_reprojection_error_px": 319.9894030743949, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.3364649702867649, + "mean_reprojection_error_px": 319.9894030743949, + "corner_reprojection_errors_px": [ + 297.7784176112965, + 321.2632775986662, + 342.12879416557814, + 318.78712292203863 + ] + } + ] + }, + { + "marker_id": 198, + "link_name": "Arm1", + "position_world_m": [ + 0.1936678738221083, + -0.04630507797358846, + 0.15710136776571965 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.1708737557403893, + "mean_reprojection_error_px": 173.75585674911616, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.20939472520051636, + "mean_reprojection_error_px": 250.68402341711896, + "corner_reprojection_errors_px": [ + 276.58098681044964, + 248.3015862011881, + 225.19824045129988, + 252.6552802055382 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.13235278628026223, + "mean_reprojection_error_px": 96.82769008111335, + "corner_reprojection_errors_px": [ + 86.14028865296076, + 96.54841237858139, + 117.89661118485392, + 86.72544810805726 + ] + } + ] + }, + { + "marker_id": 229, + "link_name": "Arm1", + "position_world_m": [ + 0.1936678738221083, + -0.08961029442397768, + 0.2359978710354143 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.2199830218620032, + "mean_reprojection_error_px": 111.48418089668428, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.2634483409899881, + "mean_reprojection_error_px": 158.57789833970793, + "corner_reprojection_errors_px": [ + 183.23095634369403, + 159.8980008563882, + 134.10338119920908, + 157.07925495954032 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.17651770273401826, + "mean_reprojection_error_px": 64.39046345366064, + "corner_reprojection_errors_px": [ + 53.76348865479547, + 65.98012218463036, + 89.14976602616233, + 48.66847694905442 + ] + } + ] + }, + { + "marker_id": 242, + "link_name": "Arm1", + "position_world_m": [ + 0.1936678738221083, + -0.15097424141151797, + 0.2023160360184449 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 243, + "link_name": "Arm1", + "position_world_m": [ + 0.1936678738221083, + -0.13713318542623254, + 0.24983892702069976 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.783838885722734, + "mean_reprojection_error_px": 44.94196369988338, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.753480565397225, + "mean_reprojection_error_px": 82.27135266344914, + "corner_reprojection_errors_px": [ + 104.64641625637452, + 75.05759016037157, + 54.73600619528254, + 94.64539804176789 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.7779633248368785, + "mean_reprojection_error_px": 17.133880995253847, + "corner_reprojection_errors_px": [ + 13.52613306369719, + 20.79198380803457, + 20.738458388035028, + 13.478948721248596 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.8200727669340984, + "mean_reprojection_error_px": 35.42065744094714, + "corner_reprojection_errors_px": [ + 43.2051334803787, + 2.291855750175984, + 46.29738248992781, + 49.88825804330606 + ] + } + ] + }, + { + "marker_id": 244, + "link_name": "Ellbow", + "position_world_m": [ + 0.31866787382210826, + 0.0, + 0.0 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 245, + "link_name": "Ellbow", + "position_world_m": [ + 0.2836678738221083, + 0.029915046239746786, + -0.018168379357383857 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 246, + "link_name": "Ellbow", + "position_world_m": [ + 0.2836678738221083, + -0.029915046239746786, + 0.018168379357383857 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.5848503519198133, + "mean_reprojection_error_px": 71.95677931061337, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.6846593913143055, + "mean_reprojection_error_px": 129.77061184774738, + "corner_reprojection_errors_px": [ + 131.10152630147377, + 148.01757225834027, + 132.02269451379757, + 107.940654317378 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.6496660357669276, + "mean_reprojection_error_px": 39.429662635023675, + "corner_reprojection_errors_px": [ + 54.265219903618416, + 25.613227047621212, + 36.12153940947933, + 41.71866417937572 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.4202256286782067, + "mean_reprojection_error_px": 46.67006344906903, + "corner_reprojection_errors_px": [ + 17.76180722171543, + 53.41185602621912, + 87.55552599091499, + 27.95106455742659 + ] + } + ] + }, + { + "marker_id": 247, + "link_name": "Ellbow", + "position_world_m": [ + 0.24616787382210828, + -0.029915046239746786, + 0.018168379357383857 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.6103408077771776, + "mean_reprojection_error_px": 72.45582056932597, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.7451994373791682, + "mean_reprojection_error_px": 109.52982904634278, + "corner_reprojection_errors_px": [ + 126.13937483803942, + 126.72281250876043, + 96.93499026995522, + 88.3221385686161 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.6388783942274684, + "mean_reprojection_error_px": 42.48268761553851, + "corner_reprojection_errors_px": [ + 66.85934117736593, + 52.808931850254176, + 27.34232661092379, + 22.920150823610143 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.44694459172489637, + "mean_reprojection_error_px": 65.35494504609662, + "corner_reprojection_errors_px": [ + 65.94881395992364, + 79.79307781356299, + 80.2686839721486, + 35.40920443875125 + ] + } + ] + }, + { + "marker_id": 124, + "link_name": "Arm2", + "position_world_m": [ + 0.20446625306675464, + -0.14213782157794694, + -0.16990066121932695 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.38376633052345943, + "mean_reprojection_error_px": 119.57328172201322, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.31559423864949376, + "mean_reprojection_error_px": 134.82416625853605, + "corner_reprojection_errors_px": [ + 121.33281341523052, + 103.50465151028168, + 148.6485339972427, + 165.81066611138934 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.4519384223974251, + "mean_reprojection_error_px": 104.32239718549039, + "corner_reprojection_errors_px": [ + 97.26022837754157, + 65.51154041781498, + 119.230195720015, + 135.28762422659 + ] + } + ] + }, + { + "marker_id": 122, + "link_name": "Arm2", + "position_world_m": [ + 0.22220435967071417, + -0.08656453557061031, + -0.16036287025635595 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.5007571026495876, + "mean_reprojection_error_px": 100.5976968444762, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.19097609792206996, + "mean_reprojection_error_px": 191.04201527524393, + "corner_reprojection_errors_px": [ + 161.2461896774225, + 187.67710037351839, + 219.07478119264024, + 196.16998985739463 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.8023854845720537, + "mean_reprojection_error_px": 37.97273645764808, + "corner_reprojection_errors_px": [ + 36.73735527126386, + 66.77343554076022, + 29.865847324866966, + 18.51430769370129 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.5089097254546391, + "mean_reprojection_error_px": 72.77833880053663, + "corner_reprojection_errors_px": [ + 79.87926104625087, + 114.41534929802285, + 63.25062596802093, + 33.56811888985185 + ] + } + ] + }, + { + "marker_id": 218, + "link_name": "Arm2", + "position_world_m": [ + 0.18286949457746193, + -0.029683137487597516, + -0.11301020464799262 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 101, + "link_name": "Arm2", + "position_world_m": [ + 0.1624892762454371, + -0.0808799499047689, + -0.16381530379227105 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.30496613331262606, + "mean_reprojection_error_px": 266.775950196611, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.30496613331262606, + "mean_reprojection_error_px": 266.775950196611, + "corner_reprojection_errors_px": [ + 251.08509253516107, + 234.8164115324836, + 283.5537072385155, + 297.64858948028376 + ] + } + ] + }, + { + "marker_id": 102, + "link_name": "Arm2", + "position_world_m": [ + 0.17776126974857978, + -0.12112440660686963, + -0.13937353791513551 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.7291583793913716, + "mean_reprojection_error_px": 139.1860336202907, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.8030005342619584, + "mean_reprojection_error_px": 274.10231703594735, + "corner_reprojection_errors_px": [ + 237.94975046516782, + 264.59434010512416, + 308.4630690582601, + 285.4021085152374 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.7644345761691943, + "mean_reprojection_error_px": 72.4273672978813, + "corner_reprojection_errors_px": [ + 46.62612295920637, + 34.03763203823939, + 100.37413904993618, + 108.67157514414326 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.6200400277429619, + "mean_reprojection_error_px": 71.02841652704336, + "corner_reprojection_errors_px": [ + 102.37939191515659, + 31.002903116690042, + 42.58563098754617, + 108.14574008878068 + ] + } + ] + }, + { + "marker_id": 219, + "link_name": "Arm2", + "position_world_m": [ + 0.18286949457746193, + -0.08522646866588529, + -0.20446477458093276 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + } + ] +} \ No newline at end of file diff --git a/pipeline/multiview_pose_neu.json b/pipeline/multiview_pose_neu.json new file mode 100644 index 0000000..730682d --- /dev/null +++ b/pipeline/multiview_pose_neu.json @@ -0,0 +1,2144 @@ +{ + "schema_version": "1.0", + "created_utc": "2026-05-28T20:51:28.589969Z", + "source_robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\robot.json", + "source_detections": [ + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json" + ], + "robot_pose": { + "state": { + "x": 216.2125544201488, + "y": 39.806379269892254, + "z": -54.991084397171825, + "a": -130.65882483284662, + "b": 22.000000000002032, + "c": 90.99999999999798, + "e": 10.000000000001718 + }, + "uncertainty": { + "x_mm": 224.10687807100763, + "y_mm": 605.4181830366131, + "z_mm": 248.0806970645967, + "a_deg": 997.7447286683357, + "b_deg": 12094.993764453631, + "c_deg": 12094.993807226765, + "e_mm": 120949.93791544222 + }, + "confidence": { + "x": 1.8499583454054539e-10, + "y": 5.093571259225315e-27, + "z": 1.6826439170056386e-11, + "a": 4.66119207217934e-44, + "b": 0.0, + "c": 0.0, + "e": 0.36787944117144233 + } + }, + "camera_poses": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + -38.46428656854336, + -74.09008711895505, + -21.334303864681747 + ], + "rvec": [ + 110.95428904561572, + -126.68939270587695, + 43.92636633496647 + ], + "tvec": [ + 0.4736830640184213, + 3.5722846578605267, + -86.08721901995688 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 17 + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + -17.75034590814752, + 49.992391204647504, + -9.204276670320416 + ], + "rvec": [ + 0.31469131936958156, + 2.0195329754781035, + 1.5707717909374486 + ], + "tvec": [ + -1.9399600172876972, + 2.0553500305952532, + -53.7684364532229 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 10 + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + 0.2729594318862425, + -0.6573042534860901, + 0.4430179270292649 + ], + "rvec": [ + -3.9931652753171334, + 0.3705917863703731, + 0.6116696935981153 + ], + "tvec": [ + -0.13797082899413618, + 0.016029224160589235, + 0.8267573592628941 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 7 + } + ], + "marker_positions": [ + { + "marker_id": 210, + "link_name": "Board", + "position_world_m": [ + 0.02, + -0.02, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.6882418402751833, + "mean_detector_confidence": 0.6997700579082148, + "mean_reprojection_error_px": 348.28128404408494, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.5673043275049208, + "confidence_weighted": 0.556048533067895, + "quality": { + "detector_confidence": 0.5673043275049208, + "weighted_confidence": 0.556048533067895, + "q": { + "size": 0.8108224868774414, + "aspect": 0.9096486158109359, + "border": 0.2833333333333333, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.9999983069718208, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9981082248687744, + "aspect": 0.9990964861581093, + "border": 0.9928333333333333, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9999999830697182, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9801591599229813, + "raw": { + "mean_edge_px": 40.54112434387207, + "edge_ratio": 1.1986511772098227, + "distance_to_border_px": 34.0, + "distance_to_center_norm": 0.7614269256591797, + "laplacian_var": 3797.5312506581813 + } + }, + "mean_reprojection_error_px": 586.9935302222972, + "corner_reprojection_errors_px": [ + 612.6505119930617, + 568.2120894731479, + 561.3485382966923, + 605.7629811262867 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.7813266383036261, + "confidence_weighted": 0.7686240953581938, + "quality": { + "detector_confidence": 0.7813266383036261, + "weighted_confidence": 0.7686240953581938, + "q": { + "size": 0.7824347686767578, + "aspect": 0.8792155830729744, + "border": 1.0, + "center": 0.0, + "sharpness": 0.9904164099455028, + "homography": 0.7145588675251666, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9978243476867675, + "aspect": 0.9987921558307298, + "border": 1.0, + "center": 0.99, + "sharpness": 0.999904164099455, + "homography": 0.9971455886752516, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9837423398579991, + "raw": { + "mean_edge_px": 39.12173843383789, + "edge_ratio": 1.274754950327127, + "distance_to_border_px": 252.0, + "distance_to_center_norm": 0.5032430291175842, + "laplacian_var": 2476.0410248637572 + } + }, + "mean_reprojection_error_px": 427.63428905378987, + "corner_reprojection_errors_px": [ + 446.12766553590336, + 403.96001290416933, + 408.1519561283892, + 452.29752164669765 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.7506792079160973, + "confidence_weighted": 0.740052892399461, + "quality": { + "detector_confidence": 0.7506792079160973, + "weighted_confidence": 0.740052892399461, + "q": { + "size": 0.8434026336669922, + "aspect": 0.8575862494073492, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.8786678750976363, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9984340263366699, + "aspect": 0.9985758624940735, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9987866787509764, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9858443987730322, + "raw": { + "mean_edge_px": 42.17013168334961, + "edge_ratio": 1.3321269451115116, + "distance_to_border_px": 298.0, + "distance_to_center_norm": 0.3557531535625458, + "laplacian_var": 2842.0926549741707 + } + }, + "mean_reprojection_error_px": 30.216032856167953, + "corner_reprojection_errors_px": [ + 35.67266624562453, + 21.942859474246884, + 43.42315186071883, + 19.82545384408156 + ] + } + ] + }, + { + "marker_id": 211, + "link_name": "Board", + "position_world_m": [ + 0.25, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.6305246964757232, + "mean_detector_confidence": 0.6412317666518965, + "mean_reprojection_error_px": 213.454796419243, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.6412317666518965, + "confidence_weighted": 0.6305246964757232, + "quality": { + "detector_confidence": 0.6412317666518965, + "weighted_confidence": 0.6305246964757232, + "q": { + "size": 0.6744685745239258, + "aspect": 0.9460729944417767, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.7016198391981602, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9967446857452392, + "aspect": 0.9994607299444178, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9970161983919816, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9833023397576218, + "raw": { + "mean_edge_px": 33.72342872619629, + "edge_ratio": 1.1140017860673477, + "distance_to_border_px": 276.0, + "distance_to_center_norm": 0.26670128107070923, + "laplacian_var": 3165.7184033540047 + } + }, + "mean_reprojection_error_px": 213.454796419243, + "corner_reprojection_errors_px": [ + 236.6948016318256, + 201.2877507939219, + 190.69927477677504, + 225.13735847444946 + ] + } + ] + }, + { + "marker_id": 215, + "link_name": "Board", + "position_world_m": [ + 0.25, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.7997306526656554, + "mean_detector_confidence": 0.8108527003549935, + "mean_reprojection_error_px": 158.99744861646724, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.7952557920267838, + "confidence_weighted": 0.7849458403437536, + "quality": { + "detector_confidence": 0.7952557920267838, + "weighted_confidence": 0.7849458403437536, + "q": { + "size": 0.7146316909790039, + "aspect": 0.9859016728248396, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 1.0, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.99714631690979, + "aspect": 0.9998590167282484, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 1.0, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9870356786000208, + "raw": { + "mean_edge_px": 35.731584548950195, + "edge_ratio": 1.0285998645985972, + "distance_to_border_px": 211.0, + "distance_to_center_norm": 0.213719442486763, + "laplacian_var": 3704.0260869185627 + } + }, + "mean_reprojection_error_px": 202.81242503739065, + "corner_reprojection_errors_px": [ + 215.99477550077216, + 182.26503017592103, + 191.06124849415332, + 221.92864597871608 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.826449608683203, + "confidence_weighted": 0.8145154649875572, + "quality": { + "detector_confidence": 0.826449608683203, + "weighted_confidence": 0.8145154649875572, + "q": { + "size": 0.8409605407714844, + "aspect": 0.9049793706370471, + "border": 1.0, + "center": 0.0, + "sharpness": 0.8049029197222222, + "homography": 1.0, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9984096054077148, + "aspect": 0.9990497937063705, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9980490291972222, + "homography": 1.0, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9855597442720546, + "raw": { + "mean_edge_px": 42.04802703857422, + "edge_ratio": 1.2099951279465397, + "distance_to_border_px": 290.0, + "distance_to_center_norm": 0.0916082039475441, + "laplacian_var": 2012.2572993055553 + } + }, + "mean_reprojection_error_px": 115.1824721955438, + "corner_reprojection_errors_px": [ + 102.04871121339015, + 92.02281620719849, + 129.7002932180607, + 136.95806814352588 + ] + } + ] + }, + { + "marker_id": 214, + "link_name": "Board", + "position_world_m": [ + 0.35000000000000003, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.5924337979452556, + "mean_detector_confidence": 0.6041252446922665, + "mean_reprojection_error_px": 338.292638805463, + "observations": [ + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.6041252446922665, + "confidence_weighted": 0.5924337979452556, + "quality": { + "detector_confidence": 0.6041252446922665, + "weighted_confidence": 0.5924337979452556, + "q": { + "size": 0.9836519622802734, + "aspect": 0.7532145593882991, + "border": 1.0, + "center": 0.0, + "sharpness": 0.5256355772646303, + "homography": 0.7899472530560614, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9998365196228027, + "aspect": 0.997532145593883, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9952563557726463, + "homography": 0.9978994725305605, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.980647313036941, + "raw": { + "mean_edge_px": 49.18259811401367, + "edge_ratio": 1.655285901037602, + "distance_to_border_px": 137.0, + "distance_to_center_norm": 0.6772311925888062, + "laplacian_var": 1314.0889431615756 + } + }, + "mean_reprojection_error_px": 338.292638805463, + "corner_reprojection_errors_px": [ + 334.17680905883867, + 319.4817160418119, + 346.09532378608355, + 353.4167063351179 + ] + } + ] + }, + { + "marker_id": 208, + "link_name": "Board", + "position_world_m": [ + 0.35000000000000003, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.6179064007574118, + "mean_detector_confidence": 0.6280424706698967, + "mean_reprojection_error_px": 100.37855071417272, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.6280424706698967, + "confidence_weighted": 0.6179064007574118, + "quality": { + "detector_confidence": 0.6280424706698967, + "weighted_confidence": 0.6179064007574118, + "q": { + "size": 0.6625362014770508, + "aspect": 0.9537163525948422, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.7625645902124035, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9966253620147705, + "aspect": 0.9995371635259485, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.997625645902124, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9838608527514494, + "raw": { + "mean_edge_px": 33.12681007385254, + "edge_ratio": 1.0970595655180506, + "distance_to_border_px": 303.0, + "distance_to_center_norm": 0.05652238056063652, + "laplacian_var": 2848.9886204705635 + } + }, + "mean_reprojection_error_px": 100.37855071417272, + "corner_reprojection_errors_px": [ + 95.32006064225416, + 79.9218729308236, + 108.20304850767852, + 118.06922077593458 + ] + } + ] + }, + { + "marker_id": 206, + "link_name": "Board", + "position_world_m": [ + 0.65, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.33185586633646474, + "mean_detector_confidence": 0.33820423087105295, + "mean_reprojection_error_px": 276.1297836775614, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.33820423087105295, + "confidence_weighted": 0.33185586633646474, + "quality": { + "detector_confidence": 0.33820423087105295, + "weighted_confidence": 0.33185586633646474, + "q": { + "size": 0.5361141967773437, + "aspect": 0.8936906729306451, + "border": 0.9833333333333333, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.6985669093200941, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9953611419677735, + "aspect": 0.9989369067293065, + "border": 0.9998333333333334, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.996985669093201, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9812291983508372, + "raw": { + "mean_edge_px": 26.805709838867188, + "edge_ratio": 1.2379107901411548, + "distance_to_border_px": 118.0, + "distance_to_center_norm": 0.41312646865844727, + "laplacian_var": 4112.338450277431 + } + }, + "mean_reprojection_error_px": 276.1297836775614, + "corner_reprojection_errors_px": [ + 257.8900669402429, + 282.33421351116806, + 294.3714307574213, + 269.9234235014133 + ] + } + ] + }, + { + "marker_id": 205, + "link_name": "Board", + "position_world_m": [ + 0.75, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.2820948444008322, + "mean_detector_confidence": 0.28724459014346065, + "mean_reprojection_error_px": 426.56646984308156, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.28724459014346065, + "confidence_weighted": 0.2820948444008322, + "quality": { + "detector_confidence": 0.28724459014346065, + "weighted_confidence": 0.2820948444008322, + "q": { + "size": 0.5248580741882324, + "aspect": 0.839187418386558, + "border": 0.8333333333333334, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.9999815099800249, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9952485807418823, + "aspect": 0.9983918741838655, + "border": 0.9983333333333333, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9999998150998003, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9820719139042569, + "raw": { + "mean_edge_px": 26.24290370941162, + "edge_ratio": 1.383257847031654, + "distance_to_border_px": 100.0, + "distance_to_center_norm": 0.5996246933937073, + "laplacian_var": 5067.414824476962 + } + }, + "mean_reprojection_error_px": 426.56646984308156, + "corner_reprojection_errors_px": [ + 406.09564835107483, + 428.0016350720032, + 446.9080809260819, + 425.26051502316636 + ] + } + ] + }, + { + "marker_id": 207, + "link_name": "Board", + "position_world_m": [ + 0.75, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.2656859333164099, + "mean_detector_confidence": 0.27228561618555186, + "mean_reprojection_error_px": 374.4597857850409, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.27228561618555186, + "confidence_weighted": 0.2656859333164099, + "quality": { + "detector_confidence": 0.27228561618555186, + "weighted_confidence": 0.2656859333164099, + "q": { + "size": 0.5014523983001709, + "aspect": 0.8554115971298921, + "border": 0.5, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.6975670005943979, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9950145239830017, + "aspect": 0.998554115971299, + "border": 0.995, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.996975670005944, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9757619114751748, + "raw": { + "mean_edge_px": 25.072619915008545, + "edge_ratio": 1.3380557461583085, + "distance_to_border_px": 60.0, + "distance_to_center_norm": 0.5434604287147522, + "laplacian_var": 4016.6321593416924 + } + }, + "mean_reprojection_error_px": 374.4597857850409, + "corner_reprojection_errors_px": [ + 357.40079371775073, + 378.999822513009, + 391.8463073017326, + 369.592219607671 + ] + } + ] + }, + { + "marker_id": 217, + "link_name": "Board", + "position_world_m": [ + 0.65, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.3494362969135403, + "mean_detector_confidence": 0.35596573288593486, + "mean_reprojection_error_px": 330.08452718425906, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.35596573288593486, + "confidence_weighted": 0.3494362969135403, + "quality": { + "detector_confidence": 0.35596573288593486, + "weighted_confidence": 0.3494362969135403, + "q": { + "size": 0.5561128711700439, + "aspect": 0.8721453879265322, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.726899391813532, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9955611287117004, + "aspect": 0.9987214538792654, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9972689939181353, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9816571221070685, + "raw": { + "mean_edge_px": 27.805643558502197, + "edge_ratio": 1.2931956388084183, + "distance_to_border_px": 161.0, + "distance_to_center_norm": 0.4665455222129822, + "laplacian_var": 3793.153007417641 + } + }, + "mean_reprojection_error_px": 330.08452718425906, + "corner_reprojection_errors_px": [ + 308.1750045594493, + 332.05822953172486, + 351.9569332059738, + 328.14794143988826 + ] + } + ] + }, + { + "marker_id": 198, + "link_name": "Arm1", + "position_world_m": [ + 0.2162125544201488, + -0.10050712667090819, + 0.12931866643434742 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.1628904920977715, + "mean_detector_confidence": 0.16652042240877096, + "mean_reprojection_error_px": 243.65457954180246, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.20150745250271476, + "confidence_weighted": 0.19749969171522036, + "quality": { + "detector_confidence": 0.20150745250271476, + "weighted_confidence": 0.19749969171522036, + "q": { + "size": 0.6339855194091797, + "aspect": 0.7539930512070505, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.6098583763162305, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9963398551940917, + "aspect": 0.9975399305120705, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9960985837631623, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9801111038935872, + "raw": { + "mean_edge_px": 31.699275970458984, + "edge_ratio": 1.652544339497884, + "distance_to_border_px": 237.0, + "distance_to_center_norm": 0.3810231387615204, + "laplacian_var": 3972.096222043203 + } + }, + "mean_reprojection_error_px": 248.60962775444693, + "corner_reprojection_errors_px": [ + 274.4618015839291, + 245.99327248236204, + 223.16393875898757, + 250.8194981925089 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.13153339231482716, + "confidence_weighted": 0.12828129248032266, + "quality": { + "detector_confidence": 0.13153339231482716, + "weighted_confidence": 0.12828129248032266, + "q": { + "size": 0.6576880264282227, + "aspect": 0.42738020051250675, + "border": 0.5916666666666667, + "center": 0.0, + "sharpness": 0.9362022578647182, + "homography": 0.8917140926962271, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9965768802642823, + "aspect": 0.994273802005125, + "border": 0.9959166666666667, + "center": 0.99, + "sharpness": 0.9993620225786471, + "homography": 0.9989171409269623, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9752754811742362, + "raw": { + "mean_edge_px": 32.88440132141113, + "edge_ratio": 3.6796739708616246, + "distance_to_border_px": 71.0, + "distance_to_center_norm": 0.3842795193195343, + "laplacian_var": 2340.5056446617955 + } + }, + "mean_reprojection_error_px": 238.699531329158, + "corner_reprojection_errors_px": [ + 255.24209245503738, + 233.94584808506465, + 221.27827772724922, + 244.3319070492807 + ] + } + ] + }, + { + "marker_id": 229, + "link_name": "Arm1", + "position_world_m": [ + 0.2162125544201488, + -0.16964622912493513, + 0.18693623764184944 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.22245621469865084, + "mean_detector_confidence": 0.2274747191640703, + "mean_reprojection_error_px": 172.21902964047672, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.26810902547334975, + "confidence_weighted": 0.2630164795315655, + "quality": { + "detector_confidence": 0.26810902547334975, + "weighted_confidence": 0.2630164795315655, + "q": { + "size": 0.6824631023406983, + "aspect": 0.7938768481947832, + "border": 1.0, + "center": 0.0, + "sharpness": 0.9086003975826067, + "homography": 0.7035912150387432, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.996824631023407, + "aspect": 0.9979387684819478, + "border": 1.0, + "center": 0.99, + "sharpness": 0.999086003975826, + "homography": 0.9970359121503874, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9810056900069167, + "raw": { + "mean_edge_px": 34.12315511703491, + "edge_ratio": 1.5192824359947652, + "distance_to_border_px": 235.0, + "distance_to_center_norm": 0.26675668358802795, + "laplacian_var": 2271.5009939565166 + } + }, + "mean_reprojection_error_px": 155.18292375210498, + "corner_reprojection_errors_px": [ + 179.61793897038316, + 156.36707592341475, + 130.9673904026988, + 153.77928971192316 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.18684041285479083, + "confidence_weighted": 0.18189594986573623, + "quality": { + "detector_confidence": 0.18684041285479083, + "weighted_confidence": 0.18189594986573623, + "q": { + "size": 0.7395829486846924, + "aspect": 0.44796521997625727, + "border": 1.0, + "center": 0.0, + "sharpness": 0.5568649165432099, + "homography": 0.5823463065693475, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9973958294868469, + "aspect": 0.9944796521997625, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9955686491654321, + "homography": 0.9958234630656935, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9735364372540894, + "raw": { + "mean_edge_px": 36.97914743423462, + "edge_ratio": 3.4646323214690695, + "distance_to_border_px": 130.0, + "distance_to_center_norm": 0.30442705750465393, + "laplacian_var": 1392.1622913580247 + } + }, + "mean_reprojection_error_px": 189.25513552884843, + "corner_reprojection_errors_px": [ + 210.953664691596, + 180.02926949382038, + 165.06706834326602, + 200.9705395867113 + ] + } + ] + }, + { + "marker_id": 242, + "link_name": "Arm1", + "position_world_m": [ + 0.2162125544201488, + -0.21445989561965892, + 0.1331613801776063 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_detector_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 243, + "link_name": "Arm1", + "position_world_m": [ + 0.2162125544201488, + -0.21894049110441863, + 0.1824556421570898 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.903504284314228, + "mean_detector_confidence": 0.9174550709990235, + "mean_reprojection_error_px": 76.41294345524527, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.8899728634608616, + "confidence_weighted": 0.8780472636948905, + "quality": { + "detector_confidence": 0.8899728634608616, + "weighted_confidence": 0.8780472636948905, + "q": { + "size": 0.8810945701599121, + "aspect": 0.9417837479752699, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.8333271723300208, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9988109457015991, + "aspect": 0.9994178374797527, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9983332717233002, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9866000411297984, + "raw": { + "mean_edge_px": 44.054728507995605, + "edge_ratio": 1.1236297656439467, + "distance_to_border_px": 275.0, + "distance_to_center_norm": 0.14032743871212006, + "laplacian_var": 2678.6956247003295 + } + }, + "mean_reprojection_error_px": 77.73247765881362, + "corner_reprojection_errors_px": [ + 100.09663777901342, + 71.03155845847478, + 49.68444998113758, + 90.11726441662871 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.9132502955127223, + "confidence_weighted": 0.8990944567220429, + "quality": { + "detector_confidence": 0.9132502955127223, + "weighted_confidence": 0.8990944567220429, + "q": { + "size": 1.0, + "aspect": 0.9546584653922503, + "border": 1.0, + "center": 0.0, + "sharpness": 0.5809177986450728, + "homography": 0.9082012101971718, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9995465846539225, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9958091779864507, + "homography": 0.9990820121019717, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9844994971693583, + "raw": { + "mean_edge_px": 55.26974582672119, + "edge_ratio": 1.0949900645130086, + "distance_to_border_px": 219.0, + "distance_to_center_norm": 0.16541028022766113, + "laplacian_var": 1452.2944966126818 + } + }, + "mean_reprojection_error_px": 122.78655606717538, + "corner_reprojection_errors_px": [ + 157.6458318939967, + 109.99288557766964, + 84.06400631503655, + 139.44350048199863 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.9491420540234864, + "confidence_weighted": 0.9333711325257503, + "quality": { + "detector_confidence": 0.9491420540234864, + "weighted_confidence": 0.9333711325257503, + "q": { + "size": 1.0, + "aspect": 0.9739075220959238, + "border": 1.0, + "center": 0.0, + "sharpness": 0.43477113518953137, + "homography": 0.9224349218355518, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9997390752209593, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9943477113518953, + "homography": 0.9992243492183555, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9833840240974658, + "raw": { + "mean_edge_px": 75.11714553833008, + "edge_ratio": 1.0535830709016873, + "distance_to_border_px": 185.0, + "distance_to_center_norm": 0.1876671463251114, + "laplacian_var": 1086.9278379738284 + } + }, + "mean_reprojection_error_px": 28.719796639746797, + "corner_reprojection_errors_px": [ + 13.96625838999557, + 28.16351736568848, + 48.750308006934766, + 23.999102796368366 + ] + } + ] + }, + { + "marker_id": 244, + "link_name": "Ellbow", + "position_world_m": [ + 0.3412125544201488, + 0.0, + 0.0 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_detector_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 245, + "link_name": "Ellbow", + "position_world_m": [ + 0.30621255442014883, + 0.009167604674109032, + -0.033778025764382 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_detector_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 246, + "link_name": "Ellbow", + "position_world_m": [ + 0.30621255442014883, + -0.009167604674109032, + 0.033778025764382 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.6682660968032644, + "mean_detector_confidence": 0.6792447690577089, + "mean_reprojection_error_px": 112.50880855094645, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.8015179238063419, + "confidence_weighted": 0.7895911927962278, + "quality": { + "detector_confidence": 0.8015179238063419, + "weighted_confidence": 0.7895911927962278, + "q": { + "size": 0.7650188636779786, + "aspect": 0.9580747137765034, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.7832604752816245, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9976501886367798, + "aspect": 0.999580747137765, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9978326047528162, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9851198199617608, + "raw": { + "mean_edge_px": 38.250943183898926, + "edge_ratio": 1.0875198679615226, + "distance_to_border_px": 150.0, + "distance_to_center_norm": 0.25916191935539246, + "laplacian_var": 3236.7051337367984 + } + }, + "mean_reprojection_error_px": 133.98596502059948, + "corner_reprojection_errors_px": [ + 134.9693924937541, + 152.59340276536824, + 136.43578909428862, + 111.9452757289869 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.7581700566520715, + "confidence_weighted": 0.7467269698455701, + "quality": { + "detector_confidence": 0.7581700566520715, + "weighted_confidence": 0.7467269698455701, + "q": { + "size": 1.0, + "aspect": 0.8624536105407097, + "border": 1.0, + "center": 0.0, + "sharpness": 0.7134050632712029, + "homography": 0.9089132203508788, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9986245361054071, + "border": 1.0, + "center": 0.99, + "sharpness": 0.997134050632712, + "homography": 0.9990891322035088, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9849069655203322, + "raw": { + "mean_edge_px": 50.77022838592529, + "edge_ratio": 1.3189653049815784, + "distance_to_border_px": 149.0, + "distance_to_center_norm": 0.34769952297210693, + "laplacian_var": 1783.5126581780073 + } + }, + "mean_reprojection_error_px": 163.62727079508792, + "corner_reprojection_errors_px": [ + 164.9925267514254, + 195.46921994489523, + 166.5180336585285, + 127.52930282550257 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.4780463267147134, + "confidence_weighted": 0.46848012776799536, + "quality": { + "detector_confidence": 0.4780463267147134, + "weighted_confidence": 0.46848012776799536, + "q": { + "size": 1.0, + "aspect": 0.6468624400661076, + "border": 1.0, + "center": 0.0, + "sharpness": 0.6283678308439046, + "homography": 0.7101453224803067, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9964686244006611, + "border": 1.0, + "center": 0.99, + "sharpness": 0.996283678308439, + "homography": 0.997101453224803, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9799889709174003, + "raw": { + "mean_edge_px": 59.82627487182617, + "edge_ratio": 2.0918474719224776, + "distance_to_border_px": 163.0, + "distance_to_center_norm": 0.531389057636261, + "laplacian_var": 1570.9195771097613 + } + }, + "mean_reprojection_error_px": 39.913189837151904, + "corner_reprojection_errors_px": [ + 41.87309117550474, + 32.973954442868155, + 66.11821920721233, + 18.68749452302238 + ] + } + ] + }, + { + "marker_id": 247, + "link_name": "Ellbow", + "position_world_m": [ + 0.2687125544201488, + -0.009167604674109032, + 0.033778025764382 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.7010103986241017, + "mean_detector_confidence": 0.7117000257529918, + "mean_reprojection_error_px": 102.35857446070808, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.8796777163094818, + "confidence_weighted": 0.8670496997853304, + "quality": { + "detector_confidence": 0.8796777163094818, + "weighted_confidence": 0.8670496997853304, + "q": { + "size": 0.7921941375732422, + "aspect": 0.9657885238796377, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.8015391946807702, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9979219413757324, + "aspect": 0.9996578852387964, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9980153919468077, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9856447238687257, + "raw": { + "mean_edge_px": 39.60970687866211, + "edge_ratio": 1.0708467232203849, + "distance_to_border_px": 184.0, + "distance_to_center_norm": 0.22855591773986816, + "laplacian_var": 4202.582433286217 + } + }, + "mean_reprojection_error_px": 112.24175599930025, + "corner_reprojection_errors_px": [ + 128.22755608967458, + 129.80902970204835, + 100.25704493487244, + 90.67339327060562 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.7448005120854795, + "confidence_weighted": 0.7340842516844052, + "quality": { + "detector_confidence": 0.7448005120854795, + "weighted_confidence": 0.7340842516844052, + "q": { + "size": 1.0, + "aspect": 0.8537371543928008, + "border": 1.0, + "center": 0.0, + "sharpness": 0.8698383110697441, + "homography": 0.8325296434913341, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.998537371543928, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9986983831106975, + "homography": 0.9983252964349133, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9856119051649572, + "raw": { + "mean_edge_px": 51.05013561248779, + "edge_ratio": 1.3426413969560103, + "distance_to_border_px": 145.0, + "distance_to_center_norm": 0.28477779030799866, + "laplacian_var": 2174.5957776743603 + } + }, + "mean_reprojection_error_px": 133.79252008274474, + "corner_reprojection_errors_px": [ + 153.68125849002428, + 156.09016013832314, + 114.89720630378679, + 110.50145539884473 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.5106218488640142, + "confidence_weighted": 0.5018972444025696, + "quality": { + "detector_confidence": 0.5106218488640142, + "weighted_confidence": 0.5018972444025696, + "q": { + "size": 1.0, + "aspect": 0.6760419217397143, + "border": 1.0, + "center": 0.0, + "sharpness": 0.9265392364192184, + "homography": 0.6801291688207284, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9967604192173971, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9992653923641922, + "homography": 0.9968012916882073, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9829137658702729, + "raw": { + "mean_edge_px": 58.36018657684326, + "edge_ratio": 1.958396418454695, + "distance_to_border_px": 143.0, + "distance_to_center_norm": 0.41272374987602234, + "laplacian_var": 2316.348091048046 + } + }, + "mean_reprojection_error_px": 61.0414473000793, + "corner_reprojection_errors_px": [ + 81.18204901625982, + 66.99465013231631, + 55.649947539132306, + 40.339142512608746 + ] + } + ] + }, + { + "marker_id": 124, + "link_name": "Arm2", + "position_world_m": [ + 0.18131118911414393, + -0.10739570221017908, + -0.03189330410226154 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.4015628677453015, + "mean_detector_confidence": 0.4106676690676095, + "mean_reprojection_error_px": 260.07136092003475, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.34091855704160245, + "confidence_weighted": 0.33488305339370045, + "quality": { + "detector_confidence": 0.34091855704160245, + "weighted_confidence": 0.33488305339370045, + "q": { + "size": 0.7142756080627441, + "aspect": 0.7379840018220383, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.7675736815140904, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9971427560806274, + "aspect": 0.9973798400182203, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9976757368151409, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9822963475491728, + "raw": { + "mean_edge_px": 35.71378040313721, + "edge_ratio": 1.7100858488288635, + "distance_to_border_px": 332.0, + "distance_to_center_norm": 0.14613474905490875, + "laplacian_var": 3569.5639450778804 + } + }, + "mean_reprojection_error_px": 133.84586705079283, + "corner_reprojection_errors_px": [ + 119.82530745688197, + 102.71844746528825, + 148.11005996258078, + 164.72965331842028 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.4804167810936165, + "confidence_weighted": 0.46824268209690245, + "quality": { + "detector_confidence": 0.4804167810936165, + "weighted_confidence": 0.46824268209690245, + "q": { + "size": 1.0, + "aspect": 0.9604332717578841, + "border": 0.21666666666666667, + "center": 0.0, + "sharpness": 0.5040158791602892, + "homography": 0.7617971982706998, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9996043327175789, + "border": 0.9921666666666666, + "center": 0.99, + "sharpness": 0.9950401587916029, + "homography": 0.997617971982707, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9746592969358792, + "raw": { + "mean_edge_px": 61.16414737701416, + "edge_ratio": 1.0823934976132112, + "distance_to_border_px": 26.0, + "distance_to_center_norm": 0.5047972202301025, + "laplacian_var": 1260.039697900723 + } + }, + "mean_reprojection_error_px": 386.2968547892767, + "corner_reprojection_errors_px": [ + 335.99015619978667, + 377.81233094568637, + 434.52780813886665, + 396.8571238727673 + ] + } + ] + }, + { + "marker_id": 122, + "link_name": "Arm2", + "position_world_m": [ + 0.23901692370487546, + -0.11504425270797457, + -0.003712231187506812 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.5578116149791655, + "mean_detector_confidence": 0.5690911450460799, + "mean_reprojection_error_px": 156.97704137303592, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.18665602922528673, + "confidence_weighted": 0.18263714689166236, + "quality": { + "detector_confidence": 0.18665602922528673, + "weighted_confidence": 0.18263714689166236, + "q": { + "size": 0.7027967643737792, + "aspect": 0.654945658590568, + "border": 1.0, + "center": 0.0, + "sharpness": 0.9331720780648362, + "homography": 0.539630944261658, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9970279676437378, + "aspect": 0.9965494565859057, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9993317207806484, + "homography": 0.9953963094426166, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9784690462434849, + "raw": { + "mean_edge_px": 35.139838218688965, + "edge_ratio": 2.0536884606639982, + "distance_to_border_px": 242.0, + "distance_to_center_norm": 0.27940502762794495, + "laplacian_var": 2332.9301951620905 + } + }, + "mean_reprojection_error_px": 193.56682332292803, + "corner_reprojection_errors_px": [ + 163.97016509333642, + 190.41476052018322, + 221.47627845820935, + 198.40608921998313 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.9456847621099602, + "confidence_weighted": 0.9281720009504786, + "quality": { + "detector_confidence": 0.9456847621099602, + "weighted_confidence": 0.9281720009504786, + "q": { + "size": 1.0, + "aspect": 0.9720842559145406, + "border": 1.0, + "center": 0.0, + "sharpness": 0.4361118058809464, + "homography": 0.7295816020733066, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9997208425591454, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9943611180588094, + "homography": 0.997295816020733, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9814813964852218, + "raw": { + "mean_edge_px": 53.96408939361572, + "edge_ratio": 1.0574348240198506, + "distance_to_border_px": 283.0, + "distance_to_center_norm": 0.3038843870162964, + "laplacian_var": 1090.279514702366 + } + }, + "mean_reprojection_error_px": 181.7153931265307, + "corner_reprojection_errors_px": [ + 138.684540863363, + 193.0880077987136, + 223.0588957628043, + 172.030128081242 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.5749326438029929, + "confidence_weighted": 0.5626256970953559, + "quality": { + "detector_confidence": 0.5749326438029929, + "weighted_confidence": 0.5626256970953559, + "q": { + "size": 1.0, + "aspect": 0.7301044220084257, + "border": 1.0, + "center": 0.0, + "sharpness": 0.34034870646107274, + "homography": 0.7735552097414035, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9973010442200843, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9934034870646107, + "homography": 0.997735552097414, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9785941069092363, + "raw": { + "mean_edge_px": 75.16977119445801, + "edge_ratio": 1.7393341824971433, + "distance_to_border_px": 251.0, + "distance_to_center_norm": 0.45140743255615234, + "laplacian_var": 850.8717661526819 + } + }, + "mean_reprojection_error_px": 95.64890766964893, + "corner_reprojection_errors_px": [ + 53.773295761932275, + 105.21890905303789, + 145.62101368093536, + 77.98241218269024 + ] + } + ] + }, + { + "marker_id": 218, + "link_name": "Arm2", + "position_world_m": [ + 0.19340818513542216, + -0.10113511218407022, + -0.05496043872679098 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_detector_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 101, + "link_name": "Arm2", + "position_world_m": [ + 0.18131118911414393, + -0.1749517537389431, + -0.0502285134504796 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.3264687769670023, + "mean_detector_confidence": 0.3325004465415643, + "mean_reprojection_error_px": 264.93045143660436, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.3325004465415643, + "confidence_weighted": 0.3264687769670023, + "quality": { + "detector_confidence": 0.3325004465415643, + "weighted_confidence": 0.3264687769670023, + "q": { + "size": 0.7345538902282714, + "aspect": 0.6782259971718826, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.7627185514162481, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9973455389022827, + "aspect": 0.9967822599717188, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9976271855141625, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9818596647394037, + "raw": { + "mean_edge_px": 36.727694511413574, + "edge_ratio": 1.9488695631540953, + "distance_to_border_px": 265.0, + "distance_to_center_norm": 0.31515657901763916, + "laplacian_var": 3563.870814189421 + } + }, + "mean_reprojection_error_px": 264.93045143660436, + "corner_reprojection_errors_px": [ + 248.83022765040747, + 232.83467620506548, + 282.08856122928034, + 295.96834066166423 + ] + } + ] + }, + { + "marker_id": 102, + "link_name": "Arm2", + "position_world_m": [ + 0.2135630828168288, + -0.1847875031094183, + -0.013988709547700082 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.8354983021138915, + "mean_detector_confidence": 0.8473641170835915, + "mean_reprojection_error_px": 202.84175431125945, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence_detector": 0.9494437061622057, + "confidence_weighted": 0.9376120619964978, + "quality": { + "detector_confidence": 0.9494437061622057, + "weighted_confidence": 0.9376120619964978, + "q": { + "size": 0.9537287521362304, + "aspect": 0.9740662971297988, + "border": 1.0, + "center": 0.0, + "sharpness": 1.0, + "homography": 0.8234129943538817, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 0.9995372875213623, + "aspect": 0.9997406629712979, + "border": 1.0, + "center": 0.99, + "sharpness": 1.0, + "homography": 0.9982341299435388, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9875383405156971, + "raw": { + "mean_edge_px": 47.68643760681152, + "edge_ratio": 1.0532483321651058, + "distance_to_border_px": 309.0, + "distance_to_center_norm": 0.3549750745296478, + "laplacian_var": 3935.778766550373 + } + }, + "mean_reprojection_error_px": 274.9015986721038, + "corner_reprojection_errors_px": [ + 238.63013881195602, + 266.10100794961005, + 309.3183640595005, + 285.55688386734846 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence_detector": 0.8913851020933449, + "confidence_weighted": 0.880139786945703, + "quality": { + "detector_confidence": 0.8913851020933449, + "weighted_confidence": 0.880139786945703, + "q": { + "size": 1.0, + "aspect": 0.9425738852513735, + "border": 1.0, + "center": 0.0, + "sharpness": 0.7931141622847128, + "homography": 0.9999959590215692, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.9994257388525137, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9979311416228471, + "homography": 0.9999999595902157, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9873844479549488, + "raw": { + "mean_edge_px": 62.59456253051758, + "edge_ratio": 1.1218495773056807, + "distance_to_border_px": 134.0, + "distance_to_center_norm": 0.3347931206226349, + "laplacian_var": 1982.7854057117818 + } + }, + "mean_reprojection_error_px": 267.3922477582417, + "corner_reprojection_errors_px": [ + 230.84709969997198, + 248.37489636844154, + 301.82494379742434, + 288.52205116712895 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence_detector": 0.7012635429952238, + "confidence_weighted": 0.6887430573994738, + "quality": { + "detector_confidence": 0.7012635429952238, + "weighted_confidence": 0.6887430573994738, + "q": { + "size": 1.0, + "aspect": 0.8244031865405023, + "border": 1.0, + "center": 0.0, + "sharpness": 0.6987050522983833, + "homography": 0.6814939272403986, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "factor": { + "size": 1.0, + "aspect": 0.998244031865405, + "border": 1.0, + "center": 0.99, + "sharpness": 0.9969870505229839, + "homography": 0.9968149392724039, + "normal_visibility": 1.0, + "spin": 1.0 + }, + "weight_multiplier": 0.9821458198977909, + "raw": { + "mean_edge_px": 84.7633228302002, + "edge_ratio": 1.4259974156489281, + "distance_to_border_px": 140.0, + "distance_to_center_norm": 0.3269830048084259, + "laplacian_var": 1746.7626307459584 + } + }, + "mean_reprojection_error_px": 66.23141650343285, + "corner_reprojection_errors_px": [ + 109.10953068690768, + 54.093739871757776, + 12.868357032820903, + 88.85403842224508 + ] + } + ] + }, + { + "marker_id": 219, + "link_name": "Arm2", + "position_world_m": [ + 0.19340818513542216, + -0.20439936237803805, + -0.08298711587335288 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_detector_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + } + ], + "statistics": { + "observation_count": 34, + "camera_count": 3, + "marker_count": 23, + "observed_marker_count": 18, + "mean_detector_confidence": 0.5871913728875101, + "mean_weighted_confidence": 0.5774319023193206, + "mean_reprojection_error_px": 231.03443493219376, + "quality_means": { + "size": 0.8143773112577551, + "aspect": 0.834768084426124, + "border": 0.9237745098039215, + "homography": 0.7934741744632792 + }, + "quality_config": { + "size_ref_px": 50.0, + "border_ref_px": 120.0, + "center_ref_norm": 0.01, + "sharpness_ref": 2500.0, + "homography_ref": 0.18, + "size_factor": 0.01, + "aspect_factor": 0.01, + "border_factor": 0.01, + "center_factor": 0.01, + "sharpness_factor": 0.01, + "homography_factor": 0.01 + } + }, + "solver": { + "final_cost": 24726.245833952267, + "status": 0, + "message": "The maximum number of function evaluations is exceeded." + } +} \ No newline at end of file diff --git a/pipeline/multiview_pose_ohne_confidence.json b/pipeline/multiview_pose_ohne_confidence.json new file mode 100644 index 0000000..90170d9 --- /dev/null +++ b/pipeline/multiview_pose_ohne_confidence.json @@ -0,0 +1,966 @@ +{ + "schema_version": "1.0", + "created_utc": "2026-05-28T21:06:06.508985Z", + "source_robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\robot.json", + "source_detections": [ + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json" + ], + "robot_pose": { + "state": { + "x": 178.4429017494112, + "y": 58.47337818356634, + "z": -115.44834336922801, + "a": -110.23287555471994, + "b": 21.99999999999879, + "c": 91.00000000000222, + "e": 10.000000000003752 + }, + "uncertainty": { + "x_mm": 452.93520846643963, + "y_mm": 2505.6853087014742, + "z_mm": 479.7547548672694, + "a_deg": 419.0184635434338, + "b_deg": 10357.838151169784, + "c_deg": 10357.838358456424, + "e_mm": 103578.27625405855 + }, + "confidence": { + "x": 2.1343902596830898e-20, + "y": 1.5117142415373693e-109, + "z": 1.460547647110293e-21, + "a": 6.342483509852416e-19, + "b": 0.0, + "c": 0.0, + "e": 0.36787944117144233 + } + }, + "camera_poses": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + -152.34091569714903, + -19.013446299323782, + -99.72128351445228 + ], + "rvec": [ + -5.499131960772023, + -21.91270066095422, + 3.835322497331174 + ], + "tvec": [ + 1.5121559708775556, + 7.396415796967461, + -182.91147186295072 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 17 + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + 0.08962448933807897, + 0.30899658581804224, + -0.6948843092613544 + ], + "rvec": [ + -0.523540707058038, + -3.160660993109504, + -0.8426789395152159 + ], + "tvec": [ + 0.17310377758414208, + 0.03144977103054412, + -0.7452661514399899 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 10 + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "camera_id": "cam1", + "camera_position_world_m": [ + 0.19930315742175841, + -0.4034279127468583, + 0.6690051405865579 + ], + "rvec": [ + -3.515407873484386, + 0.6592488811642211, + 0.3554510183912642 + ], + "tvec": [ + -0.12629764596438484, + 0.0026714931553666757, + 0.7962948418902289 + ], + "intrinsics": { + "camera_matrix": [ + [ + 1777.77783203125, + 0.0, + 640.0 + ], + [ + 0.0, + 1500.0, + 360.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ], + "distortion_coefficients": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "observation_count": 7 + } + ], + "marker_positions": [ + { + "marker_id": 210, + "link_name": "Board", + "position_world_m": [ + 0.02, + -0.02, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.6997700579082148, + "mean_reprojection_error_px": 219.98520262396713, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.5673043275049208, + "mean_reprojection_error_px": 582.6928891559149, + "corner_reprojection_errors_px": [ + 608.4008310831335, + 564.1978138064919, + 556.9944685718621, + 601.1784431621722 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.7813266383036261, + "mean_reprojection_error_px": 39.955946109809304, + "corner_reprojection_errors_px": [ + 50.05440600297249, + 62.06318313444874, + 46.054117736318254, + 1.6520775654977295 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.7506792079160973, + "mean_reprojection_error_px": 37.30677260617712, + "corner_reprojection_errors_px": [ + 63.966234566185975, + 24.372791532782248, + 11.26324714586789, + 49.62481717987238 + ] + } + ] + }, + { + "marker_id": 211, + "link_name": "Board", + "position_world_m": [ + 0.25, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.6412317666518965, + "mean_reprojection_error_px": 213.01123894247837, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.6412317666518965, + "mean_reprojection_error_px": 213.01123894247837, + "corner_reprojection_errors_px": [ + 236.1031649719927, + 200.91925610460427, + 190.4144522672059, + 224.6080824261106 + ] + } + ] + }, + { + "marker_id": 215, + "link_name": "Board", + "position_world_m": [ + 0.25, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.8108527003549935, + "mean_reprojection_error_px": 198.10515794746527, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.7952557920267838, + "mean_reprojection_error_px": 204.57188538155356, + "corner_reprojection_errors_px": [ + 217.65412604361978, + 184.2181761177656, + 192.91255827135913, + 223.50268109346976 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.826449608683203, + "mean_reprojection_error_px": 191.63843051337702, + "corner_reprojection_errors_px": [ + 226.90990661141322, + 176.45008691276055, + 156.32935430702966, + 206.86437422230463 + ] + } + ] + }, + { + "marker_id": 214, + "link_name": "Board", + "position_world_m": [ + 0.35000000000000003, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.6041252446922665, + "mean_reprojection_error_px": 443.42359136317395, + "observations": [ + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.6041252446922665, + "mean_reprojection_error_px": 443.42359136317395, + "corner_reprojection_errors_px": [ + 448.5785815165172, + 422.5680699902232, + 440.44289571629525, + 462.10481822966005 + ] + } + ] + }, + { + "marker_id": 208, + "link_name": "Board", + "position_world_m": [ + 0.35000000000000003, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.6280424706698967, + "mean_reprojection_error_px": 104.44146786678962, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.6280424706698967, + "mean_reprojection_error_px": 104.44146786678962, + "corner_reprojection_errors_px": [ + 99.73569678834396, + 84.11026583409073, + 111.81629138739532, + 122.10361745732845 + ] + } + ] + }, + { + "marker_id": 206, + "link_name": "Board", + "position_world_m": [ + 0.65, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.33820423087105295, + "mean_reprojection_error_px": 269.1974700827843, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.33820423087105295, + "mean_reprojection_error_px": 269.1974700827843, + "corner_reprojection_errors_px": [ + 250.50345115135508, + 274.79359034013294, + 287.8396527117673, + 263.6531861278821 + ] + } + ] + }, + { + "marker_id": 205, + "link_name": "Board", + "position_world_m": [ + 0.75, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.28724459014346065, + "mean_reprojection_error_px": 418.6572411272094, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.28724459014346065, + "mean_reprojection_error_px": 418.6572411272094, + "corner_reprojection_errors_px": [ + 397.9342521865105, + 419.4901443591502, + 439.2360756416858, + 417.96849232149117 + ] + } + ] + }, + { + "marker_id": 207, + "link_name": "Board", + "position_world_m": [ + 0.75, + -0.01, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.27228561618555186, + "mean_reprojection_error_px": 365.7887375890425, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.27228561618555186, + "mean_reprojection_error_px": 365.7887375890425, + "corner_reprojection_errors_px": [ + 348.36626075065936, + 369.7628063312705, + 383.5097638627369, + 361.51611941150327 + ] + } + ] + }, + { + "marker_id": 217, + "link_name": "Board", + "position_world_m": [ + 0.65, + -0.09, + 0.0003 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.35596573288593486, + "mean_reprojection_error_px": 324.2590328208219, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.35596573288593486, + "mean_reprojection_error_px": 324.2590328208219, + "corner_reprojection_errors_px": [ + 302.09103568606685, + 325.56745248682427, + 346.3582043745394, + 323.01943873585714 + ] + } + ] + }, + { + "marker_id": 198, + "link_name": "Arm1", + "position_world_m": [ + 0.1784429017494112, + -0.05382924293825046, + 0.15468488162937843 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.16652042240877096, + "mean_reprojection_error_px": 173.03325228464936, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.20150745250271476, + "mean_reprojection_error_px": 247.8149724280193, + "corner_reprojection_errors_px": [ + 273.59743355359444, + 245.42488018268014, + 222.46143771784855, + 249.77613825795413 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.13153339231482716, + "mean_reprojection_error_px": 98.25153214127941, + "corner_reprojection_errors_px": [ + 86.59176111374053, + 97.5474468583387, + 120.03541185467505, + 88.83150873836338 + ] + } + ] + }, + { + "marker_id": 229, + "link_name": "Arm1", + "position_world_m": [ + 0.1784429017494112, + -0.100889763924023, + 0.23140063858026605 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.2274747191640703, + "mean_reprojection_error_px": 110.21276026061363, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.26810902547334975, + "mean_reprojection_error_px": 155.73254773328267, + "corner_reprojection_errors_px": [ + 180.08971330368811, + 157.10232370463987, + 131.63039756460225, + 154.10775636020045 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.18684041285479083, + "mean_reprojection_error_px": 64.69297278794461, + "corner_reprojection_errors_px": [ + 54.16045919019677, + 65.65659031871526, + 89.34107228321712, + 49.613769359649325 + ] + } + ] + }, + { + "marker_id": 242, + "link_name": "Arm1", + "position_world_m": [ + 0.1784429017494112, + -0.1605575748858245, + 0.19479801114688738 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 243, + "link_name": "Arm1", + "position_world_m": [ + 0.1784429017494112, + -0.14902498312161308, + 0.24293323034447747 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.9174550709990235, + "mean_reprojection_error_px": 44.17934855555228, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.8899728634608616, + "mean_reprojection_error_px": 78.81046188174007, + "corner_reprojection_errors_px": [ + 101.13197340765323, + 72.09114541671448, + 50.99718387664307, + 91.0215448259495 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.9132502955127223, + "mean_reprojection_error_px": 16.837449190455786, + "corner_reprojection_errors_px": [ + 14.377732738720587, + 19.045826627822404, + 19.362443297536196, + 14.563794097743955 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.9491420540234864, + "mean_reprojection_error_px": 36.89013459446098, + "corner_reprojection_errors_px": [ + 44.535439947724775, + 1.0820871934520055, + 48.70513064720212, + 53.23788058946502 + ] + } + ] + }, + { + "marker_id": 244, + "link_name": "Ellbow", + "position_world_m": [ + 0.3034429017494112, + 0.0, + 0.0 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 245, + "link_name": "Ellbow", + "position_world_m": [ + 0.2684429017494112, + 0.02934513796721045, + -0.019075190108761277 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 246, + "link_name": "Ellbow", + "position_world_m": [ + 0.2684429017494112, + -0.02934513796721045, + 0.019075190108761277 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.6792447690577089, + "mean_reprojection_error_px": 75.53581325353834, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.8015179238063419, + "mean_reprojection_error_px": 130.96780196095426, + "corner_reprojection_errors_px": [ + 131.52551717948674, + 149.219632082114, + 133.91939902794635, + 109.2066595542699 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.7581700566520715, + "mean_reprojection_error_px": 40.470485652838775, + "corner_reprojection_errors_px": [ + 54.08557804238714, + 23.05261314724495, + 38.690970054967124, + 46.052781366755866 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.4780463267147134, + "mean_reprojection_error_px": 55.16915214682197, + "corner_reprojection_errors_px": [ + 4.544326976345962, + 67.214794241062, + 103.3039176555024, + 45.61356971437756 + ] + } + ] + }, + { + "marker_id": 247, + "link_name": "Ellbow", + "position_world_m": [ + 0.23094290174941118, + -0.02934513796721045, + 0.019075190108761277 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.7117000257529918, + "mean_reprojection_error_px": 71.76825320561402, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.8796777163094818, + "mean_reprojection_error_px": 109.30571474994146, + "corner_reprojection_errors_px": [ + 125.10305772921419, + 126.687286672494, + 97.67977416118754, + 87.7527404368701 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.7448005120854795, + "mean_reprojection_error_px": 41.53123348024193, + "corner_reprojection_errors_px": [ + 62.91946766510497, + 50.39956997542899, + 30.245119355881712, + 22.56077692455205 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.5106218488640142, + "mean_reprojection_error_px": 64.46781138665867, + "corner_reprojection_errors_px": [ + 53.21697434340821, + 81.71744187395875, + 89.31098122106415, + 33.62584810820357 + ] + } + ] + }, + { + "marker_id": 124, + "link_name": "Arm2", + "position_world_m": [ + 0.1905471840415046, + -0.14689057815962717, + -0.16571856986506908 + ], + "size_m": 0.025, + "observation_count": 2, + "mean_confidence": 0.4106676690676095, + "mean_reprojection_error_px": 110.73873242579455, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.34091855704160245, + "mean_reprojection_error_px": 135.68416308738642, + "corner_reprojection_errors_px": [ + 122.09592215917837, + 104.54432626694273, + 149.5516106827851, + 166.54479324063954 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.4804167810936165, + "mean_reprojection_error_px": 85.79330176420268, + "corner_reprojection_errors_px": [ + 80.25443845468878, + 44.769514846082515, + 101.1257798229199, + 117.02347393311956 + ] + } + ] + }, + { + "marker_id": 122, + "link_name": "Arm2", + "position_world_m": [ + 0.2065917439726603, + -0.09049216814460652, + -0.1582492027972934 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.5690911450460799, + "mean_reprojection_error_px": 112.17658015146829, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.18665602922528673, + "mean_reprojection_error_px": 193.21424613028685, + "corner_reprojection_errors_px": [ + 163.5154782260392, + 189.8197178899714, + 221.16013279196892, + 198.36165561316793 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.9456847621099602, + "mean_reprojection_error_px": 59.619753741849934, + "corner_reprojection_errors_px": [ + 62.57446736991388, + 94.35842345190635, + 52.23720146118015, + 29.308922684399352 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.5749326438029929, + "mean_reprojection_error_px": 83.69574058226807, + "corner_reprojection_errors_px": [ + 95.82678742449872, + 125.24546180132528, + 68.46920157539058, + 45.24151152785769 + ] + } + ] + }, + { + "marker_id": 218, + "link_name": "Arm2", + "position_world_m": [ + 0.16633861945731776, + -0.03350621972608657, + -0.1118025920534069 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + }, + { + "marker_id": 101, + "link_name": "Arm2", + "position_world_m": [ + 0.146660650151536, + -0.08689676917303694, + -0.16058631632445308 + ], + "size_m": 0.025, + "observation_count": 1, + "mean_confidence": 0.3325004465415643, + "mean_reprojection_error_px": 267.5418618263792, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.3325004465415643, + "mean_reprojection_error_px": 267.5418618263792, + "corner_reprojection_errors_px": [ + 251.71309778665415, + 235.71974142034514, + 284.44360570880553, + 298.291002389712 + ] + } + ] + }, + { + "marker_id": 102, + "link_name": "Arm2", + "position_world_m": [ + 0.1637795636789253, + -0.12583826165265122, + -0.13527321767766717 + ], + "size_m": 0.025, + "observation_count": 3, + "mean_confidence": 0.8473641170835915, + "mean_reprojection_error_px": 135.5185983259116, + "observations": [ + { + "view_index": 0, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a.png", + "confidence": 0.9494437061622057, + "mean_reprojection_error_px": 275.69603657656097, + "corner_reprojection_errors_px": [ + 239.57198324805327, + 266.35716033620514, + 310.0207932359541, + 286.8342094860313 + ] + }, + { + "view_index": 1, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b.png", + "confidence": 0.8913851020933449, + "mean_reprojection_error_px": 62.952236808026484, + "corner_reprojection_errors_px": [ + 32.059770721250835, + 38.09936127795048, + 90.48302392022927, + 91.16679131267536 + ] + }, + { + "view_index": 2, + "source_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json", + "image_file": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c.png", + "confidence": 0.7012635429952238, + "mean_reprojection_error_px": 67.90752159314737, + "corner_reprojection_errors_px": [ + 102.72093538416912, + 41.99761561398122, + 26.866949386310086, + 100.04458598812904 + ] + } + ] + }, + { + "marker_id": 219, + "link_name": "Arm2", + "position_world_m": [ + 0.16633861945731776, + -0.09182180091572817, + -0.201514870981736 + ], + "size_m": 0.025, + "observation_count": 0, + "mean_confidence": null, + "mean_reprojection_error_px": null, + "observations": [] + } + ] +} \ No newline at end of file diff --git a/pipeline/multiview_pose_summary.json b/pipeline/multiview_pose_summary.json new file mode 100644 index 0000000..60c6c42 --- /dev/null +++ b/pipeline/multiview_pose_summary.json @@ -0,0 +1,72 @@ +{ + "schema_version": "1.0", + "created_utc": "2026-05-28T21:18:54.942233Z", + "source_robot_json": "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\robot.json", + "source_detections": [ + "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1a_aruco_detection.json", + "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1b_aruco_detection.json", + "c:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\pipeline\\render_1c_aruco_detection.json" + ], + "solver": { + "final_cost": 26976.87543820547, + "status": 0, + "message": "The maximum number of function evaluations is exceeded." + }, + "robot_pose": { + "state": { + "x": 100.21525656040845, + "y": 29.397626553503173, + "z": -36.04825291833897, + "a": -120.21337951359496, + "b": 22.00000000000008, + "c": 90.99999999999989, + "e": 10.000000000000258 + }, + "uncertainty": { + "x_mm": 17194.235819424397, + "y_mm": 6014.1408132596725, + "z_mm": 3621.298501957444, + "a_deg": 8796.009134059024, + "b_deg": 12562.017200522667, + "c_deg": 12562.017199380893, + "e_mm": 125620.17196327279 + }, + "confidence": { + "x": 0.0, + "y": 6.444409678452354e-262, + "z": 5.358019964976179e-158, + "a": 0.0, + "b": 0.0, + "c": 0.0, + "e": 0.36787944117144233 + } + }, + "statistics": { + "observation_count": 34, + "camera_count": 3, + "marker_count": 23, + "observed_marker_count": 18, + "mean_detector_confidence": 0.5871913728875101, + "mean_weighted_confidence": 0.5774319023193206, + "mean_reprojection_error_px": 236.06726174073253, + "quality_means": { + "size": 0.8143773112577551, + "aspect": 0.834768084426124, + "border": 0.9237745098039215, + "homography": 0.7934741744632792 + }, + "quality_config": { + "size_ref_px": 50.0, + "border_ref_px": 120.0, + "center_ref_norm": 0.01, + "sharpness_ref": 2500.0, + "homography_ref": 0.18, + "size_factor": 0.01, + "aspect_factor": 0.01, + "border_factor": 0.01, + "center_factor": 0.01, + "sharpness_factor": 0.01, + "homography_factor": 0.01 + } + } +} \ No newline at end of file diff --git a/pipeline/render_1a_aruco_detection.json b/pipeline/render_1a_aruco_detection.json index 4fc9276..be039ab 100644 --- a/pipeline/render_1a_aruco_detection.json +++ b/pipeline/render_1a_aruco_detection.json @@ -1,6 +1,6 @@ { "schema_version": "1.0", - "created_utc": "2026-05-28T20:31:58Z", + "created_utc": "2026-05-28T21:11:29Z", "vision_config": { "MarkerType": "DICT_4X4_250", "MarkerSize": 0.025 @@ -46,7 +46,7 @@ }, "detections": [ { - "observation_id": "11b87d79-31e1-4293-abe2-4327e2021077", + "observation_id": "e4f9bd9f-a867-4d2d-b0d3-c438f92fa01f", "type": "aruco", "marker_id": 102, "marker_size_m": 0.025, @@ -100,7 +100,7 @@ "confidence": 0.9494437061622057 }, { - "observation_id": "3f6119be-7ed5-4ba2-b0b8-f2eb85c0f4ac", + "observation_id": "3669c72d-6c64-46a9-9041-e0f332ed19a3", "type": "aruco", "marker_id": 243, "marker_size_m": 0.025, @@ -154,7 +154,7 @@ "confidence": 0.8899728634608616 }, { - "observation_id": "a963cd6a-dea8-47d2-ba29-7410d1add84e", + "observation_id": "920dccb3-6db8-43fb-b0b3-036af4ed6acb", "type": "aruco", "marker_id": 210, "marker_size_m": 0.025, @@ -208,7 +208,7 @@ "confidence": 0.5673043275049208 }, { - "observation_id": "5da8c3b3-2b28-47b4-9132-c5225c5ba0bb", + "observation_id": "858fbb79-58d9-436a-9147-96b0a15fd61e", "type": "aruco", "marker_id": 247, "marker_size_m": 0.025, @@ -262,7 +262,7 @@ "confidence": 0.8796777163094818 }, { - "observation_id": "b765e797-5dd9-4123-ac41-85b5606132a0", + "observation_id": "cafb1327-eefa-457c-9b1e-ed2d2ad78a8c", "type": "aruco", "marker_id": 246, "marker_size_m": 0.025, @@ -316,7 +316,7 @@ "confidence": 0.8015179238063419 }, { - "observation_id": "aca8152b-525f-45e7-9849-c46d2123a21c", + "observation_id": "cb014fcc-1cbe-4e59-afaa-6ea599b7f5ac", "type": "aruco", "marker_id": 101, "marker_size_m": 0.025, @@ -370,7 +370,7 @@ "confidence": 0.3325004465415643 }, { - "observation_id": "f0a37d05-7187-4ae1-a53a-2b0260b751b4", + "observation_id": "a59f4cec-6038-48f8-b124-11a1b6e89cf3", "type": "aruco", "marker_id": 215, "marker_size_m": 0.025, @@ -424,7 +424,7 @@ "confidence": 0.7952557920267838 }, { - "observation_id": "38cfa10c-246e-439d-ba19-ab664d030ccc", + "observation_id": "0d4d4912-7df5-4189-80d0-cc1066edd2e1", "type": "aruco", "marker_id": 124, "marker_size_m": 0.025, @@ -478,7 +478,7 @@ "confidence": 0.34091855704160245 }, { - "observation_id": "95edc7e5-0883-4ab5-8b6a-1f35d392d98a", + "observation_id": "47b5571d-68d0-4738-93c5-06c45c91168f", "type": "aruco", "marker_id": 229, "marker_size_m": 0.025, @@ -532,7 +532,7 @@ "confidence": 0.26810902547334975 }, { - "observation_id": "602d2bac-2427-4211-86be-9a2b5905a4e4", + "observation_id": "3a5f11f4-1233-41b7-9ce8-db0acaa2855e", "type": "aruco", "marker_id": 122, "marker_size_m": 0.025, @@ -586,7 +586,7 @@ "confidence": 0.18665602922528673 }, { - "observation_id": "308e1529-24a2-49e0-a7ad-6ac4fdead845", + "observation_id": "76947529-1679-4274-b547-56c7d61dde94", "type": "aruco", "marker_id": 198, "marker_size_m": 0.025, @@ -640,7 +640,7 @@ "confidence": 0.20150745250271476 }, { - "observation_id": "0159ed42-fec0-4b1c-a383-9ca83f5a320f", + "observation_id": "7a157cbe-69a0-4f8d-b89d-af82d8470779", "type": "aruco", "marker_id": 211, "marker_size_m": 0.025, @@ -694,7 +694,7 @@ "confidence": 0.6412317666518965 }, { - "observation_id": "4fa2ceb4-7915-4dba-b0f8-9700378eec0b", + "observation_id": "19c6229a-77c2-4846-86c2-2fe3cabd5ace", "type": "aruco", "marker_id": 208, "marker_size_m": 0.025, @@ -748,7 +748,7 @@ "confidence": 0.6280424706698967 }, { - "observation_id": "d3bc0898-720e-4180-b70a-57a9adc4a30e", + "observation_id": "cf1fe906-7f6e-459b-96cc-a983a15d58b7", "type": "aruco", "marker_id": 217, "marker_size_m": 0.025, @@ -802,7 +802,7 @@ "confidence": 0.35596573288593486 }, { - "observation_id": "d0d5506c-abf1-495f-bce9-33d4b374e599", + "observation_id": "249e0b3c-e2b1-40e4-baf8-073d85acc08c", "type": "aruco", "marker_id": 206, "marker_size_m": 0.025, @@ -856,7 +856,7 @@ "confidence": 0.33820423087105295 }, { - "observation_id": "7b5443c9-fb76-4270-8c88-32c5a20953c1", + "observation_id": "152dc984-1ca4-4ca0-aad7-1bbbd8aba04f", "type": "aruco", "marker_id": 205, "marker_size_m": 0.025, @@ -910,7 +910,7 @@ "confidence": 0.28724459014346065 }, { - "observation_id": "ac8f8ef1-039a-4762-a4f6-8bdea9e3a4e4", + "observation_id": "66ce6541-9898-4bfc-9201-0d05fa7e6e62", "type": "aruco", "marker_id": 207, "marker_size_m": 0.025, diff --git a/pipeline/render_1b_aruco_detection.json b/pipeline/render_1b_aruco_detection.json index f2e2679..ed0a67f 100644 --- a/pipeline/render_1b_aruco_detection.json +++ b/pipeline/render_1b_aruco_detection.json @@ -1,6 +1,6 @@ { "schema_version": "1.0", - "created_utc": "2026-05-28T20:31:58Z", + "created_utc": "2026-05-28T21:11:29Z", "vision_config": { "MarkerType": "DICT_4X4_250", "MarkerSize": 0.025 @@ -46,7 +46,7 @@ }, "detections": [ { - "observation_id": "e2619c8d-750d-4334-9b42-cb95426ed979", + "observation_id": "e57e88d8-4e83-459d-aacb-54dfb3d1a39f", "type": "aruco", "marker_id": 102, "marker_size_m": 0.025, @@ -100,7 +100,7 @@ "confidence": 0.8913851020933449 }, { - "observation_id": "d1d011f0-a579-448e-ace9-ea148ecbc5e7", + "observation_id": "3bb219ef-c7ff-4f0b-8cfa-284ead393c38", "type": "aruco", "marker_id": 124, "marker_size_m": 0.025, @@ -154,7 +154,7 @@ "confidence": 0.4804167810936165 }, { - "observation_id": "1b5435e6-7883-434c-a9c7-63f4b8d750d1", + "observation_id": "26604964-f6c1-492f-964c-850826bc69cf", "type": "aruco", "marker_id": 243, "marker_size_m": 0.025, @@ -208,7 +208,7 @@ "confidence": 0.9132502955127223 }, { - "observation_id": "a673d83e-73ff-4d2d-a412-470b6da12d56", + "observation_id": "5feff871-616f-43e8-b817-f5d67116b577", "type": "aruco", "marker_id": 122, "marker_size_m": 0.025, @@ -262,7 +262,7 @@ "confidence": 0.9456847621099602 }, { - "observation_id": "a755c678-9ad1-4af2-a744-a3c1a8ae0596", + "observation_id": "957db844-bb09-47b0-95a9-c2703a9f8a07", "type": "aruco", "marker_id": 247, "marker_size_m": 0.025, @@ -316,7 +316,7 @@ "confidence": 0.7448005120854795 }, { - "observation_id": "38397299-767f-490d-a47f-a3f09635e995", + "observation_id": "ce61eb47-425e-45a1-8079-a8da9414a07b", "type": "aruco", "marker_id": 246, "marker_size_m": 0.025, @@ -370,7 +370,7 @@ "confidence": 0.7581700566520715 }, { - "observation_id": "273cc5e9-e6e4-4359-8fb1-02a33a935f0d", + "observation_id": "408b46a0-047b-4718-bc75-25fe6edef9ed", "type": "aruco", "marker_id": 215, "marker_size_m": 0.025, @@ -424,7 +424,7 @@ "confidence": 0.826449608683203 }, { - "observation_id": "8da984fe-3152-43d6-8a39-b4e9266c2184", + "observation_id": "e971c366-cf09-4c98-8aba-6778415b54e2", "type": "aruco", "marker_id": 210, "marker_size_m": 0.025, @@ -478,7 +478,7 @@ "confidence": 0.7813266383036261 }, { - "observation_id": "92d1be16-65a4-4855-a63c-4d21357d0a9d", + "observation_id": "898e0c56-a4d2-4cbf-945e-1fa1cbec6ad5", "type": "aruco", "marker_id": 229, "marker_size_m": 0.025, @@ -532,7 +532,7 @@ "confidence": 0.18684041285479083 }, { - "observation_id": "5cbcbaf2-7581-4f25-81e3-85b4ce5a03b2", + "observation_id": "87adf180-14ed-459f-8d33-64e48ff2b517", "type": "aruco", "marker_id": 198, "marker_size_m": 0.025, diff --git a/pipeline/render_1c_aruco_detection.json b/pipeline/render_1c_aruco_detection.json index a5b9b3d..9aadc56 100644 --- a/pipeline/render_1c_aruco_detection.json +++ b/pipeline/render_1c_aruco_detection.json @@ -1,6 +1,6 @@ { "schema_version": "1.0", - "created_utc": "2026-05-28T20:31:59Z", + "created_utc": "2026-05-28T21:11:30Z", "vision_config": { "MarkerType": "DICT_4X4_250", "MarkerSize": 0.025 @@ -46,7 +46,7 @@ }, "detections": [ { - "observation_id": "6df4525f-58c7-4757-8a5e-130486fc123b", + "observation_id": "55dad250-7787-4d70-b26b-51bf9c63187f", "type": "aruco", "marker_id": 102, "marker_size_m": 0.025, @@ -100,7 +100,7 @@ "confidence": 0.7012635429952238 }, { - "observation_id": "c4dd28db-6041-4464-867a-96b25d671918", + "observation_id": "5af894e7-68a0-4872-ada4-689be1d630b6", "type": "aruco", "marker_id": 122, "marker_size_m": 0.025, @@ -154,7 +154,7 @@ "confidence": 0.5749326438029929 }, { - "observation_id": "5bdf65ad-9a27-4a28-be1e-6e925df61c72", + "observation_id": "47253afe-906c-444d-af3f-db6e99351519", "type": "aruco", "marker_id": 243, "marker_size_m": 0.025, @@ -208,7 +208,7 @@ "confidence": 0.9491420540234864 }, { - "observation_id": "37b9dec9-2578-4765-a40a-516fbe0424f5", + "observation_id": "4b090e16-a2e9-4cb6-81e4-307a04f04820", "type": "aruco", "marker_id": 246, "marker_size_m": 0.025, @@ -262,7 +262,7 @@ "confidence": 0.4780463267147134 }, { - "observation_id": "a49c96d9-7884-4ddb-8c07-8f86130b5220", + "observation_id": "8d0cb44f-1cd1-41a3-a6bc-c39527148ec7", "type": "aruco", "marker_id": 247, "marker_size_m": 0.025, @@ -316,7 +316,7 @@ "confidence": 0.5106218488640142 }, { - "observation_id": "4da1fc9d-a7a9-4dd8-a39b-a667b8d5d165", + "observation_id": "cde0d217-048d-42a3-88bd-52c1d620984f", "type": "aruco", "marker_id": 214, "marker_size_m": 0.025, @@ -370,7 +370,7 @@ "confidence": 0.6041252446922665 }, { - "observation_id": "a88abb43-d181-4584-b59b-28c65a2fff45", + "observation_id": "1e6148fd-0380-48d2-93f9-b4a546a35a7c", "type": "aruco", "marker_id": 210, "marker_size_m": 0.025, diff --git a/pipeline/run_pipeline.bat b/pipeline/run_pipeline.bat index fb817a1..26a5ea4 100644 --- a/pipeline/run_pipeline.bat +++ b/pipeline/run_pipeline.bat @@ -3,4 +3,4 @@ python3 1_detect_aruco_observations.py --image render_1a.png -npz render.npz -ro python3 1_detect_aruco_observations.py --image render_1b.png -npz render.npz -robot ../robot.json -cameraId cam1 -outDir . python3 1_detect_aruco_observations.py --image render_1c.png -npz render.npz -robot ../robot.json -cameraId cam1 -outDir . -python3 2_Multiview.py --robot ../robot.json --detections render_1a_aruco_detection.json render_1b_aruco_detection.json render_1c_aruco_detection.json --outDir . +python3 2_Multiview_ersteVersion.py --robot ../robot.json --detections render_1a_aruco_detection.json render_1b_aruco_detection.json render_1c_aruco_detection.json --outDir .