适用场景:把原 szuxrn 项目的 RGB-D 采集、OpenPose 姿态估计、PCL 点云处理流程迁移到 Jetson Orin Nano + Ubuntu 22.04 + Orbbec Femto Mega。本阶段复现目标很明确:做到批量粗配准 + ICP + 点云合并。后续网格化建模、纹理修复、自动质量评估等内容,以思路说明和少量代码展示为主,不作为当前阶段的强制复现目标。

1. 复现边界 🎯

本次迁移复现到以下结果即可认为阶段完成:

Femto Mega RGB-D 采集
  -> D2C 对齐彩色图、深度图、XYZRGB 点云 CSV
  -> OpenPose BODY_25 姿态 JSON
  -> JSON 转关键点 CSV
  -> PCL CSV 转 PCD
  -> PCL 背景差分提取人体点云
  -> PCL 直通滤波
  -> PCD 转 PLY
  -> Open3D 批量初始旋转 + ICP + 合并
  -> body_merged_clean.ply / body_merged_clean.pcd

当前阶段不强制完成:

Poisson 网格重建
纹理贴图
人体模型拓扑优化
自动姿态校正
自动闭环配准

不过文末会给出后续建模思路和可参考代码。

2. 硬件与软件环境 🧰

2.1 硬件

项目 配置
边缘计算设备 Jetson Orin Nano
系统 Ubuntu 22.04 / JetPack 对应版本
RGB-D 相机 Orbbec Femto Mega
姿态估计 OpenPose BODY_25
点云处理 PCL / pcl_tools / Open3D
可视化检查 CloudCompare / MeshLab / Open3D

2.2 推荐目录

在 Jetson 上建议放在:

~/ws/3D_Body_Rebuild/JO_Migrate

后续命令默认从该目录执行:

cd ~/ws/3D_Body_Rebuild/JO_Migrate

3. 代码仓库结构 📁

核心目录如下:

JO_Migrate/
├── capture/
│   └── capture_femto.py              # Femto Mega D2C 对齐采集脚本
├── pose/
│   └── openpose_json_to_csv.py        # OpenPose BODY_25 JSON 转 CSV
├── pcl/
│   ├── 01_csv2pcd.cpp                 # XYZRGB CSV 转 PCD
│   ├── 02_change_detection.cpp        # 背景差分提取人体
│   └── 03_filtering.cpp               # 直通滤波
├── scripts/
│   ├── setup_jetson.sh                # Jetson 依赖安装
│   ├── build_pcl.sh                   # 编译 PCL 程序
│   ├── run_pipeline.sh                # PCL 自动处理 + PCD 转 PLY
│   └── open3d_register_merge.py       # Open3D 批量粗配准 + ICP + 合并
├── config/
│   └── pipeline_config.json
├── requirements.txt
├── requirements-open3d.txt
└── README.md

4. 安装基础依赖 ⚙️

4.1 一键安装基础依赖

进入项目目录:

cd ~/ws/3D_Body_Rebuild/JO_Migrate

执行:

bash scripts/setup_jetson.sh

该脚本会安装:

build-essential
cmake
git
pkg-config
python3-venv
python3-pip
python3-opencv
libpcl-dev
pcl-tools
cloudcompare

并创建 Python 虚拟环境:

source .venv/bin/activate

4.2 PCL 与 pcl_tools

如果只想手动安装 PCL 和命令行工具:

sudo apt update
sudo apt install -y libpcl-dev pcl-tools

验证:

pcl_pcd2ply --help
pcl_viewer --help

常用 pcl_tools:

工具 用途
pcl_pcd2ply PCD 转 PLY,方便 MeshLab/Open3D 读取
pcl_viewer 快速查看 PCD
pcl_transform_point_cloud 命令行平移/旋转点云
pcl_icp 命令行 ICP 配准
pcl_voxel_grid 体素降采样
pcl_outlier_removal 离群点去除

