fix(work_plane): /fit returns full-scene cloud, not just ROI
The 3D viewer was only seeing points inside the ROI rectangle used for the plane fit. Now /fit also fetches nuwa.pointcloud (step=4, full frame), flips to CV frame, and returns it as points_camera (downsampled to max_preview_points). The user sees the entire scene with red = excluded by the below-plane filter, cyan = kept. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
56f8888217
commit
f75b9626be
1 file changed
+17
-7
@@ -1,6 +1,7 @@
|
|||||||
"""Work-plane calibration endpoints: fit (preview), save, get, delete."""
|
"""Work-plane calibration endpoints: fit (preview), save, get, delete."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -10,6 +11,8 @@ from fastapi import APIRouter, HTTPException
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from ..perception import filter_outliers, nuwa_to_cv_frame
|
from ..perception import filter_outliers, nuwa_to_cv_frame
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
from ..perception.work_plane import (
|
from ..perception.work_plane import (
|
||||||
WorkPlane,
|
WorkPlane,
|
||||||
WorkPlaneError,
|
WorkPlaneError,
|
||||||
@@ -83,17 +86,24 @@ def fit(req: FitReq) -> dict[str, Any]:
|
|||||||
created_at=time.time(),
|
created_at=time.time(),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Downsample for preview.
|
# Fetch the FULL-frame point cloud so the user can see the whole scene in
|
||||||
if len(pts_cv) > req.max_preview_points:
|
# 3D (not just the ROI), with each point colored by signed distance to
|
||||||
idx = np.random.choice(len(pts_cv), req.max_preview_points, replace=False)
|
# the fitted plane.
|
||||||
preview = pts_cv[idx]
|
try:
|
||||||
else:
|
with sw.step("pointcloud_full"):
|
||||||
preview = pts_cv
|
pc_full, _ = nuwa.pointcloud_with_meta(step=4, max_depth_mm=4000)
|
||||||
|
except Exception as e:
|
||||||
|
log.warning("Nuwa full pointcloud failed: %s — falling back to ROI cloud", e)
|
||||||
|
pc_full = pc
|
||||||
|
scene_cv = nuwa_to_cv_frame(pc_full[:, :3]) if len(pc_full) else np.empty((0, 3))
|
||||||
|
if len(scene_cv) > req.max_preview_points:
|
||||||
|
idx = np.random.choice(len(scene_cv), req.max_preview_points, replace=False)
|
||||||
|
scene_cv = scene_cv[idx]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"plane": asdict(wp),
|
"plane": asdict(wp),
|
||||||
"preview": True,
|
"preview": True,
|
||||||
"points_camera": preview.tolist(),
|
"points_camera": scene_cv.tolist(),
|
||||||
"timings_ms": sw.as_dict(),
|
"timings_ms": sw.as_dict(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user