Dexcap复现代码数据预处理全流程(四)——demo_clipping_3d.py

此脚本的主要功能是可视化点云数据文件(.pcd 文件),并通过键盘交互选择演示数据的起始帧和结束帧,生成片段标记文件 (clip_marks.json)

主要流程包括:

  • 用户指定数据目录:检查目录是否存在并处理标记文件 ->
  • 加载帧数据并渲染:使用 Open3D 可视化点云数据和几何结构 ->
  • 监听键盘输入:通过键盘动态导航帧,并标记片段的起始和结束 ->
  • 保存标记数据:将标记的片段保存为 JSON 文件

目录

[1 库引用](#1 库引用)

[2 主程序入口](#2 主程序入口)

[3 处理 clip_marks.json 文件](#3 处理 clip_marks.json 文件)

[3 初始化 ReplayDataVisualizer](#3 初始化 ReplayDataVisualizer)

[4 键盘交互](#4 键盘交互)

[5 回放帧可视化](#5 回放帧可视化)


1 库引用

python 复制代码
import argparse
import os
import copy
import zmq
import cv2
import sys
import json
import shutil
import open3d as o3d
import numpy as np
import platform
from pynput import keyboard
from transforms3d.quaternions import qmult, quat2mat
from transforms3d.axangles import axangle2mat
from scipy.spatial.transform import Rotation
from transforms3d.euler import quat2euler, mat2euler, quat2mat, euler2mat
from visualizer import *

# 全局变量定义
clip_marks = []  # 存储所有片段标记
current_clip = {}  # 当前片段的起始和结束标记
next_frame = False  # 用于指示是否跳转到下一帧
previous_frame = False  # 用于指示是否跳转到上一帧

2 主程序入口

python 复制代码
# 主程序入口
if __name__ == "__main__":
    # 解析命令行参数
    parser = argparse.ArgumentParser(description="Visualize saved frame data.")
    parser.add_argument("--directory", type=str, default="./saved_data", help="Directory with saved data")
    args = parser.parse_args()

    # 检查输入目录是否存在
    assert os.path.exists(args.directory), f"given directory: {args.directory} not exists"

解析命令行参数 -> 检查并处理 clip_marks.json -> 初始化数据可视化器 -> 启动回放帧可视化,并监听用户交互

命令行参数解析与输入校验:

  1. 解析命令行参数:--directory 参数指定数据目录,默认为 ./saved_data

  2. 校验输入路径:检查指定目录是否存在,否则直接报错退出

3 处理 clip_marks.json 文件

python 复制代码
    # 检查是否已有 clip_marks.json 文件,避免误覆盖
    if os.path.exists(os.path.join(args.directory, 'clip_marks.json')):
        response = (
            input(
                f"clip_marks.json already exists. Do you want to override? (y/n): "
            )
            .strip()
            .lower()
        )
        if response != "y":
            print("Exiting program without overriding the existing directory.")
            sys.exit()

如果 clip_marks.json 已存在,提示用户是否覆盖:

  • 输入 y:继续运行,并允许覆盖文件
  • 输入其他内容:程序退出,避免覆盖原有标记数据

3 初始化 ReplayDataVisualizer

python 复制代码
    # 数据目录
    dataset_folder = args.directory

    # 初始化可视化器
    visualizer = ReplayDataVisualizer(args.directory)

    # 加载左右手校准数据(偏移和旋转)
    visualizer.right_hand_offset = np.loadtxt("{}/calib_offset.txt".format(args.directory))
    visualizer.right_hand_ori_offset = np.loadtxt("{}/calib_ori_offset.txt".format(args.directory))
    visualizer.left_hand_offset = np.loadtxt("{}/calib_offset_left.txt".format(args.directory))
    visualizer.left_hand_ori_offset = np.loadtxt("{}/calib_ori_offset_left.txt".format(args.directory))

    # 开始帧回放和交互
    visualizer.replay_frames()

初始化自定义类 ReplayDataVisualizer,继承自 DataVisualizer 类

从文件中加载左右手的偏移数据(位置偏移和旋转偏移),用于调整点云的显示

4 键盘交互

python 复制代码
# 键盘按下事件的回调函数
def on_press(key):
    """
    当键盘按键被按下时触发。
    根据按键执行相应的功能,例如帧跳转、标记起始/结束、保存标记等。
    """
    global next_frame, previous_frame, frame, clip_marks, current_clip

    # 当前帧的文件夹名
    frame_folder = 'frame_{}'.format(frame)

    # 根据键盘按键的类型执行操作
    if key == keyboard.Key.up:  # 按下"上箭头"保存当前所有标记到 JSON 文件
        with open(os.path.join(dataset_folder, 'clip_marks.json'), 'w') as f:
            json.dump(clip_marks, f, indent=4)
    elif key == keyboard.Key.down:  # 按下"下箭头"跳转到上一帧
        previous_frame = True
    elif key == keyboard.Key.page_down:  # 按下"Page Down"键跳转到下一帧
        next_frame = True
    elif key == keyboard.Key.end:  # 按下"End"键标记当前片段结束
        if 'start' in current_clip.keys():  # 只有当前片段有起点时才允许结束
            print("end", frame_folder)
            current_clip['end'] = frame_folder  # 设置结束帧
            clip_marks.append(current_clip)  # 将当前片段添加到标记列表
            current_clip = {}  # 清空当前片段
    elif key == keyboard.Key.insert:  # 按下"Insert"键标记当前片段开始
        print("start", frame_folder)
        current_clip['start'] = frame_folder  # 设置起始帧
    else:
        print("Key error", key)  # 其他按键未定义功能

监听键盘输入,并根据按键触发相应功能:

  • Insert:标记当前帧为片段的起始帧
  • End:标记当前帧为片段的结束帧,并保存到 clip_marks 列表
  • Page Down:跳转到下一帧
  • Down Arrow:跳转到上一帧
  • Up Arrow:将标记的片段保存到 clip_marks.json 文件

5 回放帧可视化

python 复制代码
# 定义自定义可视化类,继承 DataVisualizer
class ReplayDataVisualizer(DataVisualizer):
    def __init__(self, directory):
        """
        初始化 ReplayDataVisualizer 类
        :param directory: 数据目录路径
        """
        super().__init__(directory)

    def replay_frames(self):
        """
        帧回放和交互函数。
        可视化点云数据,并支持用户通过键盘交互切换帧和标记片段。
        """
        global next_frame, previous_frame, frame

        # 初始化基准帧
        if self.R_delta_init is None:
            self.initialize_canonical_frame()

        # 加载初始帧数据
        self._load_frame_data(frame)

        # 将几何体添加到可视化场景中
        self.vis.add_geometry(self.pcd)  # 添加点云
        self.vis.add_geometry(self.coord_frame_1)  # 添加坐标系1
        self.vis.add_geometry(self.coord_frame_2)  # 添加坐标系2
        self.vis.add_geometry(self.coord_frame_3)  # 添加坐标系3
        for joint in self.left_joints + self.right_joints:  # 添加所有关节
            self.vis.add_geometry(joint)
        for cylinder in self.left_line_set + self.right_line_set:  # 添加所有连杆
            self.vis.add_geometry(cylinder)

        # 使用键盘监听器处理交互事件
        try:
            with keyboard.Listener(on_press=on_press) as listener:
                while True:
                    # 跳转到下一帧
                    if next_frame:
                        next_frame = False
                        frame += 10  # 每次跳转10帧
                    # 跳转到上一帧
                    if previous_frame:
                        previous_frame = False
                        frame -= 10  # 每次返回10帧

                    # 加载新帧数据
                    self._load_frame_data(frame)

                    # 更新几何体的显示
                    self.vis.update_geometry(self.pcd)
                    self.vis.update_geometry(self.coord_frame_1)
                    self.vis.update_geometry(self.coord_frame_2)
                    self.vis.update_geometry(self.coord_frame_3)
                    for joint in self.left_joints + self.right_joints:
                        self.vis.update_geometry(joint)
                    for cylinder in self.left_line_set + self.right_line_set:
                        self.vis.update_geometry(cylinder)

                    # 渲染场景
                    self.vis.poll_events()
                    self.vis.update_renderer()
                listener.join()
        finally:
            # 输出累积校正信息(如果有)
            print("cumulative_correction ", self.cumulative_correction)

加载并可视化当前帧数据:渲染点云数据和其他几何体(坐标系、关节、连杆等)

键盘监听:根据用户输入跳转到下一帧或上一帧

更新渲染:每次跳转后重新加载当前帧数据,并更新渲染场景

相关推荐
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【69】Token 用量统计
java·人工智能·spring
十三画者2 小时前
【AI学习笔记】:DeepSeek 大模型本地部署与调用实战指南
人工智能
丁常彦-自媒体-常言道2 小时前
从首发4nm智驾芯片到兜底城市领航安全,比亚迪开启AI新征程
人工智能
Unbelievabletobe2 小时前
解决了股票api接口盘后数据更新慢的问题
大数据·开发语言·python
小杨在厦门3 小时前
从AI验布到智能质检:纺织企业智能化升级的三个台阶
人工智能·服装·服装厂·服装机械·铺布机
达之云*驭影3 小时前
解锁流量密码:详解抖音AI智能推荐封面功能
人工智能
声讯电子3 小时前
全功能DSP语音模组AU‑60,机器人远场拾音利器
机器人·回音消除·全双工通话·远场拾音
lpd_lt3 小时前
AI Coding的常用Prompt技巧
python·ai·ai编程
小江的记录本3 小时前
【JVM虚拟机】堆内存分代模型:年轻代(Eden+Survivor)、老年代、元空间Metaspace(附《思维导图》+《面试高频考点清单》)
java·前端·jvm·后端·python·spring·面试