6D位姿估计--BlenderProc合成数据集

本文详细介绍了如何使用BlenderProc生成6D位姿估计的数据集,包括环境设置、工具安装、数据集制作过程,以及在实际操作中遇到的bug和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

6D位姿估计–BlenderProc合成数据集

制作真实数据集难以在短时间内获得大量数据,采用合成的方式可以弥补这一不足。

环境搭建

  1. 使用conda创建bop虚拟环境并激活
conda create --name bop python=3.8
conda activate bop
  1. 安装bop工具
git clone https://github.com/thodan/bop_toolkit.git
cd bop-toolkit
pip install -r requirements.txt -e .
  1. 安装blenderproc
git clone https://github.com/DLR-RM/BlenderProc

cd BlenderProc
pip install -e .

数据集制作

  1. BOP官网上下载以下两个文件
    在这里插入图片描述
  2. 将lm_base.zip移动到BlenderProc目录,并解压,然后将
    lm_models.zip放到刚解压出来的lm目录中并解压,得到lm目录如下:
.
├── camera.json
├── dataset_info.md
├── models
├── models_eval
└── test_targets_bop19.json
  1. 准备场景贴图,在BlenderProc目录新建backgrouns文件夹并运行
blenderproc download cc_textures ./backgrounds

这会在 ./backgrounds中下载很多场景贴图材料,下载一些就可以ctrl+c中断了,不然会下载很多。

  1. 生成数据集
blenderproc run examples/datasets/bop_challenge/main_lm_upright.py .. ./backgrounds ./output --num_scenes=20

参数含义:

parser.add_argument('bop_parent_path', help="Path to the bop datasets parent directory")
parser.add_argument('cc_textures_path', default="resources/cctextures", help="Path to downloaded cc textures")
parser.add_argument('output_dir', help="Path to where the final files will be saved ")
parser.add_argument('--num_scenes', type=int, default=20, help="How many scenes with 25 images each to generate")

也是运行一段时间差不多生成数量够了就可以提前终止了

但这一步第一次运行的时候会自动安装blender,以及一个相应的python虚拟环境,很费时间,不太好使,慢慢等待。

制作自己的目标物体数据集

  1. 将自己的ply文件放进/lm/models中,并在models_info.json中添加对应的模型信息.可以使用下面的代码获取模型信息。
from plyfile import PlyData
import os
import numpy as np
model_path = os.path.join('./Linemod_preprocessed/models/obj_01.ply')
ply = PlyData.read(model_path)
data = ply.elements[0].data
x = data['x']
y = data['y']
z = data['z']
x_size = np.max(x)-np.min(x)
y_size = np.max(y)-np.min(y)
z_size = np.max(z)-np.min(z)

print("Min X:")
print(np.min(x))
print("Min Y:")
print(np.min(y))
print("Min Z:")
print(np.min(z))
print('-----------------------------------------------------------------')
print("Size X:")
print(np.max(x)-np.min(x))
print("Size Y:")
print(np.max(y)-np.min(y))
print("Size Z:")
print(np.max(z)-np.min(z))
print('-----------------------------------------------------------------')
print("Diameter:")
print( np.sqrt(x_size**2 + y_size**2 + z_size**2) ) #直径
f = open("./Linemod_preprocessed/models/models_info.txt","w")
f.write("1: {")
f.write("diameter: {}, min_x: {}, min_y: {}, min_z: {}, size_x: {}, size_y: {}, size_z: {}".format(np.sqrt(x_size**2 + y_size**2 + z_size**2) ,np.min(x) ,np.min(y) ,np.min(z),(np.max(x)-np.min(x)) ,(np.max(y)-np.min(y)),(np.max(z)-np.min(z))))
f.write("}")
f.close()

os.rename("./Linemod_preprocessed/models/models_info.txt","./Linemod_preprocessed/models/models_info.yml")

#os.remove("compute_model_info.py")
  1. 替换camera.json中的相机参数为自己的相机参数
    depth_scale camera.json
target_bop_objs = bproc.loader.load_bop_objs(bop_dataset_path = os.path.join(args.bop_parent_path, 'lm'), obj_ids = [1], object_model_unit = 'm')
    bproc.writer.write_bop(os.path.join(args.output_dir, 'bop_data'),
                           target_objects = sampled_target_bop_objs,
                           dataset = 'lm',
                           depth_scale = 0.001,
                           depths = data["depth"],
                           colors = data["colors"], 
                           color_file_format = "JPEG",
                           ignore_dist_thres = 10)
  1. 生成数据集
blenderproc run examples/datasets/bop_challenge/main_lm_upright.py ..
./backgrounds ./output --num_scenes=20

在这里插入图片描述
(重建制作ply文件时质量太差,重建出来的瓶子很丑)
在这里插入图片描述
4.

cd  /bop_toolkit/scripts
python calc_gt_masks.py 
python calc_gt_info.py 

python gt.py 
python info.py 

BUG

FileNotFoundError: [Errno 2] No such file or directory: '/home/enco/bop_toolkit/BlenderProc/lm/camera.json'

