diff --git a/tools/calibrator/app.js b/tools/calibrator/app.js index 39fd7ed..75c4bda 100644 --- a/tools/calibrator/app.js +++ b/tools/calibrator/app.js @@ -91,17 +91,43 @@ function addPoint(event) { setStatus("请先抓取一帧"); return; } - const rect = canvas.getBoundingClientRect(); - const scaleX = canvas.width / rect.width; - const scaleY = canvas.height / rect.height; + const imageRect = getCanvasImageRect(); + const rawX = event.clientX - imageRect.left; + const rawY = event.clientY - imageRect.top; + if (rawX < 0 || rawY < 0 || rawX > imageRect.width || rawY > imageRect.height) { + setStatus("请点击截图实际显示区域内"); + return; + } const point = { - x: clamp(((event.clientX - rect.left) * scaleX) / canvas.width), - y: clamp(((event.clientY - rect.top) * scaleY) / canvas.height), + x: clamp(rawX / imageRect.width), + y: clamp(rawY / imageRect.height), }; state.polygons[state.activeZone].push(point); render(); } +function getCanvasImageRect() { + const rect = canvas.getBoundingClientRect(); + const canvasRatio = canvas.width / canvas.height; + const elementRatio = rect.width / rect.height; + if (elementRatio > canvasRatio) { + const width = rect.height * canvasRatio; + return { + left: rect.left + (rect.width - width) / 2, + top: rect.top, + width, + height: rect.height, + }; + } + const height = rect.width / canvasRatio; + return { + left: rect.left, + top: rect.top + (rect.height - height) / 2, + width: rect.width, + height, + }; +} + function undoPoint() { state.polygons[state.activeZone].pop(); render(); diff --git a/web/src/main.js b/web/src/main.js index 1e4b515..e0ebf11 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -325,13 +325,41 @@ function addPoint(event) { setStatus("请先从 RTSP 抓取一帧"); return; } - const rect = els.canvas.getBoundingClientRect(); - const x = clamp((event.clientX - rect.left) / rect.width); - const y = clamp((event.clientY - rect.top) / rect.height); + const imageRect = getCanvasImageRect(); + const rawX = event.clientX - imageRect.left; + const rawY = event.clientY - imageRect.top; + if (rawX < 0 || rawY < 0 || rawX > imageRect.width || rawY > imageRect.height) { + setStatus("请点击截图实际显示区域内"); + return; + } + const x = clamp(rawX / imageRect.width); + const y = clamp(rawY / imageRect.height); state.polygons[state.activeRegion].push({x: round(x), y: round(y)}); render(); } +function getCanvasImageRect() { + const rect = els.canvas.getBoundingClientRect(); + const canvasRatio = els.canvas.width / els.canvas.height; + const elementRatio = rect.width / rect.height; + if (elementRatio > canvasRatio) { + const width = rect.height * canvasRatio; + return { + left: rect.left + (rect.width - width) / 2, + top: rect.top, + width, + height: rect.height, + }; + } + const height = rect.width / canvasRatio; + return { + left: rect.left, + top: rect.top + (rect.height - height) / 2, + width: rect.width, + height, + }; +} + function undoPoint() { state.polygons[state.activeRegion].pop(); render();