资源
仓库地址:DLR-RM/BlenderProc: A procedural Blender pipeline for photorealistic training image generation (github.com),下载到本地,用 python 打开,解释器使用之前创建的 blender 环境。
正文
Basic example
Usage
示例代码在 examples/basics/basic/main.py
中。shell 中输入:
|
即可开跑!我说婷婷,会报错:
|
我设了个全局代理和 TUN 模式再多跑几次就可以了orz
这么看从网上下载 freeimage-3.15.1-win64.dll
,然后放到 C:\Users\XXXX\AppData\Local\imageio\freeimage\
下也是可以的!
|
|
Visualization
|
渲染了 colors、depth、normals 三张图片:
Code
接受三个 parser 参数:
examples/resources/camera_positions
:相机参数文本文件。
第一行数据表示相机位于 (0, -13.741, 4.1242) 的位置,其绕 x 轴旋转角度为 1.3,绕 y 轴旋转角度为 0,绕 z 轴旋转角度为 0。
第二行数据表示相机位于 (1.9488, -6.5202, 0.23291) 的位置,其绕 x 轴旋转角度为 1.84,绕 y 轴旋转角度为 0,绕 z 轴旋转角度为 0.5。
examples/resources/scene.obj
:obj 文件,basic scene 的信息。
这是一个 Wavefront OBJ 文件,它是一种 3D 对象文件格式。该文件包含了多个物体:"Cube" 和 "Cube.001" 等。
在文件的开头,有一行 "mtllib scene.mtl",表示该文件引用了一个名为 "scene.mtl" 的材质库文件,其中定义了这些物体所使用的材质/纹理信息。
接下来,通过使用 "v","vt",和 "vn" 关键字定义了每一个物体的顶点位置、纹理坐标和法向量。
具体来说,每一个 "v" 后面的三个数值表示一个顶点的 x,y 和 z 坐标;
每一个 "vt" 后面的两个数值表示一个纹理坐标值,在这个文件中,它们是相对于材质图像的位置;
每一个 "vn" 后面的三个数值表示一个法向量的 x,y 和 z 分量。
下面排列的 "f" 行表示了多边形,每一个 "f" 后面跟随着一些数字,这些数字表示该多边形的组成部分。
在这个文件中,不同的数字之间使用斜线 "/" 分隔。
具体来说,每一个数字表示该物体的一个顶点,该顶点由前面的 "v" 行中相应编号的顶点位置信息定义,而后面的数字则来自前面的 "vt" 和 "vn" 行。
每一行的最后一个数字是该多边形的法向量,这个法向量来自 "vn" 行,指定了多边形所在平面的朝向。
"s off" 表示关闭了 smooth shading,即不使用平滑着色技术。
examples/basics/basic/output
:输出文件路径
|
初始化 blenderproc:
|
从 args.scene
中载入模型场景:
|
载入灯光:
|
载入相机:这段代码的作用是设置相机分辨率,并读取相机位置信息并转换为齐次相机-世界变换矩阵。
|
渲染图像:
|
首先,我们需要启用 blenderproc
生成每张彩色图像的法线和距离。此外,我们设置所需的图像噪声阈值。较低的噪声阈值将减少图像中的噪声,但会增加渲染时间。默认值为 0.01
,适用于大多数应用程序。
=>在临时文件夹中创建文件 rgb_0000.png
和 rgb_0001.png
。同时还创建法线和深度图像。
- 法线和深度图像是使用
.exr
格式渲染的,可以线性色彩空间和更高的精度。 - 在这里,深度图像没有反锯齿处理,意味着对于每个像素,该像素中的深度不会聚合在其表面上。虽然距离和深度图像听起来很相似,但它们并不相同:在距离图像中,每个像素都包含从摄像机位置到场景中对应点的实际距离。而在深度图像中,每个像素都包含相应点所处的与摄像机平行的平面与摄像机之间的距离。
=>创建文件 normal_0000.exr
、normal_0001.exr
、distance_0000.exr
和 distance_0001.exr
。
在本例中,所有这些文件都是临时文件,直接在渲染后读取并在临时文件夹中删除。然后将它们打包成字典并返回,保存在 data
变量中。
FAQ:如果我们直接读取它们,为什么还要将它们存储在磁盘上?
- Blender 没有其他选项,只能先将它们保存到磁盘,然后再读取它们。
首先,通过调用 bproc.renderer.enable_normals_output() 和 bproc.renderer.enable_depth_output(activate_antialiasing=False) 函数,启用了法线和深度渲染。其中,enable_normals_output() 函数允许将法线渲染输出到渲染结果中,而 enable_depth_output(activate_antialiasing=False) 函数则允许将深度渲染输出到渲染结果中,并且关闭了抗锯齿选项。
接着,调用 bproc.renderer.render() 函数,开始渲染整个渲染管线,并将渲染结果存储在 data 变量中。在渲染过程中,会依次执行多个处理步骤,包括场景图遍历、光照计算、材质映射、纹理映射等,并最终生成最终的渲染结果。渲染结束后,data 变量中将包含法线和深度信息,它们可以用来进行后续的图像处理、计算机视觉等任务。
保存成 .hdf5
文件:
|
Camera sampling
Usage
|
Visualization
|
|
Code
|
Light sampling
Usage
|
Visualization
|
Code
|
这段代码的含义是:
首先,创建了一个名为 light 的 BlenderProc Light 类型变量。
接着,通过调用 light.set_type("POINT") 函数,指定该光源为点光源类型,即在三维空间中的某一点产生均匀辐射的光源。
然后,通过调用 bproc.sampler.shell(center=[1, 2, 3], radius_min=4, radius_max=7, elevation_min=15, elevation_max=70) 函数,生成一个位于包围点 [1, 2, 3] 的球壳内的随机三维坐标位置,并将其设置为光源的位置,以实现光源位置的随机性。具体而言,函数的参数如下:
- center=[1, 2, 3]:球心位置为 [1, 2, 3]。
- radius_min=4:球壳内径的最小值为 4。
- radius_max=7:球壳外径的最大值为 7。
- elevation_min=15:光源位置相对于球心高度的最小值为 15 度。
- elevation_max=70:光源位置相对于球心高度的最大值为 70 度。
最后,通过调用 light.set_energy(500) 函数,将光源的强度 energy 设置为 500 瓦特,以控制光照亮度。
|
这段代码的含义是:
首先,通过调用 bproc.renderer.render() 函数,对当前的场景进行渲染,并将渲染结果存储在 data 变量中。
接着,通过遍历 objs 列表中的每一个对象 obj,将 obj 的名称和本地坐标系到世界坐标系的变换矩阵信息添加到 object_states 列表中。
然后,将 object_states 列表复制 num_frames 次,并将其作为数据字典 data 中键名为 "object_states" 的值,表示所有帧的物体状态相同。
接下来,将 light 对象的名称、本地坐标系到世界坐标系的变换矩阵信息和能量值信息添加到 light_state 字典中,并将其复制 num_frames 次并添加到 data 中键名为 "light_states" 的值中,表示所有帧的光源状态相同。
最后,通过循环遍历所有帧的索引 frame,将每一帧相机的相机坐标系到世界坐标系的变换矩阵 cam2world 和相机的内参矩阵 K 添加到 cam_states 列表中,并将其作为数据字典 data 中键名为 "cam_states" 的值,表示所有帧的相机状态。
Object selection and manipulation
Usage
|
Visualization
|
Code
|
这个示例的重点是使用BlenderProc进行过滤操作以及设置对象的旋转和位置。
在此过滤操作中,我们将条件设置为:
"name": 'Suzanne'
,意思是我们想要选择所有满足obj.name == 'Suzanne'
的对象。在这种情况下,只有一个对象符合要求。如果我们想要选择多个元素,我们可以使用bproc.filter.by_attr()
函数。这样就可以选择多个对象。请注意:任何给定的字符串类型属性值都可以被视为正则表达式,只需在
one_by_attr fct.
调用中设置regex=True
即可。因此,"name": 'Cylinder.*'
的条件将选择场景中的所有三个圆柱体。要查看所有可能的属性名称,请查阅官方 Blender 文档:https://docs.blender.org/api/current/bpy.types.Object.html。
Material selection and manipulation
Usage
|
examples/basics/material_manipulation/main.py
: path to the python file.examples/basics/material_manipulation/scene.obj
: path to the object file with the basic scene.images
: path to a folder with .jpg textures to be used in the sampling process.examples/basics/material_manipulation/output
: path to the output directory.
Visualization
|
|
这段代码的作用是:
- 使用 bproc.material.collect_all()函数查找所有材质。
- 使用 bproc.filter.one_by_attr()函数通过属性查找特定材质。在这种情况下,我们使用 "name": "Material.001" 来查找 ground object 的材质。
- 使用 ground_material.set_displacement_from_principled_shader_value()函数来设置基于其基础颜色纹理的位移。在这种情况下,我们将 multiply_factor 设置为 1.5,以增加位移强度。
这段代码的目的是修改指定材质的属性,实现更具创意的渲染效果。
|
这段代码的作用是:
- 使用 pathlib 库中的 Path() 函数来设置指定目录(args.image_dir)的绝对路径,并通过 rglob() 函数找到该目录下所有以 "material_manipulation_sample_texture*.jpg" 结尾的文件。
- 遍历所有材质,为每个材质设置随机选择的纹理。在这里,我们使用了 random.choice() 函数从上一步中收集到的所有图像中随机选择一个。然后通过 mat.set_principled_shader_value() 函数将其设置为当前材质的基础颜色。
这段代码的目的是为指定的 Blender 场景中的所有材质添加多样化的纹理素材,以增强渲染效果和真实感。
Physics positioning
Usage
|
examples/basics/physics_positioning/main.py
: path to the python file.examples/basics/physics_positioning/active.obj
: path to the object file with active objects, i. e. objects which we want to participate in physics simulation.examples/basics/physics_positioning/passive.obj
: path to the object file with passive objects, i. e. objects which we do not want to participate in physics simulation, e.g. plane.examples/basics/physics_positioning/output
: path to the output directory.
Visualization
|
Code
|
首先,我们定义一个函数,将给定的物体设置为新的姿态。然后,在 bproc.object.sample_poses
函数调用中使用该函数,在每个物体上调用它,然后检查是否与其他物体发生碰撞。这个过程会重复进行,直到所有物体都被放置且没有发生碰撞。
这段代码的作用是:
- 定义一个名为 sample_pose() 的函数,该函数接受一个 bproc.types.MeshObject 对象作为参数,并对其进行位置和旋转属性的随机抽样,以模拟物体在 3D 空间中的运动姿态。具体来说,我们使用 obj.set_location() 函数将物体的位置坐标随机设置在 [-5,-5,8] 到 [5,5,12] 的范围内,并使用 obj.set_rotation_euler() 函数将物体的欧拉旋转角度随机设置。
- 使用 bproc.object.sample_poses() 函数对所有位于地面上方的 sphere 进行姿态抽样,同时确保每个 sphere 之间没有碰撞发生。我们通过传递 spheres 和 sample_pose_func 参数来执行这一操作。其中,spheres 指代待采样的所有 sphere 对象的列表,sample_pose_func 参数指定了姿态抽样函数,即上述定义的 sample_pose() 函数。
这段代码的目的是模拟物体的动态运动过程,以增加渲染效果的真实感。
|
这段代码的作用是:
- 将所有 sphere 对象设置为活动态,通过启用其刚体属性(rigidbody)实现。对于地面来说,将 active 属性设置为 False,这意味着它在场景中是被动的,但可以和其他活动态物体发生交互。此外,我们还使用 MESH 碰撞形状(collision shape)而不是默认的 CONVEX_HULL 碰撞形状来设置 ground 物体的碰撞形状。需要注意的是,在更复杂的用例中使用 mesh 碰撞形状可能会导致性能问题和错误。如果出现这些情况,最好尝试使用 physics_convex_decomposition。
- 在运行物理仿真时,函数每隔 1 秒检查一次是否仍有对象在运动。如果没有,就停止仿真。然而,仿真至少运行 4 秒,最多运行 20 秒。
- 在仿真结束时,将所有 sphere 的位置重新固定。这样,我们可以轻松采样位于凹凸不平的平面上方的 sphere 的随机位置。
这段代码的目的是模拟物体之间的物理交互和运动过程,以增加渲染效果的真实感。
Semantic Segmentation
Usage
|
examples/basics/semantic_segmentation/main.py
: path to the python file.examples/resources/camera_positions
: text file with parameters of camera positions.examples/basics/semantic_segmentation/scene.blend
: path to the blend file with the basic scene.examples/basics/semantic_segmentation/output
: path to the output directory.
Visualization
|
Code
|
这个代码段加载了 .blend
文件,从文件中仅提取网格对象,而不是提取该 .blend
文件中存储的所有信息。
需要注意的是,在加载的 .blend
文件中,所有对象都已经设置了属性名称为“category_id”的自定义属性。这可以通过手动执行以下步骤来完成:
|
|
这个模块可以将任何类型的对象相关信息映射到图像或场景中对象的索引列表。例如,如果你想要将自定义属性
category_id
映射到图像上,可以设置map_by=["category_id"]
。然后,每个像素都会被分配一个现有像素中的对象的自定义属性category_id
。如果它被设置为实例化,每个像素将获得一个场景中对象的 id,这些 id 对于多帧是一致的,这也意味着并不是每个图像中都必须出现所有的 id。此外,还可以将其设置为对象类的不同自定义属性或属性,如“name”,这将返回每个对象的名称。这无法保存在图像中,因此需要生成一个额外的字典,附加到最终的
.hdf5
容器中。其中,它将每个实例编号映射到一个名称。如果有不能存储在图像中的键,则必须生成一个实例图像,否则会引发错误消息。例如,也可以使用属性:“location”。这将访问每个对象的位置并将其添加到字典中。需要注意的是,如果背景可见,则会引发错误,因为背景没有位置属性。这可以通过提供默认值来避免,例如:
default_values={"location: [0,0,0]}
。
Camera Object Pose Setting
Usage
|
examples/basics/camera_object_pose/main.py
: Python 文件的路径。
随后的参数用于填充配置文件中的占位符,例如 <args:0>
。
examples/basics/camera_object_pose/obj_000004.ply
: 模型文件的路径,在这里是hb
数据集中的一个基本对象。
|
这个ply文件包含了一个三角网格模型的数据,其中每行数据表示一个顶点或者一个三角面的信息。下面是文件中的每个部分的解释:
第一行指定了文件使用的PLY文件格式。
第二行指定了文件的数据格式为ASCII格式,版本为1.0。
第三行声明该模型包含59070个顶点。
第四行到第十行分别声明了顶点数据中包含的属性,分别是x,y,z坐标和法线nx,ny,nz以及颜色属性red,green,blue,alpha。
第十一行声明该模型包含118136个三角形(即面)。
第十二行定义了面数据的属性列表,包括每个面由几个顶点组成以及对应的顶点索引。
第十三行是文件头与数据部分的分隔符。
从第十四行开始每一行都表示一个顶点的信息,按照x,y,z坐标、法线nx,ny,nz和颜色属性red,green,blue,alpha依次排列。
从最后一个顶点的信息结束后,文件中间间隔了若干空行,接下来每一行表示一个三角形面,格式为"3 a b c",表示该面由三个顶点a,b,c组成,a,b,c分别是该点在顶点列表中的索引。
总的来说,这个PLY文件描述了一个三角网格模型,包含了所需的顶点和面数据,可以被一些三维建模软件或者游戏引擎读取和展示。
examples/basics/camera_object_pose/output
: 输出目录的路径。
Code
|
- 将所有材质转换为顶点颜色(vertex color)材质,并直接使用每个加载的 .ply 对象的顶点颜色。这意味着,我们不再使用原始材质文件,而是用顶点颜色来渲染场景。
- 设置物体姿态的 matrix_world 属性为米(meter)单位。
- 按照每个维度的尺寸比例,将模型从毫米(mm)单位缩放到米(meter)单位。需要注意的是,如果模型已经以米(meter)为单位,则不需要执行这一步操作。
- 设置一个新的自定义属性
"category_id"
,并将其设置为1
。后面的分割渲染器将使用该属性。
这段代码的目的是对加载的模型进行预处理和优化,以便更好地适应后续渲染流程的需要。其中,将材质转换为顶点颜色材质可以减少纹理贴图的计算量,使场景更易于渲染;缩放模型到标准的米(meter)单位可以方便控制场景尺寸及物体之间距离的关系;设置自定义属性可以增加场景元素的分类信息,让后续的分割渲染器能够更好地区分不同的物体。
|
这段代码的目的是对相机的内部光学特性和相对位置进行设置。通过设置相机内参和姿态,可以精确地模拟相机在场景中的位置、朝向,以及捕捉图像时的畸变效果等。这有助于实现更逼真的渲染效果,并提高视觉算法的精度。
- 通过调用
set_intriniscs_from_K_matrix
来设置相机的 K 矩阵。 - 相机的位姿由其世界矩阵定义,在这种情况下,它只是单位矩阵。
- 将相机源帧更改为匹配 Blender 帧(这将从 OpenCV 坐标系转换为 Blender 的坐标系)。
- 最后,将这个新的相机矩阵添加到位姿中,即可渲染。
|
BOP数据集是一个公共的工业场景物体姿态估计数据集,包含了80个具有挑战性的工业部件,每个部件都有不同的材质、变形、表面纹理和反光性质。BOP数据集中每个部件都拍摄了数百张带有真实噪声深度信息和RGB图像的灰度图。此外,BOP数据集还提供了每个部件的正式模型,即CAD文件,以便将您的方法与CAD进行比较。BOP的主要目的是为评估工业场景物体姿态估计算法提供标准化基准。
- 保存 BOP 数据集中提供的所有姿态和相机信息。
"m2mm"
将姿态转换为毫米,与原始的 BOP 标注一致。如果想要使用米作为单位则设置为 False。"append_to_existing_output"
表示如果选择了相同的输出文件夹,则数据将被追加而不是覆盖。