适用场景:把原
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 环境混合加载了。
推荐做法:
- 给 OpenPose 单独编译一个本地 shared glog。
- 让 OpenPose 和 Caffe 都链接该 glog。
- 运行 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. 当前阶段验收标准 🏁
只要满足以下条件,本阶段复现即可认为完成:
data/pointcloud_result_ply/rgbpoi_body_filter2-13.ply能正常打开。
- Open3D 脚本能生成:
data/open3d_model/body_merged_clean.ply
data/open3d_model/body_merged_clean.pcd
- 合并点云中人体主体连续,无明显大尺度分裂。
- 头、肩、躯干、腿部没有严重重影。
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 就已经具备了继续建模、展示和实验对比的基础。后续如果继续推进,可以围绕网格重建、纹理优化、配准质量评估和自动闭环来迭代。稳稳落地,后面就有得玩了 😄