当前位置: 首页 > article >正文

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

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

主要流程包括:

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

目录

1 库引用

2 主程序入口

3 处理 clip_marks.json 文件

3 初始化 ReplayDataVisualizer

4 键盘交互

5 回放帧可视化


1 库引用

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 主程序入口

# 主程序入口
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 文件

    # 检查是否已有 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

    # 数据目录
    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 键盘交互

# 键盘按下事件的回调函数
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 回放帧可视化

# 定义自定义可视化类,继承 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)

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

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

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


http://www.kler.cn/a/471552.html

相关文章:

  • 鸿蒙开发(29)弹性布局 (Flex)
  • 《HeadFirst设计模式》笔记(上)
  • 06-RabbitMQ基础
  • Kubernetes Ingress:流量管理的利器
  • ERP,Enterprise Resource Planning(企业资源计划)
  • 实习总结(项目篇)
  • 东土科技参股广汽集团飞行汽车初创公司,为低空经济构建新型产业生态
  • 面向对象的思维hong
  • Ubuntu22.04 离线安装:gcc、make、dkms、build-essential
  • 模式识别-Ch3-贝叶斯估计
  • QT给端口扫描工程增加线程2
  • 【JavaWeb】2. 通用基础代码
  • ubuntu为Docker配置代理
  • 永磁同步电机模型预测控制——模型预测研究现状
  • ChatGPT在数据分析与处理中的使用详解
  • 在 a-tree 中报错 parent 期望是对象,但获得是字符串
  • PyTorch 框架实现线性回归:从数据预处理到模型训练全流程
  • vue 导出excel接口请求和axios返回值blob类型处理
  • Go语言的数据库交互
  • 最新版Chrome浏览器加载ActiveX控件之SolidWorks 3D控件
  • EasyExcel.read读取 Excel 文件
  • 第 24 章 网络请求与远程资源
  • WELL健康建筑认证在2025年相关消息
  • 网络安全主动防御技术与应用
  • 第14章 MySQL事务日志
  • 【物联网原理与运用】知识点总结(下)