update scripts in web_p (dataset, train)

This commit is contained in:
shalenikol 2025-02-28 20:21:33 +03:00
parent 7d3b8ff0cb
commit c85784f3dc
3 changed files with 256 additions and 29 deletions

View file

@ -8,6 +8,7 @@ import blenderproc as bproc
02.05.2024 @shalenikol release 0.1
02.07.2024 @shalenikol release 0.2
28.10.2024 @shalenikol release 0.3
28.02.2025 @shalenikol release 0.4 blenderproc 2.8.0 + blender 4.2.1 LTS
"""
import numpy as np
import argparse
@ -16,17 +17,32 @@ import os
import shutil
import json
from pathlib import Path
import time
###########################
# !!! чтобы избежать ошибки в версии 2.8.0
# free(): invalid pointer
# при вызове bproc.writer.write_bop
import pyrender
from pyrender.platforms import egl
###########################
start_time = time.time() # Запоминаем время начала
import bpy
VHACD_PATH = "blenderproc_resources/vhacd"
DIR_MODELS = "models"
DIR_MESH = "assets/libs/objects/"
# DIR_MESH = "assets/libs/objects/"
FILE_LOG_SCENE = "res.txt"
FILE_RBS_INFO = "rbs_info.json"
FILE_GT_COCO = "scene_gt_coco.json"
EXT_MODELS = ".fbx"
FILE_PARAMS = "form.json"
PROCEDURAL_TEXTURE = "texture_path" # key in randomization params: for texture types (Noise Textures), (Procedural Patterns) or (Tileable Textures)
EXT_MODELS = ".fbx" # for scene objects (floor ...)
DETAIL_KEY = "daeUrl" # "fbx" # key in dict 'Detail' for mesh path of model
TEXTURE_TMPL = "*.jpg"
TEXTURE_IMAGE_TYPES = ["Base Color", "Metallic", "Normal", "Roughness", "Specular IOR Level"]
Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует
@ -57,19 +73,50 @@ def convert2relative(height, width, bbox):
y += h/2
return x/width, y/height, w/width, h/height
def convert_seconds(total_seconds):
hours = int(total_seconds // 3600)
minutes = int((total_seconds % 3600) // 60)
seconds = int(total_seconds % 60)
return f"{hours:02}:{minutes:02}:{seconds:02}"
def render() -> int:
res_dir = rnd_par.output_dir
log_dir = os.path.dirname(res_dir)
# copy file with randomization params
file_params = os.path.join(res_dir, FILE_PARAMS)
if os.path.isfile(file_params):
shutil.copy2(file_params, log_dir)
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
i = 0
for obj in all_meshs:
# Make the object actively participate in the physics simulation
obj.enable_rigidbody(active=True, collision_shape="COMPOUND")
# Also use convex decomposition as collision shapes
obj.build_convex_decomposition_collision_shape(VHACD_PATH)
# # это для procedural texture, но пока не правильно
# fn = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".jpg" # файл с текстурой
# if os.path.isfile(fn):
# material = bproc.material.create_material_from_texture(fn, material_name="texture_model"+str(i))
# # Применяем текстуру к материалу
# obj.replace_materials(material)
tex = rnd_par.models.textures[i] # описание текстур
if tex["is"]:
mat = bproc.material.create("m"+str(i))
for x in tex["t_images"]:
key = list(x.keys())[0]
mat.set_principled_shader_value(key, bpy.data.images.load(filepath=x[key]))
obj.replace_materials(mat)
i += 1
# print(f"{i} : {obj.get_name()}")
objs = all_meshs + rnd_par.scene.objs
log_txt = os.path.join(os.path.dirname(rnd_par.output_dir), FILE_LOG_SCENE)
log_txt = os.path.join(log_dir, FILE_LOG_SCENE)
with open(log_txt, "w") as fh:
for i,o in enumerate(objs):
loc = o.get_location()
@ -91,23 +138,21 @@ def render() -> int:
rnd_par.image_size_wh[1],
lens_unit="FOV")
# Enable transparency so the background becomes transparent
bproc.renderer.set_output_format(enable_transparency=True) # ???
# add segmentation masks (per class and per instance)
bproc.renderer.enable_segmentation_output(map_by=["category_id", "instance", "name"])
# activate depth rendering
bproc.renderer.enable_depth_output(activate_antialiasing=False)
# res_dir = os.path.join(rnd_par.output_dir, rnd_par.ds_name)
res_dir = rnd_par.output_dir
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
# Цикл рендеринга
# Do multiple times: Position the shapenet objects using the physics simulator and render X images with random camera poses
for r in range(rnd_par.n_series):
print(f"********** Series : {r+1}")
is_texture = True if "texture_path" in rnd_par.models_randomization else False
is_texture = True if PROCEDURAL_TEXTURE in rnd_par.models_randomization else False
if is_texture:
val = rnd_par.models_randomization["texture_path"]
val = rnd_par.models_randomization[PROCEDURAL_TEXTURE]
l_texture = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(l_texture[r % len(l_texture)]))
# один случайный объект в кадре / все заданные объекты
@ -125,16 +170,32 @@ def render() -> int:
for i,o in enumerate(rnd_par.scene.objs): # объекты сцены
rnd_mat = rnd_par.scene.obj_data[i]["material_randomization"]
# if PROCEDURAL_TEXTURE in rnd_mat: # путь к текстурам (*.jpg)
# mat = bproc.material.create("m"+str(i))
# # for x in tex["t_images"]:
# # key = list(x.keys())[0]
# val = rnd_mat[PROCEDURAL_TEXTURE]
# val = _get_list_texture(val)
# image = bpy.data.images.load(filepath=str(random.choice(val)))
# mat.set_principled_shader_value("Base Color", image)
# o.replace_materials(mat)
mats = o.get_materials() #[0]
for mat in mats:
# with open(log_txt, "a") as fh:
# fh.write("************* mat\n")
# fh.write(f"{mat}\n")
val = rnd_mat["specular"]
mat.set_principled_shader_value("Specular", random.uniform(val[0], val[1]))
mat.set_principled_shader_value("Specular IOR Level", random.uniform(val[0], val[1])) # для Blender < 4.2 было "Specular"
val = rnd_mat["roughness"]
mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1]))
val = rnd_mat["metallic"]
mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1]))
if "texture_path" in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat["texture_path"]
if PROCEDURAL_TEXTURE in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat[PROCEDURAL_TEXTURE]
val = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(random.choice(val)))
mat.set_principled_shader_value("Base Color", image)
@ -156,7 +217,7 @@ def render() -> int:
# Define a function that samples 6-DoF poses
def sample_pose(obj: bproc.types.MeshObject):
obj.set_location(np.random.uniform(rnd_par.loc_range_low, rnd_par.loc_range_high)) #[-1, -1, 0], [1, 1, 2]))
obj.set_rotation_euler(bproc.sampler.uniformSO3())
obj.set_rotation_euler(bproc.sampler.uniformSO3(around_x=rnd_par.around_x, around_y=rnd_par.around_y, around_z=rnd_par.around_z))
# Sample the poses of all shapenet objects above the ground without any collisions in-between
bproc.object.sample_poses(meshs,
@ -232,7 +293,12 @@ def render() -> int:
rec["name"] = objn
rec["model"] = os.path.join(DIR_MODELS, os.path.split(rnd_par.models.filenames[i])[1]) # путь относительный
t = [obj.get_bound_box(local_coords=True).tolist() for obj in all_meshs if obj.get_name() == objn]
rec["cuboid"] = t[0]
if len(t) > 0:
rec["cuboid"] = t[0]
else: # object name does not match file name
rec["Error"] = "!!! object name does not match file name: cuboid is zero"
rec["cuboid"] = np.zeros((8, 3)).tolist()
data.append(rec)
shutil.copy2(rnd_par.models.filenames[i], models_dir)
f = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".mtl" # файл материала
@ -283,9 +349,37 @@ def render() -> int:
if Not_Categories_Name:
explore(res_dir)
end_time = time.time() # время окончания
execution_time = end_time - start_time # время выполнения
with open(log_txt, "a") as fh:
fh.write("*****************\n")
fh.write(f"Время выполнения: {convert_seconds(execution_time)}\n")
return 0 # success
def _get_models(par, data) -> int:
def set_texture_model(name: str, textures: list, model_d) -> None:
"""
textures заполняется массивом текстур вида:
[{"is": True, "t_images": [{"Base Color":"/path/to/shkaf_d.png"}, {"Normal":"/path/to/shkaf_n.png"}] }, ... ]
"""
d = {"is": False}
if "models" in model_d:
for model in model_d["models"]:
if model["name"] == name:
path = model["texture_dir"].strip()
if path:
t_images = []
for x in TEXTURE_IMAGE_TYPES:
if x in model:
rel_path = model[x].strip()
if rel_path:
t_images.append({x: os.path.join(path, rel_path)})
if len(t_images):
d["is"] = True
d["t_images"] = t_images
textures.append(d)
def _get_models(par, data, models_data) -> int:
global all_meshs
par.models = lambda: None
@ -294,13 +388,14 @@ def _get_models(par, data) -> int:
return 0 # no models
# загрузим объекты
par.models.names = [] # obj_names
par.models.filenames = [] # obj_filenames
par.models.names = []
par.models.filenames = []
par.models.textures = []
i = 1
for f in data:
nam = f["name"]
par.models.names.append(nam)
ff = f["fbx"] # _get_path_model(nam)
ff = f[DETAIL_KEY] # _get_path_model(nam)
par.models.filenames.append(ff)
if not os.path.isfile(ff):
print(f"Error: no such file '{ff}'")
@ -311,6 +406,7 @@ def _get_models(par, data) -> int:
obj = bproc.loader.load_obj(ff)
all_meshs += obj
obj[0].set_cp("category_id", i) # начиная с 1
set_texture_model(nam, par.models.textures, models_data)
i += 1
return par.models.n_item
@ -370,8 +466,6 @@ if __name__ == "__main__":
print(f"JSon error: {e}")
exit(-2)
# output_dir = args.path
ds_cfg = cfg["output"] # dataset config
generation = ds_cfg["generation"]
cam_pos = ds_cfg["camera_position"]
@ -399,11 +493,14 @@ if __name__ == "__main__":
rnd_par.models_randomization = models_randomization
rnd_par.loc_range_low = models_randomization["loc_range_low"]
rnd_par.loc_range_high = models_randomization["loc_range_high"]
rnd_par.around_x = (models_randomization["around_x"] == "True")
rnd_par.around_y = (models_randomization["around_y"] == "True")
rnd_par.around_z = (models_randomization["around_z"] == "True")
bproc.init()
all_meshs = []
if _get_models(rnd_par, rnd_par.dataset_objs) <= 0:
if _get_models(rnd_par, rnd_par.dataset_objs, models_randomization) <= 0:
print("Error: no models in config")
exit(-4)
if _get_scene(rnd_par, ds_cfg["scene"]) <= 0: