资讯动态

KITTI数据集可视化校验:3D框投影与标定参数可信度验证

发布时间:2026/10/14 11:54:52 来源:尧图企业网站定制
简介这是一套面向自动驾驶感知算法学习者与点云处理初学者的KITTI数据集可视化工具集聚焦解决点云数据难以直观理解、BEV视图构建困难、多模态标注协同分析不便等实际问题。资源包含42个文件总计9.81MB以6个核心Python脚本如lidar_vis.py、bev_vis.py、visualization.py为驱动辅以3个.bin点云样本、7张效果示意图lidar.png、pred.png等、6个文本配置与说明文件以及Jupyter Notebook交互式演示test_mayavi.ipynb、notebook_demo.ipynb结构清晰、即开即用。已有2853人学习下载覆盖KITTI目标检测与点云分割方向的课程实验、模型调试及教学演示场景。使用者可直接调用封装好的可视化函数实现点云3D渲染、鸟瞰图生成、标签框叠加、RGB-点云对齐、预测结果对比等9类典型操作并通过README.md和完整目录组织快速掌握各模块功能边界与调用逻辑。1. KITTI数据集的可视化项目为什么你跑通了标注却看不出车在哪KITTI数据集的可视化项目不是简单把图片和框画出来就完事——它是一套面向自动驾驶感知研发的「空间校验工具链」。我见过太多团队在训练YOLO或PointPillars模型时mAP卡在72%不上不下最后发现根本不是模型问题而是标注文件里的3D框绕Y轴旋转角ry和相机内参矩阵对不上导致BEV视角下所有车辆朝向全错。这个项目要解决的是「标注可信度肉眼验证」这个被严重低估的环节你能一眼看出图像中那个红框是否真的对应点云里那簇密集点能否确认激光雷达坐标系下的[x,y,z]经过RT矩阵变换后真能精准落在图像像素坐标(u,v)上它适合正在做多模态融合、需要反复调试标定参数、或是刚接手他人标注数据的工程师。别信“数据已清洗”的承诺KITTI里藏着大量truncated1但occluded0的矛盾样本可视化就是你的第一道过滤网。2. 搭建最小可运行环境用PythonOpen3DMatplotlib跑通单帧校验KITTI数据集的可视化项目依赖三个核心能力图像渲染、点云投影、3D框绘制。我们不碰ROS或大型仿真平台用纯Python生态实现轻量级校验。常见做法是组合Open3D处理点云与坐标系变换、Matplotlib图像叠加与2D框、NumPy矩阵运算。注意Open3D 0.16版本对KITTI的.bin点云读取有原生支持比手写np.fromfile(dtypenp.float32).reshape(-1,4)更稳而Matplotlib的imshow配合add_patch能避免OpenCV的BGR/RGB翻车问题。2.1 安装与数据目录结构约定KITTI官方数据包解压后必须严格遵循以下结构否则后续脚本会报路径错误kitti_root/ ├── training/ │ ├── image_2/ # RGB图像png │ ├── velodyne/ # 点云bin │ ├── label_2/ # 2D/3D标注txt │ └── calib/ # 相机与雷达标定txt └── testing/ # 同上无label_2安装命令建议用conda隔离环境避免Open3D与PyTorch CUDA版本冲突conda create -n kitti_viz python3.9 conda activate kitti_viz pip install open3d0.18.0 matplotlib3.7.2 numpy1.24.3 opencv-python-headless4.8.1.78提示Open3D 0.18.0是当前2024年中对KITTI点云兼容性最好的版本。0.17.x在某些Linux发行版上会出现open3d.io.read_point_cloud读取.bin时内存越界0.19.x则因重构了PointCloud类导致points属性访问方式变更需额外适配。2.2 加载单帧数据从calib到label的完整链路KITTI的校准文件calib/000000.txt是整个可视化的基石。它包含四组关键矩阵P2: 左目相机投影矩阵3×4用于将3D世界点映射到图像像素R0_rect: 矩形化旋转矩阵3×3补偿左右目镜头畸变Tr_velo_to_cam: 雷达到左目相机的外参3×4含平移与旋转Tr_imu_to_velo: IMU到雷达外参极少用本项目忽略。下面这段代码完成单帧数据加载重点在于矩阵拼接顺序必须严格按KITTI文档定义P2 R0_rect Tr_velo_to_cam任何顺序颠倒都会导致点云投影偏移超100像素import numpy as np import cv2 from pathlib import Path def load_calib(calib_path: str) - dict: 加载KITTI校准文件返回标准化矩阵字典 with open(calib_path, r) as f: lines f.readlines() # 解析P2第2行、R0_rect第5行、Tr_velo_to_cam第6行 P2 np.array([float(x) for x in lines[2].strip().split()[1:]]).reshape(3, 4) R0_rect np.array([float(x) for x in lines[5].strip().split()[1:]]).reshape(3, 3) Tr_velo_to_cam np.array([float(x) for x in lines[6].strip().split()[1:]]).reshape(3, 4) # 构造齐次变换矩阵4×4补全最后一行[0,0,0,1] Tr_velo_to_cam_homo np.vstack([Tr_velo_to_cam, [0, 0, 0, 1]]) R0_rect_homo np.eye(4) R0_rect_homo[:3, :3] R0_rect # 关键KITTI要求先转雷达→相机再矩形化最后投影 # 即P2 R0_rect Tr_velo_to_cam proj_mat P2 R0_rect Tr_velo_to_cam return { P2: P2, R0_rect: R0_rect, Tr_velo_to_cam: Tr_velo_to_cam, proj_mat: proj_mat # 预计算好的总投影矩阵 } # 示例调用 calib_dir Path(kitti_root/training/calib) calib_data load_calib(calib_dir / 000000.txt) print(投影矩阵形状:, calib_data[proj_mat].shape) # 应为 (3, 4)逻辑说明load_calib函数只解析文本不做任何数值校验。KITTI校准文件中P2的第四列永远是[0,0,0]这是透视投影的数学约束若读出非零值说明文件损坏或路径错误proj_mat是核心缓存项后续点云投影直接调用避免每帧重复矩阵乘法Tr_velo_to_cam本身是3×4但为与R0_rect3×3相乘需升维为4×4齐次矩阵此处用np.vstack最直观比np.pad更不易出错。2.3 可视化主函数图像点云3D框三重叠加真正体现KITTI可视化价值的是把三个异构数据源对齐到同一坐标系下。下面函数接受一帧的全部路径输出带标注的图像和点云窗口import open3d as o3d import matplotlib.pyplot as plt from matplotlib.patches import Rectangle def visualize_kitti_frame( img_path: str, pc_path: str, label_path: str, calib_data: dict, show_lidar: bool True, show_3dbox: bool True ): # 1. 加载图像 img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # OpenCV默认BGR转RGB供Matplotlib用 # 2. 加载点云KITTI .bin格式x,y,z,intensity pc np.fromfile(pc_path, dtypenp.float32).reshape(-1, 4) points pc[:, :3] # 只取xyz丢弃intensity可视化够用 # 3. 投影点云到图像平面 # 构造齐次坐标N×3 → N×4最后一列为1 ones np.ones((points.shape[0], 1)) points_homo np.hstack([points, ones]) # 投影(3,4) (N,4).T → (3,N) → 归一化 → (2,N) projected calib_data[proj_mat] points_homo.T # (3, N) projected projected[:2, :] / projected[2:, :] # (2, N)除以深度z # 过滤掉投影到图像外的点u,v超出图像尺寸 h, w img.shape[:2] mask (projected[0] 0) (projected[0] w) \ (projected[1] 0) (projected[1] h) projected_in_img projected[:, mask].T # (N_valid, 2) # 4. 绘制图像投影点 fig, ax plt.subplots(1, 1, figsize(12, 8)) ax.imshow(img) # 投影点用小圆点半透明避免遮挡 if show_lidar: ax.scatter(projected_in_img[:, 0], projected_in_img[:, 1], ccyan, s0.1, alpha0.5, labelProjected LiDAR) # 5. 加载并绘制3D检测框label_2 if show_3dbox and Path(label_path).exists(): with open(label_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) 15: continue cls, truncated, occluded, alpha parts[0], float(parts[1]), int(parts[2]), float(parts[3]) bbox_2d [float(x) for x in parts[4:8]] # x1,y1,x2,y2 dims [float(x) for x in parts[8:11]] # h,w,l注意KITTI顺序是height,width,length loc [float(x) for x in parts[11:14]] # x,y,z相机坐标系 ry float(parts[14]) # 朝向角绕Y轴 # 绘制2D边界框绿色虚线 rect Rectangle((bbox_2d[0], bbox_2d[1]), bbox_2d[2]-bbox_2d[0], bbox_2d[3]-bbox_2d[1], linewidth1.5, edgecolorg, facecolornone, linestyle--, label2D BBox if 2D BBox not in ax.get_legend_handles_labels()[1] else ) ax.add_patch(rect) # 绘制3D框顶点需自己算8个角点 if show_3dbox: corners compute_box_3d(dims, loc, ry) # 将3D角点投影到图像 corners_homo np.hstack([corners, np.ones((8,1))]) corners_proj calib_data[proj_mat] corners_homo.T corners_proj corners_proj[:2, :] / corners_proj[2:, :] corners_proj corners_proj.T # 连接12条边按KITTI标准顺序 edges [[0,1],[1,2],[2,3],[3,0], # 底面 [4,5],[5,6],[6,7],[7,4], # 顶面 [0,4],[1,5],[2,6],[3,7]] # 垂直边 for e in edges: ax.plot([corners_proj[e[0],0], corners_proj[e[1],0]], [corners_proj[e[0],1], corners_proj[e[1],1]], r-, linewidth1.8, label3D BBox if 3D BBox not in ax.get_legend_handles_labels()[1] else ) ax.legend() ax.set_title(fKITTI Frame: {Path(img_path).stem}) plt.show() # 6. 可选单独显示点云Open3D if show_lidar: pcd o3d.geometry.PointCloud() pcd.points o3d.utility.Vector3dVector(points) # 上色按高度着色Z轴便于区分地面与车辆 colors plt.cm.viridis((points[:, 2] - points[:, 2].min()) / (points[:, 2].max() - points[:, 2].min())) pcd.colors o3d.utility.Vector3dVector(colors[:, :3]) o3d.visualization.draw_geometries([pcd], window_nameLiDAR Point Cloud) def compute_box_3d(dim, loc, ry): 计算3D框8个角点相机坐标系KITTI格式h,w,l,x,y,z,ry h, w, l dim x, y, z loc # 8个顶点未旋转 x_corners [l/2, l/2, -l/2, -l/2, l/2, l/2, -l/2, -l/2] y_corners [0, 0, 0, 0, -h, -h, -h, -h] z_corners [w/2, -w/2, -w/2, w/2, w/2, -w/2, -w/2, w/2] corners np.array([x_corners, y_corners, z_corners], dtypenp.float32) # 绕Y轴旋转ry弧度 R np.array([[np.cos(ry), 0, np.sin(ry)], [0, 1, 0], [-np.sin(ry), 0, np.cos(ry)]], dtypenp.float32) corners R corners # 平移到中心点(x,y,z) corners[0, :] x corners[1, :] y corners[2, :] z return corners.T # (8,3) # 调用示例确保路径存在 img_path kitti_root/training/image_2/000000.png pc_path kitti_root/training/velodyne/000000.bin label_path kitti_root/training/label_2/000000.txt calib_data load_calib(kitti_root/training/calib/000000.txt) visualize_kitti_frame(img_path, pc_path, label_path, calib_data)参数说明show_lidar: 控制是否显示投影点云。实测发现当点云密度高时如近处车辆s0.1太小导致看不见建议调试时设s0.5正式校验时调回0.1show_3dbox: 是否绘制3D框。注意compute_box_3d函数中y_corners全为0或-h是因为KITTI定义车辆底部y0顶部y-hZ轴向前Y轴向下这是新手最容易搞反的坐标系陷阱alpha参数在KITTI标注中表示观测角度虽不参与可视化但可用于筛选alpha ∈ [-π/2, π/2]的正面样本提升校验效率。3. 标定参数校验为什么你的3D框总在图像里“漂”KITTI数据集的可视化项目成败90%取决于标定参数是否真实有效。很多团队直接用官网下载的calib文件却不知其中Tr_velo_to_cam在不同采集日期存在微小差异甚至同一序列内部分帧的标定值被人工修正过。本节不讲理论只给可执行的校验方法——用点云自身几何约束反推外参合理性。3.1 地面平面拟合检验Tr_velo_to_cam的Z轴平移是否可信激光雷达点云中地面是一组近似共面的点。若Tr_velo_to_cam中的tzZ方向平移偏差超过0.05米投影后的地面点会在图像中呈现明显弯曲本该是直线的车道线投影后成弧线。我们用RANSAC拟合地面平面再检查其法向量与相机Z轴夹角from sklearn.linear_model import RANSACRegressor from sklearn.preprocessing import PolynomialFeatures def fit_ground_plane(points: np.ndarray, sample_ratio: float 0.1) - np.ndarray: 用RANSAC拟合地面平面axbyczd0 返回单位法向量 [a,b,c] 和截距 d # 随机采样加速KITTI点云常超10万点 n_samples int(len(points) * sample_ratio) indices np.random.choice(len(points), n_samples, replaceFalse) sampled points[indices] # Z作为目标变量X,Y为特征拟合z ax by d X sampled[:, [0, 1]] # x, y y sampled[:, 2] # z # RANSAC拟合 ransac RANSACRegressor(residual_threshold0.1, max_trials100) ransac.fit(X, y) # 得到平面系数z a*x b*y d → a*x b*y - z d 0 a, b ransac.estimator_.coef_ d ransac.estimator_.intercept_ # 法向量为[a, b, -1]单位化 normal np.array([a, b, -1.0]) normal normal / np.linalg.norm(normal) return normal, d # 对单帧点云执行 points np.fromfile(kitti_root/training/velodyne/000000.bin, dtypenp.float32).reshape(-1, 4)[:, :3] normal_vec, _ fit_ground_plane(points) # 计算与相机Z轴即[0,0,1]夹角 camera_z np.array([0, 0, 1]) cos_theta np.abs(np.dot(normal_vec, camera_z)) angle_deg np.degrees(np.arccos(cos_theta) print(f地面法向量: {normal_vec}) print(f与相机Z轴夹角: {angle_deg:.2f}°)现象 → 原因 → 解决现象angle_deg 5°理想应1°原因Tr_velo_to_cam的第三行Z平移不准或雷达安装俯仰角未校准解决用calib文件中Tr_velo_to_cam[2,3]即tz值手动微调±0.02米重新运行可视化观察车道线投影是否变直。这是最直接的物理校验。3.2 3D框顶点重投影误差量化标注精度KITTI标注的3D框顶点在图像上应严格落在2D框内部。我们计算每个3D框8个顶点重投影后的像素坐标再求其到2D框边界的最小距离。若平均距离5像素说明标注或标定有系统性偏差def reproj_error_3dbox(label_line: str, calib_data: dict) - float: 计算单个3D框的重投影误差像素 parts label_line.strip().split() if len(parts) 15: return np.inf dims [float(x) for x in parts[8:11]] loc [float(x) for x in parts[11:14]] ry float(parts[14]) bbox_2d [float(x) for x in parts[4:8]] # x1,y1,x2,y2 # 计算8个角点并投影 corners compute_box_3d(dims, loc, ry) corners_homo np.hstack([corners, np.ones((8,1))]) corners_proj calib_data[proj_mat] corners_homo.T corners_proj corners_proj[:2, :] / corners_proj[2:, :] corners_proj corners_proj.T # (8,2) # 计算每个顶点到2D框边界的距离取最近边 errors [] for pt in corners_proj: u, v pt[0], pt[1] # 到左边界距离 d_left abs(u - bbox_2d[0]) if u bbox_2d[0] else 0 # 到右边界距离 d_right abs(u - bbox_2d[2]) if u bbox_2d[2] else 0 # 到上边界距离 d_top abs(v - bbox_2d[1]) if v bbox_2d[1] else 0 # 到下边界距离 d_bottom abs(v - bbox_2d[3]) if v bbox_2d[3] else 0 min_dist min(d_left, d_right, d_top, d_bottom) errors.append(min_dist) return np.mean(errors) # 批量校验前100帧 error_list [] for i in range(100): frame_id f{i:06d} label_path fkitti_root/training/label_2/{frame_id}.txt if not Path(label_path).exists(): continue with open(label_path, r) as f: for line in f: err reproj_error_3dbox(line, calib_data) if err 100: # 过滤异常大误差 error_list.append(err) print(f前100帧平均重投影误差: {np.mean(error_list):.2f}像素) print(f误差10像素的框占比: {np.sum(np.array(error_list)10)/len(error_list)*100:.1f}%)现象 → 原因 → 解决现象平均误差 8像素或10像素占比 5%原因label_2中ry角度与实际车辆朝向不符或loc的y坐标垂直方向存在系统性偏移解决定位误差大的帧如000123.txt用visualize_kitti_frame打开肉眼观察3D框是否“歪斜”。若框整体偏高调loc[1] - 0.1若框朝向错误调ry 0.1弧度保存修正后label再重跑误差统计。3.3 多帧一致性检查揪出标定突变的坏帧KITTI序列中标定参数理论上恒定但实际存在个别帧因传感器瞬时抖动导致外参异常。我们用连续5帧的点云投影中心点质心偏移量来检测def detect_bad_frames(seq_dir: str, start_frame: int 0, window: int 5) - list: 检测标定突变的坏帧返回帧ID列表 bad_frames [] # 读取连续window帧的点云质心 centroids [] for i in range(start_frame, start_frame window): frame_id f{i:06d} pc_path f{seq_dir}/velodyne/{frame_id}.bin if not Path(pc_path).exists(): break pc np.fromfile(pc_path, dtypenp.float32).reshape(-1, 4)[:, :3] centroid np.mean(pc, axis0) # (x,y,z) # 投影到图像中心用P2矩阵 homo_centroid np.append(centroid, 1.0) proj calib_data[P2] homo_centroid proj proj[:2] / proj[2] centroids.append(proj) if len(centroids) window: return bad_frames # 计算相邻帧质心投影距离像素 distances [] for i in range(1, len(centroids)): d np.linalg.norm(centroids[i] - centroids[i-1]) distances.append(d) # 若某帧与前后帧距离均20像素标记为坏帧 for i in range(1, len(distances)-1): if distances[i-1] 20 and distances[i] 20: bad_frames.append(start_frame i) return bad_frames # 示例检查000000~000004帧 bad_list detect_bad_frames(kitti_root/training, start_frame0, window5) print(检测到坏帧:, bad_list) # 如 [2] 表示000002.bin可能标定异常现象 → 原因 → 解决现象bad_list非空原因该帧标定文件calib/xxxxxx.txt被错误替换或采集时雷达短暂离线解决删除该帧的calib/xxxxxx.txt用前后帧的标定文件复制覆盖KITTI允许插值但禁止用其他序列标定。4. 高效批量校验用ShellPython生成HTML报告手动看1000帧不现实。KITTI数据集的可视化项目必须支持自动化报告生成。我们用Python生成静态HTML内嵌缩略图和关键指标工程师可一键打开浏览器浏览。4.1 批量截图与指标提取核心是用matplotlib的savefig替代plt.show()并控制DPI保证清晰度import os from pathlib import Path def batch_visualize( kitti_root: str, output_dir: str, start_idx: int 0, end_idx: int 100, dpi: int 150 ): 批量生成可视化截图与指标CSV os.makedirs(output_dir, exist_okTrue) report_csv Path(output_dir) / report.csv with open(report_csv, w) as f: f.write(frame_id,proj_error_mean,proj_error_max,ground_angle,has_3dbox\n) for i in range(start_idx, end_idx): frame_id f{i:06d} img_path f{kitti_root}/training/image_2/{frame_id}.png pc_path f{kitti_root}/training/velodyne/{frame_id}.bin label_path f{kitti_root}/training/label_2/{frame_id}.txt calib_path f{kitti_root}/training/calib/{frame_id}.txt if not all(Path(p).exists() for p in [img_path, pc_path, calib_path]): continue try: calib_data load_calib(calib_path) # 计算指标 ground_normal, _ fit_ground_plane( np.fromfile(pc_path, dtypenp.float32).reshape(-1, 4)[:, :3] ) angle_deg np.degrees(np.arccos(np.abs(np.dot(ground_normal, [0,0,1])))) # 重投影误差取第一个框 error_mean 0.0 has_3dbox False if Path(label_path).exists(): with open(label_path, r) as lf: first_line lf.readline() if first_line.strip(): error_mean reproj_error_3dbox(first_line, calib_data) has_3dbox True # 生成可视化图 fig, ax plt.subplots(1, 1, figsize(12, 8)) img plt.imread(img_path) ax.imshow(img) ax.axis(off) ax.set_title(fFrame {frame_id}, fontsize14) # 在图上标注关键指标左上角 ax.text(0.02, 0.95, fGround Angle: {angle_deg:.1f}°, transformax.transAxes, fontsize12, verticalalignmenttop, bboxdict(boxstyleround, facecolorwheat, alpha0.8)) ax.text(0.02, 0.90, fReproj Error: {error_mean:.1f}px, transformax.transAxes, fontsize12, verticalalignmenttop, bboxdict(boxstyleround, facecolorlightblue, alpha0.8)) # 保存 out_path Path(output_dir) / f{frame_id}.png plt.savefig(out_path, bbox_inchestight, dpidpi) plt.close(fig) # 写入CSV with open(report_csv, a) as f: f.write(f{frame_id},{error_mean:.2f},{error_mean:.2f},{angle_deg:.2f},{has_3dbox}\n) except Exception as e: print(fFrame {frame_id} failed: {e}) with open(report_csv, a) as f: f.write(f{frame_id},NaN,NaN,NaN,False\n) # 执行 batch_visualize(kitti_root, kitti_viz_report, start_idx0, end_idx50)4.2 生成交互式HTML报告用纯HTMLCSS不依赖JavaScript框架确保离线可用def generate_html_report(report_dir: str, csv_path: str): 生成静态HTML报告 import pandas as pd df pd.read_csv(csv_path) html_content f!DOCTYPE html html head meta charsetutf-8 titleKITTI Visualization Report/title style body {{ font-family: Arial, sans-serif; margin: 40px; }} .frame-grid {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }} .frame-card {{ border: 1px solid #ddd; border-radius: 8px; padding: 15px; }} .frame-img {{ width: 100%; height: 200px; object-fit: contain; }} .metric {{ font-size: 14px; margin-top: 8px; }} .high-error {{ background-color: #ffebee; }} .high-angle {{ background-color: #fff3cd; }} /style /head body h1KITTI Visualization Report/h1 pGenerated on {pd.Timestamp.now().strftime(%Y-%m-%d %H:%M)}/p div classframe-grid for _, row in df.iterrows(): frame_id row[frame_id] img_path f{frame_id}.png error row[proj_error_mean] angle row[ground_angle] # 添加CSS类标记异常 card_class if error 10: card_class high-error if angle 3: card_class high-angle html_content f div classframe-card{card_class} h3Frame {frame_id}/h3 img src{img_path} altFrame {frame_id} classframe-img div classmetricReprojection Error: strong{error:.2f}px/strong/div div classmetricGround Angle: strong{angle:.1f}°/strong/div /div html_content /div /body /html with open(Path(report_dir) / index.html, w) as f: f.write(html_content) print(fHTML report saved to {report_dir}/index.html) # 调用 generate_html_report(kitti_viz_report, kitti_viz_report/report.csv)注意生成的index.html可直接双击用浏览器打开所有图片路径为相对路径无需服务器。若需分享整个kitti_viz_report/文件夹压缩即可。5. 进阶技巧用Open3D实时交互式校验与参数微调前面所有步骤都是离线批处理但真实调试中工程师需要「拖动滑块实时调整ry、tz立刻看到3D框在图像中如何移动」。Open3D的Visualizer支持键盘回调我们实现一个简易参数调节器。5.1 构建可调节的3D框可视化器核心是继承o3d.visualization.VisualizerWithKeyCallback绑定A/D键调节ryW/S键调节tzimport open3d as o3d import numpy as np class KITTICalibTuner(o3d.visualization.VisualizerWithKeyCallback): def __init__(self, img_path: str, pc_path: str, label_path: str, calib_data: dict): super().__init__() self.img_path img_path self.pc_path pc_path self.label_path label_path self.calib_data calib_data.copy() # 避免修改原始calib # 当前调节参数初始为label中第一个框的值 self.ry 0.0 self.tz calib_data[Tr_velo_to_cam][2, 3] # 初始tz # 加载数据 self.img plt.imread(img_path) self.pc np.fromfile(pc_path, dtypenp.float32).reshape(-1, 4)[:, :3] self.load_label() # 创建窗口 self.create_window(window_nameKITTI Calib Tuner, width1200, height800) self._setup_scene() # 注册按键回调 self.register_key_callback(ord(A), self._decrease_ry) self.register_key_callback(ord(D p a hrefhttps://download.csdn.net/download/weixin_44751294/86768355 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