5. Orbbec Femto Mega 与 pyorbbecsdk2 📷

5.1 安装 Python SDK

项目基础依赖在 requirements.txt 中:

numpy
opencv-python
pyorbbecsdk2

安装:

source .venv/bin/activate
python -m pip install -r requirements.txt

5.2 udev 规则

需要按 Orbbec SDK v2 的 Linux 说明安装 udev 规则。否则可能出现相机权限问题。

临时排查可以用:

sudo python capture/capture_femto.py --sample-id 1

但长期建议正确安装 udev 规则,不要依赖 sudo 采集。

5.3 采集层最重要的一点:D2C 对齐

Femto Mega 的彩色相机和深度相机不是同一个光心,不能默认认为:

color[u, v] 与 depth[u, v] 天然对应

因此采集脚本默认使用:

AlignFilter(align_to_stream=OBStreamType.COLOR_STREAM)

也就是 Depth to Color,把深度图对齐到彩色图坐标系。

脚本还会调用:

pipeline.get_camera_param()

保存当前相机的:

彩色内参
深度内参
畸变参数
Depth -> Color 外参

输出位置:

data/camera_params/camera_param_sampleN.json
data/camera_params/camera_param_latest.json

6. OpenPose 安装与编译指导 🧍

本项目严格复现原始流程时使用 OpenPose BODY_25。Jetson 上编译 OpenPose 的坑比较多,尤其是 Caffe、CUDA、glog、OpenCV 这些依赖容易互相打架。

6.1 OpenPose 推荐安装位置

建议放在:

~/ws/openpose

最终需要能运行:

~/ws/openpose/build/examples/openpose/openpose.bin

6.2 常见依赖

大致依赖包括:

sudo apt update
sudo apt install -y 
  build-essential cmake git pkg-config 
  libprotobuf-dev protobuf-compiler 
  libgoogle-glog-dev libgflags-dev 
  libhdf5-dev libatlas-base-dev 
  libopencv-dev

CUDA、cuDNN、OpenCV 版本需要与你的 JetPack 环境匹配。

6.3 glog 冲突处理

如果运行 OpenPose 时出现类似错误:

ERROR: something wrong with flag 'logtostderr'
One possibility: glog is being linked both statically and dynamically

说明系统环境中存在多个 glog,被 OpenPose、Caffe 或 ROS 环境混合加载了。

推荐做法:

  1. 给 OpenPose 单独编译一个本地 shared glog。
  1. 让 OpenPose 和 Caffe 都链接该 glog。
  1. 运行 OpenPose 时用干净环境隔离 ROS 的 LD_LIBRARY_PATH。

验证链接结果:

cd ~/ws/openpose
ldd ./build/examples/openpose/openpose.bin | grep -E 'glog|caffe|openpose'

理想输出应类似:

libglog.so.0 => /home/jetson/ws/openpose/3rdparty/local/glog-0.4.0/lib/libglog.so.0
libcaffe.so.1.0.0 => /home/jetson/ws/openpose/build/caffe/lib/libcaffe.so.1.0.0
libopenpose.so.1.7.0 => /home/jetson/ws/openpose/build/src/openpose/libopenpose.so.1.7.0

如果你的系统同时装了 ROS2、机器人导航包或其他视觉库,运行 OpenPose 时建议使用:

env -i HOME="$HOME" USER="$USER" 
PATH=/usr/local/cuda-12.6/bin:/usr/local/bin:/usr/bin:/bin 
LD_LIBRARY_PATH=/home/jetson/ws/openpose/3rdparty/local/glog-0.4.0/lib:/home/jetson/ws/openpose/build/src/openpose:/home/jetson/ws/openpose/build/caffe/lib:/usr/local/cuda-12.6/lib64:/usr/local/lib:/usr/lib/aarch64-linux-gnu 
./build/examples/openpose/openpose.bin --help

6.4 OpenPose 模型文件

BODY_25 模型目录应存在:

