Click-to-fullscreen debug images + highlight detected lines on 3D scene

- Debug images clickable — opens fullscreen overlay (click to close)
- After calibration, detected court lines highlighted on 3D scene
  (blue for CAM0, pink for CAM1)
- Return matched_lines_3d from calibration (baseline, kitchen, sidelines, service)
- Show line names in calibration results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ruslan Bakiev
2026-03-22 14:53:37 +07:00
parent 8ec4ccf109
commit 6225809459
2 changed files with 105 additions and 1 deletions

View File

@@ -133,6 +133,7 @@ def auto_calibrate():
'debug_image': base64.b64encode(jpeg.tobytes()).decode('ascii'),
'lines_detected': {'across': n_across, 'along': n_along},
'points_matched': len(match['points_2d']),
'matched_lines_3d': match.get('matched_lines_3d', []),
}
print(f"[CAM {sensor_id}] Calibrated! Camera at "
f"({cam_pos[0]:.2f}, {cam_pos[1]:.2f}, {cam_pos[2]:.2f}), "
@@ -359,13 +360,51 @@ def _match_court_lines(grouped, side, frame_w, frame_h):
points_2d.append(pt)
points_3d.append([across_3d_x[1], center_service_y, 0])
# Build list of matched 3D court lines for visualization
matched_lines_3d = []
# Baseline
matched_lines_3d.append({
'name': 'baseline',
'from': [across_3d_x[0], along_3d_y[0], 0],
'to': [across_3d_x[0], along_3d_y[1], 0],
})
# Kitchen
matched_lines_3d.append({
'name': 'kitchen',
'from': [across_3d_x[1], along_3d_y[0], 0],
'to': [across_3d_x[1], along_3d_y[1], 0],
})
# Left sideline
matched_lines_3d.append({
'name': 'sideline_near',
'from': [across_3d_x[0], along_3d_y[0], 0],
'to': [across_3d_x[1], along_3d_y[0], 0],
})
# Right sideline
matched_lines_3d.append({
'name': 'sideline_far',
'from': [across_3d_x[0], along_3d_y[1], 0],
'to': [across_3d_x[1], along_3d_y[1], 0],
})
# Center service (if detected)
if len(along_sorted) >= 3:
matched_lines_3d.append({
'name': 'center_service',
'from': [across_3d_x[0], center_service_y, 0],
'to': [across_3d_x[1], center_service_y, 0],
})
if len(points_2d) < 4:
return {
'points_2d': None, 'points_3d': None,
'matched_lines_3d': matched_lines_3d,
'error': f'Only {len(points_2d)} intersection points found (need >= 4)',
}
return {'points_2d': points_2d, 'points_3d': points_3d, 'error': None}
return {
'points_2d': points_2d, 'points_3d': points_3d,
'matched_lines_3d': matched_lines_3d, 'error': None,
}