文章目录

  • 6D位姿估计--BlenderProc合成数据集
  • 环境搭建
  • 数据集制作
  • 制作自己的目标物体数据集
  • BUG


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

Blender 怎么打开stp文件_Blender 怎么打开stp文件


(重建制作ply文件时质量太差,重建出来的瓶子很丑)

Blender 怎么打开stp文件_计算机视觉_02


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)