models/pose/body_25/

如果使用 --model_pose BODY_25,缺少模型会报:

Caffe trained model file not found

这时需要下载或复制对应 .caffemodel 文件。

7. 数据采集流程 ✨

7.1 默认保存路径

如果不指定 --data-root:

python capture/capture_femto.py --sample-id 1

数据会保存到:

data/

如果希望保存到单独实验目录:

python capture/capture_femto.py 
  --sample-id 1 
  --align-mode sw 
  --data-root /home/jetson/datasets/body_scan_001

7.2 采集空背景

空背景必须满足:

相机位置不变
背景环境不变
画面中没有人体
地面、墙面、桌椅等尽量保持静止

采集:

source .venv/bin/activate
python capture/capture_femto.py --sample-id 1 --align-mode sw

输出:

data/color/col1.png
data/depth/img/dep1.png
data/depth/csv/dep1.csv
data/pointcloud/xyzrgb/rgbpoi1.csv
data/camera_params/camera_param_sample1.json

7.3 采集人体 12 个角度

原项目约定:

rgbpoi1       空背景
rgbpoi2-13    人体 12 个角度

采集建议:

人体站在相机前约 2 米
脚底位置尽量固定
每次转动约 30 度
相机不要移动
光照不要明显变化
衣物颜色尽量和背景有区分

命令:

python capture/capture_femto.py --sample-id 2 --align-mode sw
python capture/capture_femto.py --sample-id 3 --align-mode sw
# ...
python capture/capture_femto.py --sample-id 13 --align-mode sw

如果硬件 D2C 可用,也可以测试:

python capture/capture_femto.py --sample-id 1 --align-mode hw

脚本结束时重点看:

alignment=software_d2c 或 hardware_d2c
color=宽x高, depth=宽x高
intrinsics fx/fy/cx/cy=(...)

理想情况是 color 与 depth 分辨率一致。若不一致,需要回到 Orbbec Viewer 或 SDK profile 设置排查。

8. OpenPose 姿态估计 🦾

对人体角度图片运行 OpenPose:

cd ~/ws/openpose

env -i HOME="$HOME" USER="$USER" 
PATH=/usr/local/cuda-12.6/bin:/usr/local/bin:/usr/bin:/bin 
LD_LIBRARY_PATH=/home/jetson/ws/openpose/3rdparty/local/glog-0.4.0/lib:/home/jetson/ws/openpose/build/src/openpose:/home/jetson/ws/openpose/build/caffe/lib:/usr/local/cuda-12.6/lib64:/usr/local/lib:/usr/lib/aarch64-linux-gnu 
./build/examples/openpose/openpose.bin 
  --image_dir ~/ws/3D_Body_Rebuild/JO_Migrate/data/color 
  --write_json ~/ws/3D_Body_Rebuild/JO_Migrate/data/json 
  --model_pose BODY_25 
  --net_resolution 256x192 
  --display 0 
  --render_pose 0 
  --face false 
  --hand false

Jetson 内存紧张时可进一步降低:

--net_resolution 192x144

如果进程被系统杀掉,常见表现是:

Killed

可尝试:

关闭桌面无关程序
降低 net_resolution
不要 write_video
只处理 image_dir,不处理长视频
开启 swap

9. OpenPose JSON 转 CSV 📝

回到迁移项目:

cd ~/ws/3D_Body_Rebuild/JO_Migrate
source .venv/bin/activate

转换:

python pose/openpose_json_to_csv.py 
  --json-dir data/json 
  --out-dir data/keypoints_csv 
  --start 2 
  --end 13

输出:

data/keypoints_csv/col2_keypoints.csv
...
data/keypoints_csv/col13_keypoints.csv

10. 编译 PCL 程序 🔧

项目内的 PCL 程序包括:

pcl/01_csv2pcd.cpp
pcl/02_change_detection.cpp
pcl/03_filtering.cpp

编译:

