1. 目的
本文说明如何基于 BOP 风格的数据组织方式,为当前仓库中的 PVN3D 准备可训练的自定义数据集。
重点回答四个问题:
PVN3D训练到底依赖哪些文件- 如果数据已经是 BOP 格式,需要补齐什么
- 如果只是沿用现有 LINEMOD 类别,如何最小代价接入
- 如果是真正的自定义新类别,代码和数据还需要改哪些地方
本文基于当前仓库代码,而不是通用的 BOP 理论描述。
2. 先给结论
如果你只是想把"BOP 格式的数据"拿来训练当前仓库里的 PVN3D,需要先明确你属于哪一种情况。
情况 A:对象类别仍然是当前仓库已经支持的 LINEMOD 类别
例如:
apecandrillerduck
这时你主要需要做的是:
- 准备符合 BOP 结构的训练数据
- 转换到
Linemod_preprocessed - 确保
models/、train.txt、gt.yml、rgb/depth/mask可用 - 可选地准备
renders/
这种情况最简单,因为:
- 类别映射已经存在
lm_obj_kps已经存在- 关键点文件已经存在
- 训练代码基本不用改
情况 B:你要训练真正的新物体类别
例如:
- 自己采集的工业零件
- 当前仓库里没有的对象 ID
- 自定义 BOP 数据集而不是 LINEMOD 对象
这时除了数据转换外,还必须补齐:
- 类别映射
- 模型文件
- 关键点文件
models_info.yml- 训练脚本和配置中的对象列表
这不是单纯"转一下 BOP 数据"就能完成的事情,而是要把新类别接入当前 LINEMOD 风格管线。
3. 当前仓库训练时真正依赖什么
当前 LINEMOD 训练入口是:
训练数据集是:
训练集初始化时,LM_Dataset('train', cls_type=...) 直接依赖这些文件:
text
Linemod_preprocessed/
├── data/
│ └── {obj_id:02d}/
│ ├── train.txt
│ ├── gt.yml
│ ├── rgb/*.png
│ ├── depth/*.png
│ └── mask/*.png
├── models/
│ └── obj_{obj_id:02d}.ply
可选增强数据:
text
Linemod_preprocessed/
├── renders/{cls}/*.pkl
├── renders/{cls}/file_list.txt
├── fuse/{cls}/*.pkl
└── fuse/{cls}/file_list.txt
另外,训练和评估还依赖:
text
pvn3d/datasets/linemod/lm_obj_kps/{cls}/
├── corners.txt
├── farthest.txt
├── farthest4.txt
├── farthest12.txt
├── farthest16.txt
└── farthest20.txt
以及:
text
pvn3d/datasets/linemod/dataset_config/models_info.yml
4. 从代码角度看,训练最少需要什么
4.1 每帧训练样本需要的信息
在 linemod_dataset.py 中,每个训练样本最终需要得到:
- RGB 图像
- 深度图
- 单物体 mask
- 相机内参
K - 位姿
RT
这些会被转换成:
- 点云
- 每点的 RGB 特征
- 中心偏移监督
- 关键点偏移监督
所以无论你的原始数据格式是什么,只要想训练 PVN3D,最终必须为每个样本提供:
- 彩色图
- 深度图
- 当前物体的二值 mask
- 当前物体的 6D pose
- 相机内参
4.2 每个类别还需要的信息
训练不是只靠逐帧标注就够了。每个类别还必须有:
- 物体 3D 模型
.ply - 物体关键点文件
farthest*.txt - 包围盒角点文件
corners.txt - 类别到
obj_id的映射
对应代码读取位置:
- 模型点: basic_utils.py
- 关键点: basic_utils.py
- 中心点: basic_utils.py
- 类别映射: common.py
5. 如果你的数据已经是 BOP 格式,需要具备哪些内容
当前仓库已经有训练转换脚本:
从这个脚本的输入可以看出,BOP 根目录至少要具备:
text
<bop_root>/
├── lm_models/
│ └── models/
│ ├── obj_000001.ply
│ ├── obj_000002.ply
│ └── ...
├── lm_train/
│ └── train/
│ └── 000001/
│ ├── rgb/
│ ├── depth/
│ ├── mask/
│ └── scene_gt.json
└── lm_train_pbr/
└── train_pbr/
└── 000000/
├── rgb/
├── depth/
├── mask_visib/
├── scene_gt.json
└── scene_camera.json
也支持 zip 包形式:
lm_train.ziplm_train_pbr.zip
5.1 真实训练数据最少要求
真实训练数据转换时,脚本实际读取:
scene_gt.jsonrgb/{frame}.png或.jpgdepth/{frame}.pngmask/{frame}_{ann_idx}.png
也就是说,真实训练样本最少要有:
- RGB
- depth
- 每个实例的 mask
- 6D pose 标注
5.2 PBR 合成训练数据最少要求
PBR 训练数据转换时,脚本实际读取:
scene_gt.jsonscene_camera.jsonrgb/{frame}.jpg或.pngdepth/{frame}.pngmask_visib/{frame}_{ann_idx}.png,如果没有则退回mask/
也就是说,PBR 样本除了 pose,还必须有相机内参和深度缩放信息。
5.3 模型文件要求
模型目录必须存在:
text
lm_models/models/obj_{obj_id:06d}.ply
转换后会拷贝到:
text
Linemod_preprocessed/models/obj_{obj_id:02d}.ply
6. BOP 转换后,PVN3D 训练目录应当长什么样
如果你要训练单个对象,例如 ape,最终至少应得到:
text
pvn3d/datasets/linemod/Linemod_preprocessed/
├── data/
│ └── 01/
│ ├── train.txt
│ ├── test.txt
│ ├── gt.yml
│ ├── rgb/
│ ├── depth/
│ └── mask/
├── models/
│ └── obj_01.ply
└── renders/
└── ape/
├── *.pkl
└── file_list.txt
其中:
train.txt是训练硬依赖test.txt用于测试和验证gt.yml是当前仓库使用的位姿标注格式renders/ape是可选但推荐的合成训练数据
如果你没有 renders/,训练仍能启动,但只能用真实图像。
7. 当前仓库现成脚本能处理到什么程度
7.1 测试集转换脚本
作用:
- 转
lm_test_all/test - 生成
test.txt - 生成
gt.yml - 拷贝模型
.ply
这个脚本只够:
- 测试
- demo
- eval
不够直接训练,因为它不生成:
train.txtrenders/*.pkl
7.2 训练集转换脚本
作用:
- 将 BOP 真实训练数据转成
data/%02d/* - 生成
train.txt - 生成
gt.yml - 将 PBR 数据转成
renders/{cls}/*.pkl - 拷贝模型
.ply
也就是说,当前仓库已经具备:
- BOP 训练数据接入能力
但它的前提是:
- 你的对象类别仍然是当前脚本支持的对象 ID
8. 如果只是沿用现有 LINEMOD 类别,应如何准备数据
这是最稳妥的路径。
8.1 数据侧需要准备
你需要准备一套符合 BOP 结构的数据根目录,例如:
text
/workspace/bop/
├── lm_models/models/
├── lm_train/train/
└── lm_train_pbr/train_pbr/
说明:
- 你当前说明 BOP 数据根目录是
/workspace/bop - 当前仓库的转换脚本支持通过
--bop-root显式指定该路径
如果你的数据就在 /workspace/bop,只需要显式传参即可。
8.2 执行训练转换
例如把数据转换到当前仓库默认训练目录:
bash
python pvn3d/datasets/convert_bop_lm_train_to_pvn3d.py \
--bop-root /workspace/bop \
--output-root /home/xx/project/workflow/self/PVN3D/pvn3d/datasets/linemod/Linemod_preprocessed \
--scene-ids 1 \
--overwrite
如果只转真实训练数据:
bash
python pvn3d/datasets/convert_bop_lm_train_to_pvn3d.py \
--bop-root /workspace/bop \
--output-root /home/xx/project/workflow/self/PVN3D/pvn3d/datasets/linemod/Linemod_preprocessed \
--scene-ids 1 \
--real-only \
--overwrite
如果只转 PBR 数据:
bash
python pvn3d/datasets/convert_bop_lm_train_to_pvn3d.py \
--bop-root /workspace/bop \
--output-root /home/xx/project/workflow/self/PVN3D/pvn3d/datasets/linemod/Linemod_preprocessed \
--scene-ids 1 \
--pbr-only \
--overwrite
8.3 做目录校验
可以用仓库里的检查脚本验证布局:
bash
python pvn3d/datasets/check_linemod_pvn3d_layout.py \
--data-root /home/xx/project/workflow/self/PVN3D/pvn3d/datasets/linemod/Linemod_preprocessed \
--obj-ids 1
注意:
- 这个检查脚本主要检查
test.txt - 对训练来说,你还应额外确认
train.txt存在且非空
8.4 启动训练
bash
cd /home/xx/project/workflow/self/PVN3D/pvn3d
conda activate pvn3d
python -m train.train_linemod_pvn3d --cls ape
如果显存较小,则结合前面已经支持的参数:
bash
PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:64 python -m train.train_linemod_pvn3d \
--cls ape \
--mini_batch_size 1 \
--val_mini_batch_size 1 \
--n_sample_points 4096 \
--num_workers 2
9. 自定义自己的测试场景数据集,如何采集并制作成 LINEMOD / PVN3D 可用格式
这一节讨论的是:
- 你已经有自己的真实场景
- 想采集一批 RGB-D 测试样本
- 希望最终接到当前仓库的
demo/eval/test流程
这里需要先分清两个层次:
- 场景数据本身如何采集
- 采集后如何整理成当前仓库可读的
Linemod_preprocessed风格
9.1 自采测试场景最少需要采到什么
如果目标只是"让 PVN3D 在自己的真实场景里测试",每个场景帧至少需要以下信息:
- RGB 图像
- 深度图
- 当前目标物体的 mask
- 相机内参
- 目标物体的真实 6D pose
其中:
- RGB、深度图是输入
- mask 和 pose 是评估时的真值
- 内参用于把深度还原成点云以及做投影
如果你只想做"无标注 demo",则可以临时不准备:
- mask
- pose
但如果你想做真正的定量测试,就必须有这两项。
9.2 采集流程建议
推荐的采集流程是:
- 固定相机,并完成相机内参标定
- 准备目标物体的高质量 3D 模型
.ply - 在不同距离、角度、光照、遮挡条件下采集 RGB-D 帧
- 为每帧标注目标的 6D pose
- 由投影或人工校正生成物体 mask
这里最关键的不是"拍到图",而是:
- 模型坐标系
- 相机坐标系
- pose 标注
三者必须严格一致。
如果这三者不一致,后续无论是评估还是可视化都会错。
9.3 推荐的原始采集产物
在最开始的原始数据层,不一定非要直接做成 LINEMOD 格式。更合理的是先保留一份"采集原始版":
text
my_scene_raw/
├── rgb/
│ ├── 000001.png
│ ├── 000002.png
│ └── ...
├── depth/
│ ├── 000001.png
│ ├── 000002.png
│ └── ...
├── pose/
│ ├── 000001.json
│ ├── 000002.json
│ └── ...
├── mask/
│ ├── 000001.png
│ ├── 000002.png
│ └── ...
└── camera.json
原因是:
- 原始采集格式更容易维护
- 以后可以再导出成 BOP、LINEMOD、或别的格式
- 不建议一开始就把原始数据直接耦合到某个训练框架的目录结构
9.4 如何把自采测试场景整理成 BOP 风格
如果你想复用当前仓库已有的转换脚本,最省事的做法不是手写 LINEMOD 目录,而是先把自采数据整理成 BOP 风格。
对单对象测试集,建议整理为:
text
/workspace/bop/my_dataset_test/test/000001/
├── rgb/
│ ├── 000000.png
│ ├── 000001.png
│ └── ...
├── depth/
│ ├── 000000.png
│ ├── 000001.png
│ └── ...
├── mask/
│ ├── 000000_000000.png
│ ├── 000001_000000.png
│ └── ...
├── scene_gt.json
└── scene_camera.json
其中:
- 场景目录
000001可以理解为某个对象或某个测试场景 scene_gt.json保存每帧每个实例的cam_R_m2c与cam_t_m2cscene_camera.json保存每帧相机参数,例如cam_K、depth_scalemask用 BOP 约定命名:frameid_annid.png
如果每帧只有一个目标实例,ann_idx 通常就是 000000。
9.5 自采测试场景整理成 LINEMOD / PVN3D 格式时需要哪些文件
如果你不经过 BOP 中间层,直接整理成当前仓库能读的测试目录,至少需要:
text
Linemod_preprocessed/data/{obj_id:02d}/
├── test.txt
├── gt.yml
├── rgb/
│ ├── 000001.png
│ ├── 000002.png
│ └── ...
├── depth/
│ ├── 000001.png
│ ├── 000002.png
│ └── ...
└── mask/
├── 000001.png
├── 000002.png
└── ...
此外还需要:
text
Linemod_preprocessed/models/obj_{obj_id:02d}.ply
9.6 test.txt 应如何制作
test.txt 的内容非常简单,每行一个帧号,不带扩展名,例如:
text
000001
000002
000003
要求:
- 必须和
rgb/、depth/、mask/文件名一致 - 必须和
gt.yml中的键一致
9.7 gt.yml 应如何制作
当前仓库的测试读取逻辑要求:
- 每个帧号是一个键
- 每个键对应一个列表
- 列表里至少有一个字典
每个字典至少包含:
cam_R_m2ccam_t_m2cobj_id
典型结构:
yaml
1:
- cam_R_m2c: [r11, r12, r13, r21, r22, r23, r31, r32, r33]
cam_t_m2c: [tx, ty, tz]
obj_id: 1
2:
- cam_R_m2c: [...]
cam_t_m2c: [...]
obj_id: 1
注意:
cam_R_m2c是长度为 9 的行优先展开数组cam_t_m2c在当前 LINEMOD 流程里通常按毫米保存- 训练/测试代码内部会在需要时转成米
9.8 自采场景中的 pose 如何得到
这是最核心也最难的一步。常见做法有三种:
- 人工交互式标注
- 基于 AprilTag / ArUco / 外部定位系统建立参考系后求解
- 用 Blender / 仿真自动生成
无论用哪种方法,最终必须得到:
- 物体模型坐标系到相机坐标系的变换
R, t
如果你是纯真实采集,推荐优先保证:
- 相机内参准确
- 模型尺度准确
cam_t_m2c与.ply单位一致
9.9 自采测试场景中的 mask 如何得到
常见做法:
- 根据真实 pose 和模型投影自动渲染出 mask
- 用标注工具手工勾出 mask
- 先用语义分割工具自动生成,再人工修正
建议:
- 如果 pose 足够准,优先用模型投影自动生成
- 如果有遮挡严重、透明反光、深度噪声大,再人工修正
9.10 深度图和相机内参需要注意什么
当前代码会把深度图结合相机内参变成点云,因此必须保证:
- 深度图数值真实可用
- 深度单位清晰
- 相机内参与采集设备一致
如果是 BOP 风格,通常通过:
scene_camera.json中的cam_Kdepth_scale
来说明。
如果你直接做 LINEMOD 格式,则要保证:
- 代码里使用的
K与你的采集相机一致
当前默认 LINEMOD 内参写在:
如果你的实际相机不是 LINEMOD 原始相机,就不应继续直接使用默认内参。
9.11 建议的制作路线
对于自采测试场景,推荐采用两步走:
- 先保存为你自己的"原始采集格式"
- 再写一个小转换脚本导出成 BOP 或 Linemod_preprocessed
原因:
- 后续你可能还要做重标注
- 还可能用于别的算法或基准
- 原始数据和训练框架格式解耦更稳
9.12 自采测试场景的最小检查清单
在你认为"测试集已经做完"之前,至少检查这些项:
rgb、depth、mask帧数一致test.txt中的帧号都存在gt.yml的每个键都对应真实文件obj_id与当前类别一致cam_R_m2c长度为 9cam_t_m2c长度为 3.ply模型存在且尺度正确- 相机内参与实际采集设备一致
10. 如果是真正的新类别,自定义数据集还需要什么
这是最容易低估的部分。
当前仓库的 LINEMOD 分支不是"任意 BOP 数据自动适配"的实现,而是对一组固定对象有很多硬编码假设。
10.1 必须修改类别映射
位置:
你至少要改这些内容:
lm_cls_lstlm_obj_dictlm_id2obj_dict
否则:
- 训练入口
--cls xxx找不到你的类别 - 数据集无法把类名转成
obj_id - 评估逻辑无法正确反查类名
10.2 必须准备关键点文件
位置:
pvn3d/datasets/linemod/lm_obj_kps/{cls}/
至少要有:
text
corners.txt
farthest.txt
如果保留当前多种评估/可视化逻辑,最好一并准备:
text
farthest4.txt
farthest12.txt
farthest16.txt
farthest20.txt
原因是训练和评估会调用:
其中:
get_kps()读取farthest*.txtget_ctr()通过corners.txt求中心
如果这些文件不存在,训练和评估会直接失败。
10.3 必须准备模型尺寸信息
位置:
当前代码会读取:
text
pvn3d/datasets/linemod/dataset_config/models_info.yml
如果你引入了新的对象 ID,需要把它的模型尺寸信息写进去。
10.4 必须准备模型文件
需要提供:
text
Linemod_preprocessed/models/obj_{obj_id:02d}.ply
这个 .ply 需要满足当前代码的读取方式:
- 能读出顶点坐标
- 单位与现有流程一致
当前 LINEMOD 流程默认把 .ply 当作毫米单位,并在内部转成米。
10.5 需要考虑训练脚本只按"单类训练"设计
当前 LINEMOD 训练是:
bash
python -m train.train_linemod_pvn3d --cls ape
即一次训练一个对象类别。
所以引入新类别后,你还要保证:
- 新类别名能被
--cls识别 - 数据目录按该类别的
obj_id放置 - 关键点目录按该类别名建立
10.6 新类别接入时,转换脚本也需要同步改
如果你希望继续使用当前仓库的 BOP 转换脚本,那么下面这几个常量也需要更新:
你至少要同步:
SUPPORTED_OBJ_IDSOBJ_ID_TO_NAME
否则会出现以下情况:
- 脚本直接跳过你的对象
renders/{cls}无法按你的类名生成.ply无法按新对象 ID 拷贝或命名
10.7 新类别接入时,训练与评估的隐含依赖也要检查
除了主训练脚本,还建议逐项检查这些依赖:
demo.py里是否使用了固定类别名pvn3d_eval_utils.py是否依赖lm_id2obj_dict- 任何使用
obj_id -> cls_name的地方是否都能映射到新类别 lm_sym_cls_ids是否需要更新
其中对称物体尤其要注意:
- 如果你的新对象是对称物体
- 评估时通常需要像
eggbox、glue一样特殊处理
否则 ADD 和 ADDS 的解释会不准确。
10.8 新类别接入时,建议新增哪些文档化产物
从工程维护角度,建议你为每个新类别额外保存:
- 模型来源说明
- 模型单位说明
- 坐标系定义说明
- 相机标定文件
- 关键点生成脚本或生成记录
- BOP 转换脚本的对象映射说明
这些内容不直接参与训练,但会显著影响后续复现实验和排查标注错误。
10.9 新类别接入的建议实施顺序
推荐顺序如下:
- 先给新对象分配稳定
obj_id - 准备
.ply并确认单位 - 生成
corners.txt和farthest*.txt - 修改
common.py的类别映射 - 修改
models_info.yml - 修改 BOP 转换脚本中的对象白名单和名称映射
- 准备真实训练集
train.txt + gt.yml + rgb/depth/mask - 可选补齐
renders/ - 先做
test/demo验证,再开始训练
这样做的原因是:
- 先验证几何与坐标系统是否正确
- 再投入长时间训练
如果一开始就直接训练,很多错误会被掩盖成"loss 不收敛"。
11. 新类别接入时建议改动的代码与数据清单
这一节不要求你现在真实修改代码,但需要明确有哪些位置迟早要动。
11.1 必改代码文件
通常至少包括:
按实际情况可能还包括:
- demo.py
- pvn3d_eval_utils.py
- 任何使用固定 LINEMOD 类名或对象 ID 的脚本
11.2 必补数据文件
通常至少包括:
Linemod_preprocessed/models/obj_{obj_id:02d}.plyLinemod_preprocessed/data/{obj_id:02d}/train.txtLinemod_preprocessed/data/{obj_id:02d}/test.txtLinemod_preprocessed/data/{obj_id:02d}/gt.ymlrgb/*.pngdepth/*.pngmask/*.pnglm_obj_kps/{cls}/corners.txtlm_obj_kps/{cls}/farthest*.txtdataset_config/models_info.yml
11.3 最容易遗漏的点
工程上最常见的遗漏项有:
- 新类别名已经加到
lm_obj_dict,但lm_id2obj_dict没同步 .ply已经放进models/,但lm_obj_kps/{cls}没创建gt.yml的obj_id写对了,但train.txt/test.txt帧号对不上- 相机内参沿用了默认 LINEMOD 的
K,但实际采集设备不同 cam_t_m2c和.ply的单位不一致- 对称物体没有更新对称类别列表
12. 自定义数据集最小必需清单
如果你的目标是"让一个新对象在当前 PVN3D LINEMOD 流程中能训练起来",至少需要以下内容。
10.1 数据文件
text
Linemod_preprocessed/data/{obj_id:02d}/
├── train.txt
├── gt.yml
├── rgb/*.png
├── depth/*.png
└── mask/*.png
10.2 模型文件
text
Linemod_preprocessed/models/obj_{obj_id:02d}.ply
10.3 关键点文件
text
pvn3d/datasets/linemod/lm_obj_kps/{cls}/
├── corners.txt
├── farthest.txt
├── farthest4.txt
├── farthest12.txt
├── farthest16.txt
└── farthest20.txt
10.4 配置和映射
text
pvn3d/common.py
pvn3d/datasets/linemod/dataset_config/models_info.yml
10.5 可选增强数据
text
Linemod_preprocessed/renders/{cls}/*.pkl
Linemod_preprocessed/renders/{cls}/file_list.txt
Linemod_preprocessed/fuse/{cls}/*.pkl
Linemod_preprocessed/fuse/{cls}/file_list.txt
其中真正的"硬依赖"是:
- 训练样本目录
- 模型
.ply - 关键点文件
- 类别映射
13. 推荐实施路线
路线 A:先复用现有 LINEMOD 对象
如果你的目标是先把训练链路打通,这是最推荐的路线。
步骤:
- 准备 BOP 格式的
lm_train/lm_train_pbr/lm_models - 用当前仓库脚本转换到
Linemod_preprocessed - 校验训练目录
- 启动单类训练
优点:
- 改动最少
- 风险最低
- 文档和代码都已有参考
路线 B:再接入真正的新类别
如果你确认要训练新物体,建议在路线 A 跑通后再做。
步骤:
- 为新对象分配
obj_id - 修改
common.py中类别映射 - 补齐
models_info.yml - 准备
.ply - 生成
corners.txt与farthest*.txt - 准备训练样本目录
- 视需要修改转换脚本中的
SUPPORTED_OBJ_IDS和OBJ_ID_TO_NAME
优点:
- 可扩展到任意自定义对象
代价:
- 代码改动明显更多
- 更容易漏掉关键点文件或映射配置
14. 当前仓库里需要特别注意的限制
12.1 训练转换脚本当前是 LINEMOD 定制的
在 convert_bop_lm_train_to_pvn3d.py 中,当前写死了:
SUPPORTED_OBJ_IDSOBJ_ID_TO_NAME
所以如果你的 BOP 数据里有新的对象 ID,这个脚本默认不会自动支持。
12.2 当前训练数据集假设每次只训练一个对象
这和 BOP 的多对象场景组织方式不同。
也就是说,你虽然可以从多对象 BOP 数据中抽取某个对象的数据来训练,但当前 LINEMOD 分支不是一个原生多对象联合训练实现。
12.3 当前关键点文件需要你自己提供
仓库不会自动从 .ply 生成:
corners.txtfarthest*.txt
如果你接入新类别,这些文件必须自行生成。
15. 实际落地时你至少需要准备什么
如果你现在要基于 /workspace/bop 做一套可训练数据,建议按下面清单准备。
最小可训练版本
/workspace/bop/lm_models/models/obj_XXXXXX.ply/workspace/bop/lm_train/train/{scene_id}/rgb/workspace/bop/lm_train/train/{scene_id}/depth/workspace/bop/lm_train/train/{scene_id}/mask/workspace/bop/lm_train/train/{scene_id}/scene_gt.json- 将其转换到
Linemod_preprocessed/data/{obj_id} - 准备
lm_obj_kps/{cls}/corners.txt - 准备
lm_obj_kps/{cls}/farthest*.txt - 在
common.py和models_info.yml中登记类别
更完整、更稳的版本
在最小版本基础上,再补:
/workspace/bop/lm_train_pbr/train_pbr/...scene_camera.jsonmask_visib- 转换得到
renders/{cls}/*.pkl
这样训练时就能混合:
- 真实图像
- PBR 合成图像
通常比只用真实图像更稳。
16. 总结
基于 BOP 格式构建 PVN3D 自定义训练数据集,不只是"把 RGB、depth、mask 拷过来"。
对当前仓库来说,真正需要同时满足的是三层要求:
- 逐帧训练样本完整
- 类别级别的模型与关键点完整
- 代码中的类别映射与对象配置完整
如果你只是沿用现有 LINEMOD 类别,当前仓库已经提供了相对完整的:
- BOP 训练数据转换脚本
- 训练目录结构
- 训练入口
如果你要训练真正的新类别,则至少还要补齐:
- 新对象 ID 映射
.plycorners.txtfarthest*.txtmodels_info.yml- 转换脚本中的对象白名单
所以最稳妥的实施顺序是:
- 先用现有 LINEMOD 类别跑通 BOP 到训练的整条链路
- 再把这套流程推广到新类别
这样能显著减少"数据格式已经对了,但训练仍然起不来"的排查成本。