feat(work_plane gui): overlay inliers used for fit as blue dots on RGB
The fit endpoint now returns fit_points_px (the post-outlier-filter inliers projected to RGB pixels via Nuwa's RGB intrinsics). The GUI draws them on the same overlay as the ROI rectangle so the user can visually verify which depth pixels were fed to fit_plane_svd. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
76e0739620
commit
ae510e4387
2 files changed
+47
-2
No files matched your search
+15
-1
@@ -10,6 +10,7 @@ const RGB_REFRESH_MS = 1000;
|
||||
let roi = null; // {u0,v0,u1,v1} in image pixel coords
|
||||
let previewPlane = null; // last response.plane (preview, not saved)
|
||||
let previewPoints = null; // list of [x,y,z] in CV camera frame, meters
|
||||
let fitPointsPx = null; // list of [u,v] pixels of inliers used for the fit
|
||||
let savedPlane = null; // last GET /api/work_plane response.plane
|
||||
|
||||
function setChip(text, level) {
|
||||
@@ -89,6 +90,12 @@ function startRgbLoop() {
|
||||
function drawOverlay() {
|
||||
const ctx = overlay.getContext('2d');
|
||||
ctx.clearRect(0, 0, overlay.width, overlay.height);
|
||||
// Inliers used for the last fit, drawn first so the ROI rectangle stays
|
||||
// on top.
|
||||
if (fitPointsPx && fitPointsPx.length) {
|
||||
ctx.fillStyle = '#4da3ff';
|
||||
for (const [u, v] of fitPointsPx) ctx.fillRect(u, v, 2, 2);
|
||||
}
|
||||
if (roi) {
|
||||
ctx.strokeStyle = '#9b6dff';
|
||||
ctx.lineWidth = 2;
|
||||
@@ -99,11 +106,15 @@ function startRgbLoop() {
|
||||
drawCross(ctx, firstCorner.u, firstCorner.v);
|
||||
}
|
||||
}
|
||||
// Re-export so doFit can refresh the overlay after a successful fit.
|
||||
window.__wpDrawOverlay = drawOverlay;
|
||||
|
||||
viewport.addEventListener('click', (e) => {
|
||||
const p = imgPixelFromEvent(e);
|
||||
if (firstCorner === null && roi === null) {
|
||||
// First click: place corner A.
|
||||
// First click: place corner A. Drop any stale fit-points overlay so we
|
||||
// don't suggest the new ROI is being analyzed yet.
|
||||
fitPointsPx = null;
|
||||
firstCorner = p;
|
||||
drawOverlay();
|
||||
setChip('punto 1/2 piazzato — clicca il secondo angolo');
|
||||
@@ -132,6 +143,7 @@ function startRgbLoop() {
|
||||
}
|
||||
// ROI already set: start a new selection on the next click.
|
||||
roi = null;
|
||||
fitPointsPx = null;
|
||||
firstCorner = p;
|
||||
drawOverlay();
|
||||
setRoiInfo();
|
||||
@@ -277,8 +289,10 @@ async function doFit() {
|
||||
if (r.detail) throw new Error(formatDetail(r.detail));
|
||||
previewPlane = r.plane;
|
||||
previewPoints = r.points_camera;
|
||||
fitPointsPx = r.fit_points_px || null;
|
||||
three.setPlane(previewPlane);
|
||||
three.setScatter(previewPoints, previewPlane, previewPlane.offset_mm);
|
||||
if (window.__wpDrawOverlay) window.__wpDrawOverlay();
|
||||
renderDetails(previewPlane);
|
||||
$('wpStateBlock').innerHTML = `<strong>preview</strong> · RMS ${previewPlane.fit_rms_mm.toFixed(1)} mm · n_inliers ${previewPlane.n_inliers} · offset ${previewPlane.offset_mm} mm · <span class="warn">non salvato</span>`;
|
||||
setChip('preview pronto', 'ok');
|
||||
|
||||
Reference in new issue
Block a user