bash scripts/build_pcl.sh

等价于:

cmake -S pcl -B build/pcl -DCMAKE_BUILD_TYPE=Release
cmake --build build/pcl -j"$(nproc)"

11. PCL 自动处理 + PCD 转 PLY 🌈

运行:

bash scripts/run_pipeline.sh

内部流程:

01_csv2pcd:
  data/pointcloud/xyzrgb/rgbpoi*.csv
  -> data/pointcloud_pcd/rgbpoi*.pcd

02_change_detection:
  rgbpoi1 空背景 vs rgbpoi2-13 人体
  -> data/pointcloud_result/rgbpoi_body*.pcd

03_filtering:
  直通滤波
  -> data/pointcloud_result/rgbpoi_body_filter*.pcd

pcl_pcd2ply:
  PCD -> PLY
  -> data/pointcloud_result_ply/rgbpoi_body_filter*.ply

重点输出:

data/pointcloud_result/rgbpoi_body_filter2.pcd
...
data/pointcloud_result/rgbpoi_body_filter13.pcd

data/pointcloud_result_ply/rgbpoi_body_filter2.ply
...
data/pointcloud_result_ply/rgbpoi_body_filter13.ply

11.1 滤波参数调整

scripts/run_pipeline.sh 中默认滤波:

./build/pcl/03_filtering data/pointcloud_result data/pointcloud_result 2 13 -800 800 -1200 1200 500 5000

参数含义:

x_min x_max y_min y_max z_min z_max

如果人体左右被裁掉:

-1200 1200 -1200 1200 500 5000

如果人体远近被裁掉:

-800 800 -1200 1200 300 6000

如果点云质量已经不错,不要过度调参。此时最重要的是进入 Open3D 配准融合阶段。

12. Open3D 批量粗配准 + ICP + 合并 ✅

12.1 安装 Open3D

优先尝试:

python -m pip install -r requirements-open3d.txt

如果 Jetson 上没有合适的 aarch64 wheel,可以选择:

方案 A:在性能更好的 PC 上运行 Open3D 配准
方案 B:在 Jetson 上从源码编译 Open3D
方案 C:用 CloudCompare/MeshLab 手动完成配准

12.2 一键批量配准

运行:

python scripts/open3d_register_merge.py 
  --input-dir data/pointcloud_result_ply 
  --start 2 
  --end 13 
  --angle-step 30 
  --direction -1 
  --axis y 
  --voxel 5 
  --icp-threshold 40 
  --save-intermediate

输出:

data/open3d_model/registered_views/
data/open3d_model/body_merged_raw.ply
data/open3d_model/body_merged_clean.ply
data/open3d_model/body_merged_clean.pcd
data/open3d_model/registration_transforms.json

其中:

