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

@@ -335,6 +335,7 @@
border-radius: 4px;
border: 1px solid #333;
display: block;
cursor: pointer;
}
.cal-debug-card .cal-live {
opacity: 0.5;
@@ -356,6 +357,23 @@
z-index: 1;
}
/* Fullscreen image overlay */
.fullscreen-overlay {
display: none;
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
z-index: 1000;
background: rgba(0,0,0,0.95);
cursor: pointer;
align-items: center;
justify-content: center;
}
.fullscreen-overlay.show { display: flex; }
.fullscreen-overlay img {
max-width: 95vw;
max-height: 95vh;
object-fit: contain;
}
</style>
</head>
<body>
@@ -374,6 +392,9 @@
</div>
<div class="event-banner" id="eventBanner">VAR: Close Call</div>
<div class="fullscreen-overlay" id="fullscreenOverlay" onclick="this.classList.remove('show')">
<img id="fullscreenImg">
</div>
<!-- Tab 1: Camera -->
<div class="tab-content active" id="tab-camera">
@@ -533,6 +554,9 @@ function doCalibrate() {
fetch('/api/calibration/data')
.then(function(r) { return r.json(); })
.then(function(camData) { addCamerasToScene(camData); });
// Highlight detected court lines on 3D scene
if (data.result) highlightDetectedLines(data.result);
} else {
btn.textContent = 'Calibrate';
// Show errors
@@ -555,6 +579,15 @@ function doCalibrate() {
});
}
// ===================== Fullscreen image viewer =====================
document.querySelectorAll('.cal-debug-card img').forEach(function(img) {
img.addEventListener('click', function() {
if (!this.src || this.src === location.href) return;
document.getElementById('fullscreenImg').src = this.src;
document.getElementById('fullscreenOverlay').classList.add('show');
});
});
var systemReady = false;
function updateCalibrationStatus() {
@@ -621,6 +654,38 @@ function addCamerasToScene(camData) {
}
}
// ===================== Highlight detected court lines on 3D =====================
var detectedLineMeshes = [];
function highlightDetectedLines(calibResult) {
if (!courtSceneInitialized) return;
// Remove old highlights
detectedLineMeshes.forEach(function(m) { courtScene.remove(m); });
detectedLineMeshes = [];
var camColors = { '0': 0x44aaff, '1': 0xff44aa };
for (var sid in calibResult) {
var r = calibResult[sid];
var lines3d = r.matched_lines_3d || [];
var color = camColors[sid] || 0xffffff;
for (var i = 0; i < lines3d.length; i++) {
var l = lines3d[i];
var z = 0.08; // slightly above court surface
var geo = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(l.from[0], l.from[1], z),
new THREE.Vector3(l.to[0], l.to[1], z)
]);
var mat = new THREE.LineBasicMaterial({ color: color, linewidth: 3 });
var mesh = new THREE.Line(geo, mat);
courtScene.add(mesh);
detectedLineMeshes.push(mesh);
}
}
}
// ===================== Camera frame polling =====================
var camPrefixes = { 'camera': 'cam', 'calibration': 'cal', 'trajectory': 'traj' };