创建该文件并写入自己的相机参数。
2.

FileNotFoundError: The given filepath does not exist: /home/enco/bop_toolkit/BlenderProc/lm/models/obj_000001.ply

这里需要修改main_lm_upright.py中的第16行代码,作者把代码写死了,这里需要根据自己的实际情况对obj_ids = [1]进行修改,原作者调用bop_tookit中的params.py传入这个参数的,而params.py中默认lm数据集有15个模型,另外确保ply文件命名正确。

target_bop_objs = bproc.loader.load_bop_objs(bop_dataset_path = os.path.join(args.bop_parent_path, 'lm'), obj_ids = [1], object_model_unit = 'm')

object_model_unit = 'm’是模型的单位参数,有m、cm、mm,具体查看自己的ply文件,视情况而定。
3.

sampled_target_bop_objs = list(np.random.choice(target_bop_objs, size=15, replace=False))
  File "mtrand.pyx", line 965, in numpy.random.mtrand.RandomState.choice
ValueError: Cannot take a larger sample than population when 'replace=False'

使用np.random.choice时,你试图从一个群体中抽取比群体大小更多的元素,而且是在replace=False(即无放回抽样)的情况下,在不放回抽样的情况下,抽样大小不能超过群体大小。
在相应位置修改如下:

if len(target_bop_objs) < 15:  # 检查群体大小是否小于期望的样本大小,否则不抽样
        sampled_target_bop_objs = target_bop_objs
else:
   	    sampled_target_bop_objs = list(np.random.choice(target_bop_objs, size=15, replace=False))

当然也可以修改size=15参数,但不建议修改为有放回抽样。

poi = bproc.object.compute_poi(np.random.choice(sampled_target_bop_objs, size=1, replace=False))

这一行也需要做相应的修改。

gt.py

import yaml
import json
import os
from pathlib import Path
from fnmatch import fnmatchcase


class Yaml_Interconversion_Json:
    def __init__(self):
        self.filePathList = []

    # json文件内容转换成yaml格式
    def json_to_yaml(self, jsonPath1, jsonPath2):
        with open(jsonPath1, encoding="utf-8") as f1:
            datas1 = json.load(f1)  # 将文件的内容转换为字典形式
        with open(jsonPath2, encoding="utf-8") as f2:
            datas2 = json.load(f2)  # 将文件的内容转换为字典形式
            i = 0
            new_data = {}
            while (i < 100):############################################修改为生成的数据集图片数量
                b = str(i)
                new_data.update({i: [{'cam_R_m2c': datas1[b][0]['cam_R_m2c'], 'cam_t_m2c': datas1[b][0]['cam_t_m2c'],
                                      'obj_bb': datas2[b][0]['bbox_obj'], 'obj_id': datas1[b][0]['obj_id']}]})

                print(i)
                i = i + 1
            yamlDatas = yaml.dump(new_data, indent=5, sort_keys=False)  # 将字典的内容转换为yaml格式的字符串
        return yamlDatas

    #    # json文件内容转换成yaml格式
    # def json_to_yaml(self, jsonPath):
    #     with open(jsonPath, encoding="utf-8") as f:
    #         datas = json.load(f)
    #     yamlDatas = yaml.dump(datas, indent=5, sort_keys=False)
    #     # print(yamlDatas)
    #     return yamlDatas

    # 生成文件
    def generate_file(self, filePath, datas):
        if os.path.exists(filePath):
            os.remove(filePath)
        with open(filePath, 'w') as f:
            f.write(datas)

    # 清空列表
    def clear_list(self):
        self.filePathList.clear()

    # 修改文件后缀
    def modify_file_suffix(self, filePath1, suffix):
        dirPath = os.path.dirname(filePath1)
        fileName = 'gt' + suffix
        newPath = dirPath + '/' + fileName
        # print('{}_path:{}'.format(suffix, newPath))
        return newPath

    # 原json文件同级目录下,生成yaml文件
    def generate_yaml_file(self, jsonPath1, jsonPath2, suffix='.yml'):
        yamlDatas = self.json_to_yaml(jsonPath1, jsonPath2)
        yamlPath = self.modify_file_suffix(jsonPath1, suffix)
        # print('yamlPath:{}'.format(yamlPath))
        self.generate_file(yamlPath, yamlDatas)


if __name__ == "__main__":
    jsonPath1 = '/home/enco/bop_toolkit/BlenderProc/output/bop_data/lm/train_pbr/000000/scene_gt.json'##scene_gt.json位置
    jsonPath2 = '/home/enco/bop_toolkit/BlenderProc/output/bop_data/lm/train_pbr/000000/scene_gt_info.json'##scene_gt_info.json位置
    yaml_interconversion_json = Yaml_Interconversion_Json()
    yaml_interconversion_json.generate_yaml_file(jsonPath1, jsonPath2)

info.py

import yaml
import json
import os
from pathlib import Path
from fnmatch import fnmatchcase


