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)

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

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

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

相关推荐
周末程序猿2 分钟前
谈谈上下文工程(Context Engineering)
人工智能
一水鉴天17 分钟前
整体设计 逻辑系统程序 之29 拼语言+ CNN 框架核心定位、三阶段程序与三种交换模式配套的方案讨论 之2
人工智能·神经网络·cnn
海森大数据18 分钟前
AI破解数学界遗忘谜题:GPT-5重新发现尘封二十年的埃尔德什问题解法
人工智能·gpt
望获linux1 小时前
【实时Linux实战系列】Linux 内核的实时组调度(Real-Time Group Scheduling)
java·linux·服务器·前端·数据库·人工智能·深度学习
Dev7z1 小时前
河南特色农产品识别系统:让AI守护“中原味道”
人工智能
新子y1 小时前
【小白笔记】PyTorch 和 Python 基础的这些问题
pytorch·笔记·python
万俟淋曦1 小时前
【论文速递】2025年第28周(Jul-06-12)(Robotics/Embodied AI/LLM)
人工智能·ai·机器人·大模型·论文·robotics·具身智能
我是李武涯1 小时前
PyTorch DataLoader 高级用法
人工智能·pytorch·python
每月一号准时摆烂1 小时前
PS基本教学(三)——像素与分辨率的关系以及图片的格式
人工智能·计算机视觉