文件 说明
registered_views/*.ply 每个角度配准后的中间结果
body_merged_raw.ply 未最终清理的合并点云
body_merged_clean.ply 推荐检查和后续建模的清理点云
body_merged_clean.pcd PCL 兼容版本
registration_transforms.json 每个角度的 4×4 变换矩阵、ICP fitness、RMSE

12.3 参数怎么调

如果旋转方向反了,把:

--direction -1

改为:

--direction 1

如果 ICP 把局部点云吸歪:

--icp-threshold 20

如果 ICP 几乎不动:

--icp-threshold 60

如果 Open3D 报:

voxel_size is too small

通常是点云中存在极端异常坐标。脚本已加入预清理,可尝试:

python scripts/open3d_register_merge.py 
  --input-dir data/pointcloud_result_ply 
  --start 2 
  --end 13 
  --angle-step 30 
  --direction -1 
  --axis y 
  --voxel 5 
  --icp-threshold 40 
  --max-abs-coordinate 8000 
  --save-intermediate

运行时会打印:

[input 2] points=..., min=(...), max=(...)

正常人体点云坐标通常在几千毫米范围内。如果出现几十万、几百万的坐标,说明该文件混入了异常点。

13. 当前阶段验收标准 🏁

只要满足以下条件,本阶段复现即可认为完成:

  1. data/pointcloud_result_ply/rgbpoi_body_filter2-13.ply 能正常打开。
  1. Open3D 脚本能生成:
data/open3d_model/body_merged_clean.ply
data/open3d_model/body_merged_clean.pcd
  1. 合并点云中人体主体连续,无明显大尺度分裂。
  1. 头、肩、躯干、腿部没有严重重影。
  1. registration_transforms.json 中大多数视角有可接受的 ICP 结果。

这里的目标是拿到一个可检查、可继续建模的合并点云,而不是一次性得到完美人体网格。

14. 后续建模思路 🧭

14.1 MeshLab 路线

打开:

data/open3d_model/body_merged_clean.ply

建议步骤:

1. 手动删除明显漂浮噪点
2. Compute normals for point sets
3. Screened Poisson Surface Reconstruction
4. 删除 Poisson 外壳和小碎片
5. Laplacian Smooth 轻微平滑
6. Quadric Edge Collapse Decimation 简化网格
7. 导出 body_mesh_final.ply / body_mesh_final.obj

Poisson 初始参数:

Reconstruction Depth: 8
Samples Per Node: 1.5 - 3

如果模型太粗糙,尝试:

Depth = 9

如果内存压力大:

Depth = 7

14.2 Open3D Poisson 代码片段

后续如果希望继续自动化,可以参考:

import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("data/open3d_model/body_merged_clean.ply")

pcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(
        radius=30.0,
        max_nn=30,
    )
)
pcd.orient_normals_consistent_tangent_plane(30)

mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
    pcd,
    depth=8,
)

densities = np.asarray(densities)
threshold = np.quantile(densities, 0.02)
mesh.remove_vertices_by_mask(densities < threshold)
mesh.compute_vertex_normals()

o3d.io.write_triangle_mesh("data/open3d_model/body_mesh_poisson.ply", mesh)

这一步目前作为探索项,不作为阶段验收项。

15. 常见问题排查表 🛠️

问题 可能原因 处理
彩色点云颜色明显偏移 RGB-D 未正确 D2C 对齐 回到采集层,检查 --align-mode sw/hw,确认 color/depth 尺寸一致
OpenPose 报 glog flag 冲突 系统 glog、ROS 环境、OpenPose/Caffe 链接混乱 使用本地 shared glog,运行时用 env -i 隔离环境
OpenPose 被 Killed Jetson 内存不足 降低 --net_resolution,关闭 write_video,处理图片而不是视频
缺少 .caffemodel OpenPose 模型未下载 补齐 models/pose/body_25
人体只剩半边 PCL 滤波范围过窄或背景差分过强 放宽 03_filtering 的 x/y/z 范围,检查空背景
Open3D voxel_size is too small PLY 中有极端坐标点 使用 --max-abs-coordinate 8000 或检查 PLY/PCD
ICP 越配越散 初始旋转方向错或阈值过大 改 --direction,降低 --icp-threshold
合并后有双层人体 粗配准不足或人体采集时移动 剔除差视角,或用 --target previous 尝试相邻配准

16. 小结 🌟

本次迁移的关键不是把原项目所有代码原封不动搬过来,而是保留它的数据链路思想:

RGB-D 采集 -> 姿态估计 -> 点云提取 -> 多视角融合

同时替换掉不适合 Jetson + Femto Mega 的部分:

Astra/OpenNI2 采集层
  -> Orbbec SDK v2 + D2C 对齐采集

手工零散处理
  -> PCL 脚本化处理 + Open3D 批量配准

当前阶段完成到 body_merged_clean.ply 就已经具备了继续建模、展示和实验对比的基础。后续如果继续推进,可以围绕网格重建、纹理优化、配准质量评估和自动闭环来迭代。稳稳落地,后面就有得玩了 😄

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注