class Yaml_Interconversion_Json:
    def __init__(self):
        self.filePathList = []

    # json文件内容转换成yaml格式
    def json_to_yaml(self, jsonPath):
        with open(jsonPath, encoding="utf-8") as f1:
            datas = json.load(f1)  # 将文件的内容转换为字典形式
            i = 0
            new_data = {}
            while i < 100:#################################################################修改为生成的数据集图片数量
                b = str(i)
                new_data.update({i: {'cam_K': datas[b]['cam_K'], 'depth_scale': datas[b]['depth_scale']}})
                print(i)
                i = i + 1
            yamlDatas = yaml.dump(new_data, indent=5, sort_keys=False)  # 将字典的内容转换为yaml格式的字符串
        return yamlDatas

    #    # json文件内容转换成yaml格式
    # def json_to_yaml(self, jsonPath):
    #     with open(jsonPath, encoding="utf-8") as f:
    #         datas = json.load(f)
    #     yamlDatas = yaml.dump(datas, indent=5, sort_keys=False)
    #     # print(yamlDatas)
    #     return yamlDatas

    # 生成文件
    def generate_file(self, filePath, datas):
        if os.path.exists(filePath):
            os.remove(filePath)
        with open(filePath, 'w') as f:
            f.write(datas)

    # 清空列表
    def clear_list(self):
        self.filePathList.clear()

    # 修改文件后缀
    def modify_file_suffix(self, filePath, suffix):
        dirPath = os.path.dirname(filePath)
        fileName = 'info' + suffix
        newPath = dirPath + '/' + fileName
        # print('{}_path:{}'.format(suffix, newPath))
        return newPath

    # 原json文件同级目录下,生成yaml文件
    def generate_yaml_file(self, jsonPath, suffix='.yml'):
        yamlDatas = self.json_to_yaml(jsonPath)
        yamlPath = self.modify_file_suffix(jsonPath, suffix)
        # print('yamlPath:{}'.format(yamlPath))
        self.generate_file(yamlPath, yamlDatas)


if __name__ == "__main__":
    jsonPath = '/home/enco/bop_toolkit/BlenderProc/output/bop_data/lm/train_pbr/000000/scene_camera.json'##scene_camera.json的位置
    yaml_interconversion_json = Yaml_Interconversion_Json()
    yaml_interconversion_json.generate_yaml_file(jsonPath)

您可以在 Ant Design Vue 的弹窗中使用 Table 组件和 Select 组件来实现行编辑中的下拉选择框。首先,您需要在 Table 组件中设置 editable 属性为 true,这样就可以开启行编辑功能。然后,您可以在需要进行下拉选择框编辑的列中,使用 scoped slot 的方式自定义单元格内容,并在该单元格中使用 Select 组件来实现下拉选择框。具体实现方法可以参考以下代码示例: ```html <template> <div> <a-button type="primary" @click="showModal">打开弹窗</a-button> <a-modal v-model="visible" title="编辑表格" :width="800"> <a-form :form="form"> <a-table :columns="columns" :data-source="data" :row-key="record => record.id" :editable="true"> <template slot-scope="text, record, index"> <a-form-item> <a-select v-model="record.selectValue" style="width: 100%"> <a-select-option v-for="option in options" :key="option.value" :value="option.value">{{ option.label }}</a-select-option> </a-select> </a-form-item> </template> </a-table> </a-form> </a-modal> </div> </template> <script> import { Modal, Form, Button, Table, Select } from 'ant-design-vue' export default { components: { 'a-modal': Modal, 'a-form': Form, 'a-button': Button, 'a-table': Table, 'a-form-item': Form.Item, 'a-select': Select, 'a-select-option': Select.Option, }, data() { return { visible: false, form: this.$form.createForm(this), data: [ { id: 1, name: '张三', age: 18, selectValue: 'option1' }, { id: 2, name: '李四', age: 22, selectValue: 'option2' }, { id: 3, name: '王五', age: 25, selectValue: 'option3' }, ], options: [ { label: '选项1', value: 'option1' }, { label: '选项2', value: 'option2' }, { label: '选项3', value: 'option3' }, ], columns: [ { title: 'ID', key: 'id', dataIndex: 'id', editable: false }, { title: '姓名', key: 'name', dataIndex: 'name', editable: true }, { title: '年龄', key: 'age', dataIndex: 'age', editable: true }, { title: '下拉选择框', key: 'selectValue', dataIndex: 'selectValue', editable: true }, ], } }, methods: { showModal() { this.visible = true }, }, } </script> ``` 在上面的代码示例中,我们使用了 Ant Design Vue 的 Modal、Form、Button、Table 和 Select 组件来实现弹窗、表单、按钮、表格和下拉选择框。在 Table 组件中,我们使用了 scoped slot 来自定义单元格内容,并在该单元格中使用 Select 组件来实现下拉选择框。同时,我们还需要在该列的配置项中设置 editable 属性为 true,以开启该列的编辑功能。最终,我们将 Table 组件放置在 Modal 组件中,实现了在弹窗中编辑带有下拉选择框的表格的功能。
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值