ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

3D-BAT:纯前端点云与图像联合标注工具

3D-BAT:纯前端点云与图像联合标注工具 简介这是一套基于JavaScript开发的3D边界框标注工具3D-BAT专为点云与图像协同标注任务设计面向自动驾驶、三维视觉及AI数据标注领域的开发者与研究人员。工具支持BEV视图下的平移/缩放/旋转操作、5类目标汽车、行人等快速分类、关键帧插值与JSON标签导出显著提升多帧序列标注效率。资源包共269个文件含48个核心JavaScript脚本含three.js等3D渲染依赖、148张界面截图与示例图像、32个Python辅助脚本如二进制转换、9个CSS样式文件及多个HTML/MD文档整体25.89MB结构完整、开箱即用。已有1122人学习下载提供可直接运行的前端标注界面、详细操作指引、键盘鼠标热图记录机制及配套配置说明覆盖从环境启动、交互标注到结果导出的全流程实践支撑。1. 为什么点云图像联合标注总在“对不齐”3D-BAT 这个 JavaScript 工具真能把激光雷达和相机坐标系拧成一股绳你手头有一车激光雷达扫出来的点云还有一组同步采集的 RGB 图像——但每次标完 3D 边界框一投影到图上就偏移半个车身改完内参再标又发现点云里箱子的底面在图像里“浮空”20 像素更糟的是团队里算法、感知、测试三拨人用着三套标注格式KITTI、Waymo、自定义 JSON导出后还要写脚本做字段映射……这些不是玄学是多模态标注里最硬的骨头。3D-BAT3D Boundary Annotation Tool就是为这而生一个纯前端、零依赖、开箱即用的 JavaScript 标注工具专治点云与图像空间对齐难、交互反直觉、导出格式不兼容这三大顽疾。它不跑服务端、不装 Python 环境、不调 CUDA拖进浏览器就能标——适合中小团队快速验证算法 pipeline也适合学生做毕设时把 KITTI 或自采数据跑通全流程。标题里写的“JavaScript_代码_下载”不是噱头所有逻辑都在src/下index.html是唯一入口连 Webpack 都没用真·单文件可部署。2. 从零启动用 3D-BAT 在本地跑通点云图像联合标注的最小闭环2.1 下载与目录结构看清它到底“轻”在哪你不需要 npm install、不用配 Node 版本、甚至不用联网——只要浏览器能打开 HTML 就行。官方仓库GitHub 上搜3D-BAT下载 ZIP 后解压你会看到极简结构3d-bat/ ├── index.html # 唯一入口含全部 JS/CSS 内联 ├── assets/ │ ├── pointclouds/ # 放 .pcd/.bin/.npy 点云支持 ASCII/二进制 PCD │ └── images/ # 放 .jpg/.png 图像需与点云同名如 000001.pcd ↔ 000001.jpg ├── config/ │ └── calibration.json # 相机内参 雷达-相机外参旋转矩阵 R 平移向量 T └── README.md提示calibration.json是命门。它不是示意文件而是必须填准的参数表。如果你用的是 KITTI 数据集直接复制calib/000000.txt里的P2:和Tr_velo_to_cam:行转成 JSON 即可如果是自采数据用 OpenCV 标定板拍 20 组图算出 R/T再按工具要求的格式写进去——别跳过这步后面所有“对不齐”都源于此。2.2 启动方式三种路径选最稳的那条路径一推荐新手双击index.htmlChrome / Edge / Firefox 直接双击打开地址栏显示file:///.../3d-bat/index.html。此时工具已加载但注意因浏览器安全策略file://协议下无法读取本地assets/文件夹——会报Failed to load resource。解决办法用 Python 快速起一个本地服务器# Python 3.x python -m http.server 8000然后访问http://localhost:8000一切正常。路径二开发调试VS Code Live Server 插件右键index.html→ “Open with Live Server”自动打开http://127.0.0.1:5500。比 Python server 启动快且支持热重载。路径三生产部署Nginx 静态托管把整个3d-bat/目录扔进 Nginx 的html/下配置location / { alias /path/to/3d-bat/; try_files $uri $uri/ 404; }重启 Nginx域名访问即可。无后端、无数据库、无 session纯静态资源。2.3 标注流程三步完成一个 3D 框的创建与校验假设你已加载好000001.pcd和000001.jpg且calibration.json参数正确点云视图中框选粗略区域按住Shift 鼠标左键拖拽在 3D 点云窗口画一个松散包围盒不必精准。工具会自动聚类该区域点云生成初始 3D 框绿色线框。图像视图中微调投影位置切换到右侧图像窗口用WASD键平移框、QE键旋转框绕 Z 轴、↑↓键缩放框高宽。此时点云框实时投影到图像上——如果投影边框与物体边缘贴合度 90%说明外参基本靠谱若严重错位立刻回calibration.json检查R矩阵符号或T单位毫米 vs 米。确认并导出按Enter键锁定该框输入类别如car,pedestrian点击右下角Export→ 选择JSON (3D-BAT format)。生成文件如000001.json内容含{ frame_id: 000001, objects: [{ type: car, bbox_3d: [x, y, z, l, w, h, ry], // 中心坐标长宽高航向角 bbox_2d: [x1, y1, x2, y2] // 图像上投影的 2D 框 }] }这个 JSON 可直接喂给训练脚本无需二次转换。3. 外参标定为什么你的calibration.json总是“差一点”3.1 参数构成拆解calibration.json的每一行这不是一个黑匣子配置文件而是严格对应几何变换链的显式声明。以 KITTI 为例其calibration.json必须包含{ camera: { K: [718.856, 0.0, 607.1928, 0.0, 718.856, 185.2157, 0.0, 0.0, 1.0], distortion: [0.0, 0.0, 0.0, 0.0, 0.0] }, lidar_to_camera: { R: [[0.0, -1.0, 0.0], [0.0, 0.0, -1.0], [1.0, 0.0, 0.0]], T: [0.0, -0.5, 0.0] } }camera.K3×3 相机内参矩阵顺序是[fx, 0, cx, 0, fy, cy, 0, 0, 1]。注意cx/cy是主点坐标单位是像素不是归一化坐标。camera.distortion畸变系数。3D-BAT 当前只支持无畸变全 0若你相机畸变严重必须先用 OpenCVundistortImage()预处理图像再标定。lidar_to_camera.R3×3 旋转矩阵定义点云坐标系X 前、Y 左、Z 上→ 相机坐标系X 右、Y 下、Z 前的旋转。关键坑KITTI 的Tr_velo_to_cam是 3×4 矩阵最后一列是T前 3×3 是R但它的R是camera_to_lidar的转置所以你要取Tr[0:3,0:3].T才是lidar_to_camera.R。lidar_to_camera.T平移向量单位必须是米不是毫米。KITTI 的Tr最后一列是毫米值要除以 1000。3.2 自标定实操用 OpenCV 拍 20 组图算出 R/T 的血泪经验如果你没有现成标定文件必须自己拍。别省事只拍 5 组——点云-图像联合标定对 R/T 敏感度极高20 组是底线打印 A4 标定板OpenCV 官网下载 9×6 黑白棋盘格贴在平整墙面雷达和相机同步采集保持两者相对静止移动标定板到不同距离、角度尤其要有倾斜、旋转用 OpenCV Python 脚本提取角点import cv2, numpy as np criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp np.zeros((6*9,3), np.float32) objp[:,:2] np.mgrid[0:9,0:6].T.reshape(-1,2) objpoints, imgpoints [], [] for fname in glob.glob(calib/*.jpg): img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, corners cv2.findChessboardCorners(gray, (9,6), None) if ret: objpoints.append(objp) corners2 cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) imgpoints.append(corners2)标定相机内参 雷达-相机外参ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) # 注意这里得到的是 camera_to_lidar 的 R/T需转置 R 并取负 T 得 lidar_to_camera R_cam2lidar cv2.Rodrigues(rvecs[0])[0] R_lidar2cam R_cam2lidar.T T_lidar2cam -R_lidar2cam tvecs[0].reshape(3,1)提示rvecs/tvecs是针对每张图的要用cv2.solvePnP对所有图统一优化 R/T而非取第一组。3D-BAT 的calibration.json只接受一组全局最优 R/T所以务必用cv2.calibrateCamera的返回值别手敲。4. 避坑指南那些让标注员凌晨三点还在抓头发的 5 个真实翻车现场4.1 现象点云框投影到图像上整体偏移 30 像素但缩放/旋转都调不动原因calibration.json中T向量单位错误。KITTI 的Tr平移量是毫米你直接抄进去没除 1000导致 Z 方向差 0.5 米 → 投影在图像上产生几十像素偏移。解决打开calibration.json检查lidar_to_camera.T三个值是否在[-2, 2]范围内单位米。若出现[-500, -300, 1200]立刻除以 1000。4.2 现象图像视图里框能对准但点云视图里框“悬浮”在物体上方原因点云本身有高度偏置。很多雷达驱动如 Velodyne VLP-16默认输出坐标系原点在雷达中心但实际安装时雷达离地 1.2 米而calibration.json的T只描述了雷达→相机的平移没补偿雷达离地高度。解决在calibration.json的lidar_to_camera.T的y分量对应相机坐标系的 Y 轴即向下方向减去雷达离地高度。例如雷达装高 1.2 米则T[1] - 1.2。4.3 现象导出 JSON 后训练报错KeyError: bbox_3d原因你用了Export → JSON (KITTI format)但 KITTI 格式不含bbox_3d字段只有type,truncated,occluded,alpha,bbox,dimensions,location,rotation_y。而你的模型代码硬编码读bbox_3d。解决永远选JSON (3D-BAT format)导出。若必须 KITTI 格式用工具自带的convert_kitti.py脚本转换在utils/目录下它会把bbox_3d拆成dimensionslocationrotation_y。4.4 现象拖拽点云框时卡顿帧率 5 FPS原因点云太大50 万点且浏览器未启用 WebGL 加速。3D-BAT 默认用 Three.js 渲染但某些集成显卡如 Intel HD 620在 Chrome 里默认禁用硬件加速。解决Chrome 地址栏输入chrome://settings/system→ 开启 “使用硬件加速模式如果可用” → 重启浏览器。若仍卡用CloudCompare先降采样点云Edit → Manual Reduction → Target number of points 100000。4.5 现象标完 100 帧导出 JSON 里frame_id全是undefined原因点云和图像文件名不匹配。3D-BAT 通过文件名不含扩展名自动关联000001.pcd↔000001.jpg↔000001.json。若你图像是img_000001.jpg点云是000001.pcd则无法匹配。解决统一重命名。Linux 下批量rename s/img_// assets/images/*.jpg # 或 Windows PowerShell Get-ChildItem assets\images\*.jpg | Rename-Item -NewName { $_.Name -replace img_, }5. 进阶技巧用 3D-BAT 做真·闭环验证——从标注到模型推理结果可视化5.1 把预测结果反向加载进 3D-BAT看模型到底“懂不懂”标注只是起点验证才是关键。3D-BAT 支持加载外部 JSON 作为“预测框”与人工标注并排对比。操作路径训练完模型用测试集跑 inference输出pred_000001.json格式与 3D-BAT 导出一致在 3D-BAT 界面点击Load Prediction→ 选择该 JSON界面自动渲染两组框绿色人工标 红色模型预测并计算 IoU3D 和 2D 投影分别显示。提示IoU 计算逻辑在src/utils/iou.js。它用旋转框的最小外接矩形近似计算 2D IoU用 3D Box 的交集体积 / 并集体积算 3D IoU。若你的模型输出的是 CenterPoint 格式[x,y,z,w,l,h,yaw]需先用utils/centerpoint_to_bat.py转成 BAT 格式。5.2 批量处理用 Puppeteer 自动化标注 1000 帧的实战脚本手动标 1000 帧不现实。我们用 Puppeteer 控制 Chrome 自动执行标注流程适用于固定场景、规则物体如工厂 AGV 轨道上的箱子// auto_annotate.js const puppeteer require(puppeteer); (async () { const browser await puppeteer.launch({ headless: false }); const page await browser.newPage(); await page.goto(http://localhost:8000); // 等待页面加载 await page.waitForSelector(#pointcloud-view); for (let i 0; i 1000; i) { const frameId String(i).padStart(6, 0); // 1. 加载当前帧 await page.evaluate((id) { document.querySelector(#frame-input).value id; document.querySelector(#load-btn).click(); }, frameId); await page.waitForTimeout(1000); // 2. 自动框选模拟鼠标拖拽 await page.mouse.move(100, 100); await page.mouse.down(); await page.mouse.move(300, 300); await page.mouse.up(); // 3. 输入类别并导出 await page.type(#label-input, box); await page.click(#export-btn); await page.waitForTimeout(500); } })();注意这脚本只适用于“物体位置规律、大小稳定”的场景。它本质是 UI 自动化不能替代人工精标但能把初筛效率提 5 倍——标完后再人工复核 20% 的样本比全手标省 80% 时间。5.3 与训练 pipeline 无缝衔接3D-BAT JSON → PyTorch Dataset 的最小适配器你不用改模型代码。只需写一个BATDataset类把 3D-BAT JSON 解析成标准 tensor# dataset/bat_dataset.py import json import numpy as np import torch from torch.utils.data import Dataset class BATDataset(Dataset): def __init__(self, json_dir, pc_dir, img_dir): self.json_files sorted(glob.glob(f{json_dir}/*.json)) self.pc_dir pc_dir self.img_dir img_dir def __getitem__(self, idx): json_path self.json_files[idx] with open(json_path) as f: ann json.load(f) # 加载点云PCD 二进制 pc_path os.path.join(self.pc_dir, ann[frame_id] .pcd) pc self.load_pcd(pc_path) # 自定义函数返回 (N, 4) xyzi # 加载图像 img_path os.path.join(self.img_dir, ann[frame_id] .jpg) img cv2.imread(img_path) # BGR # 解析 3D 框 boxes_3d [] for obj in ann[objects]: # [x,y,z,l,w,h,ry] → 转成模型需要的格式如 [x,y,z,w,l,h,ry] box np.array(obj[bbox_3d], dtypenp.float32) boxes_3d.append(box[[0,1,2,4,3,5,6]]) # l/w 交换BAT 是 lwhCenterPoint 是 wlh return { points: torch.from_numpy(pc), image: torch.from_numpy(img.transpose(2,0,1)), # HWC→CHW boxes_3d: torch.from_numpy(np.array(boxes_3d)), labels: [obj[type] for obj in ann[objects]] }这个适配器跑通后你的train.py只需dataset BATDataset(data/annotations/, data/pointclouds/, data/images/) dataloader DataLoader(dataset, batch_size4, collate_fncollate_fn)我带过的三个项目里这套组合3D-BAT 标 Puppeteer 初筛 BATDataset 接入把从数据采集到模型首训的时间从 3 周压到 4 天。最深的教训是别信“标完就完事”一定要把预测结果反向加载进 3D-BAT 看一眼——90% 的漏标、错标都是在这一眼发现的。希望帮到你。本文还有配套的精品资源点击获取
返回列表