def property_reference(run_name="property_reference"): """Produces identical visualization to small_scale, but does not store repeated properties of ``vertex_positions`` and ``vertex_normals``. """ logdir = os.path.join(BASE_LOGDIR, run_name) writer = SummaryWriter(logdir) cube = o3d.geometry.TriangleMesh.create_box(1, 2, 4) cube.compute_vertex_normals() cylinder = o3d.geometry.TriangleMesh.create_cylinder(radius=1.0, height=2.0, resolution=20, split=4) cylinder.compute_vertex_normals() colors = [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)] for step in range(3): cube.paint_uniform_color(colors[step]) cube_summary = to_dict_batch([cube]) if step > 0: cube_summary['vertex_positions'] = 0 cube_summary['vertex_normals'] = 0 writer.add_3d('cube', cube_summary, step=step) cylinder.paint_uniform_color(colors[step]) cylinder_summary = to_dict_batch([cylinder]) if step > 0: cylinder_summary['vertex_positions'] = 0 cylinder_summary['vertex_normals'] = 0 writer.add_3d('cylinder', cylinder_summary, step=step)
def small_scale(run_name="small_scale"): """Basic demo with cube and cylinder with normals and colors. """ logdir = os.path.join(BASE_LOGDIR, run_name) writer = tf.summary.create_file_writer(logdir) cube = o3d.geometry.TriangleMesh.create_box(1, 2, 4, create_uv_map=True) cube.compute_vertex_normals() cylinder = o3d.geometry.TriangleMesh.create_cylinder(radius=1.0, height=2.0, resolution=20, split=4, create_uv_map=True) cylinder.compute_vertex_normals() colors = [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)] with writer.as_default(): for step in range(3): cube.paint_uniform_color(colors[step]) summary.add_3d('cube', to_dict_batch([cube]), step=step, logdir=logdir) cylinder.paint_uniform_color(colors[step]) summary.add_3d('cylinder', to_dict_batch([cylinder]), step=step, logdir=logdir)
def large_scale(n_steps=16, batch_size=1, base_resolution=200, run_name="large_scale"): """Generate a large scale summary. Geometry resolution increases linearly with step. Each element in a batch is painted a different color. """ logdir = os.path.join(BASE_LOGDIR, run_name) writer = tf.summary.create_file_writer(logdir) colors = [] for k in range(batch_size): t = k * np.pi / batch_size colors.append(((1 + np.sin(t)) / 2, (1 + np.cos(t)) / 2, t / np.pi)) with writer.as_default(): for step in range(n_steps): resolution = base_resolution * (step + 1) cylinder_list = [] moebius_list = [] cylinder = o3d.geometry.TriangleMesh.create_cylinder( radius=1.0, height=2.0, resolution=resolution, split=4) cylinder.compute_vertex_normals() moebius = o3d.geometry.TriangleMesh.create_moebius( length_split=int(3.5 * resolution), width_split=int(0.75 * resolution), twists=1, raidus=1, flatness=1, width=1, scale=1) moebius.compute_vertex_normals() for b in range(batch_size): cylinder_list.append(copy.deepcopy(cylinder)) cylinder_list[b].paint_uniform_color(colors[b]) moebius_list.append(copy.deepcopy(moebius)) moebius_list[b].paint_uniform_color(colors[b]) summary.add_3d('cylinder', to_dict_batch(cylinder_list), step=step, logdir=logdir, max_outputs=batch_size) summary.add_3d('moebius', to_dict_batch(moebius_list), step=step, logdir=logdir, max_outputs=batch_size)
def test_tensorflow_summary(geometry_data, tmp_path): """Test writing summary from TensorFlow """ tf = pytest.importorskip("tensorflow") logdir = str(tmp_path) writer = tf.summary.create_file_writer(logdir) rng = np.random.default_rng() tensor_converter = (tf.convert_to_tensor, o3d.core.Tensor.from_numpy, np.array) cube, material = geometry_data['cube'], geometry_data['material'] cube_ls, material_ls = geometry_data['cube_ls'], geometry_data[ 'material_ls'] colors = geometry_data['colors'] max_outputs = geometry_data['max_outputs'] with writer.as_default(): for step in range(3): cube[0].paint_uniform_color(colors[step][0]) cube[1].paint_uniform_color(colors[step][1]) cube_summary = to_dict_batch(cube) cube_summary.update(material) # Randomly convert to TF, Open3D, Numpy tensors, or use property # reference if step > 0: cube_summary['vertex_positions'] = 0 cube_summary['vertex_normals'] = 0 cube_summary['vertex_colors'] = rng.choice(tensor_converter)( cube_summary['vertex_colors']) else: for prop, tensor in cube_summary.items(): # skip material scalar and vector props if (not prop.startswith("material_") or prop.startswith("material_texture_map_")): cube_summary[prop] = rng.choice(tensor_converter)( tensor) summary.add_3d('cube', cube_summary, step=step, logdir=logdir, max_outputs=max_outputs) for key in tuple(cube_summary): # Convert to PointCloud if key.startswith(('triangle_', 'material_texture_map_')): cube_summary.pop(key) summary.add_3d('cube_pcd', cube_summary, step=step, logdir=logdir, max_outputs=max_outputs) cube_ls[0].paint_uniform_color(colors[step][0]) cube_ls[1].paint_uniform_color(colors[step][1]) cube_ls_summary = to_dict_batch(cube_ls) cube_ls_summary.update(material_ls) for prop, tensor in cube_ls_summary.items(): if (not prop.startswith("material_") or prop.startswith("material_texture_map_")): cube_ls_summary[prop] = rng.choice(tensor_converter)( tensor) summary.add_3d('cube_ls', cube_ls_summary, step=step, logdir=logdir, max_outputs=max_outputs) sleep(0.25) # msgpack writing disk flush time dirpath_ref = [ logdir, os.path.join(logdir, 'plugins'), os.path.join(logdir, 'plugins/Open3D') ] filenames_ref = [['events.out.tfevents.*'], [], ['cube.*.msgpack']] dirpath, filenames = [], [] for dp, unused_dn, fn in os.walk(logdir): dirpath.append(dp) filenames.append(fn) assert (dirpath[:2] == dirpath_ref[:2] and dirpath[2][0][:20] == dirpath_ref[2][0][:20]) assert filenames[0][0][:20] == filenames_ref[0][0][:20] assert set(x.split('.')[0] for x in filenames[2]) == set( ('cube', 'cube_pcd', 'cube_ls')) assert filenames_ref[2][0][-8:] == '.msgpack' # Note: The event file written during this test cannot be reliably verified # in the same Python process, since it's usually buffered by GFile / Python # / OS and written to disk in increments of the filesystem blocksize. # Complete write is guaranteed after Python has exited. shutil.rmtree(logdir)
def test_pytorch_summary(geometry_data, tmp_path): """Test writing summary from PyTorch""" torch = pytest.importorskip("torch") torch_tb = pytest.importorskip("torch.utils.tensorboard") SummaryWriter = torch_tb.SummaryWriter logdir = str(tmp_path) writer = SummaryWriter(logdir) rng = np.random.default_rng() tensor_converter = (torch.from_numpy, o3d.core.Tensor.from_numpy, np.array) cube, material = geometry_data['cube'], geometry_data['material'] cube_custom_prop = geometry_data['cube_custom_prop'] cube_ls, material_ls = geometry_data['cube_ls'], geometry_data[ 'material_ls'] colors = geometry_data['colors'] cube_labels = geometry_data['cube_labels'] label_to_names = geometry_data['label_to_names'] max_outputs = geometry_data['max_outputs'] bboxes = geometry_data['bboxes'] for step in range(3): cube[0].paint_uniform_color(colors[step][0]) cube[1].paint_uniform_color(colors[step][1]) cube_summary = to_dict_batch(cube) cube_summary.update(material) # Randomly convert to PyTorch, Open3D, Numpy tensors, or use property # reference if step > 0: cube_summary['vertex_positions'] = 0 cube_summary['vertex_normals'] = 0 cube_summary['vertex_colors'] = rng.choice(tensor_converter)( cube_summary['vertex_colors']) else: for prop, tensor in cube_summary.items(): # skip material scalar and vector props if (not prop.startswith("material_") or prop.startswith("material_texture_map_")): cube_summary[prop] = rng.choice(tensor_converter)(tensor) writer.add_3d('cube', cube_summary, step=step, max_outputs=max_outputs) for key in tuple(cube_summary): # Convert to PointCloud if key.startswith(('triangle_', 'material_texture_map_')): cube_summary.pop(key) cube_summary['vertex_custom'] = tuple( rng.choice(tensor_converter)(tensor) for tensor in cube_custom_prop[step]) # Add custom prop cube_summary['vertex_labels'] = tuple( rng.choice(tensor_converter)(tensor) for tensor in cube_labels[step]) # Add labels writer.add_3d('cube_pcd', cube_summary, step=step, max_outputs=max_outputs, label_to_names=label_to_names) cube_ls[0].paint_uniform_color(colors[step][0]) cube_ls[1].paint_uniform_color(colors[step][1]) cube_ls_summary = to_dict_batch(cube_ls) cube_ls_summary.update(material_ls) for prop, tensor in cube_ls_summary.items(): if (not prop.startswith("material_") or prop.startswith("material_texture_map_")): cube_ls_summary[prop] = rng.choice(tensor_converter)(tensor) writer.add_3d('cube_ls', cube_ls_summary, step=step, max_outputs=max_outputs) if len(bboxes) > 0: writer.add_3d('bboxes', {'bboxes': bboxes[step]}, step=step, logdir=logdir, max_outputs=max_outputs, label_to_names=label_to_names) sleep(0.25) # msgpack writing disk flush time tags_ref = geometry_data['tags'] dirpath_ref = [ logdir, os.path.join(logdir, 'plugins'), os.path.join(logdir, 'plugins/Open3D') ] filenames_ref = geometry_data['filenames'] dirpath, filenames = [], [] for dp, unused_dn, fn in os.walk(logdir): dirpath.append(dp) filenames.append(fn) assert dirpath == dirpath_ref assert filenames[0][0].startswith(filenames_ref[0][0][:20]) assert sorted(x.split('.')[0] for x in filenames[2]) == tags_ref assert all(fn.endswith('.msgpack') for fn in filenames[2]) # Note: The event file written during this test cannot be reliably verified # in the same Python process, since it's usually buffered by GFile / Python # / OS and written to disk in increments of the filesystem blocksize. # Complete write is guaranteed after Python has exited. shutil.rmtree(logdir)
def test_pytorch_summary(geometry_data): """Test writing summary from PyTorch""" torch = pytest.importorskip("torch") torch_tb = pytest.importorskip("torch.utils.tensorboard") SummaryWriter = torch_tb.SummaryWriter logdir = tempfile.mkdtemp(prefix='open3d_tb_plugin_test') writer = SummaryWriter(logdir) rng = np.random tensor_converter = (torch.from_numpy, o3d.core.Tensor.from_numpy, np.array) cube = geometry_data['cube'] cube_ls = geometry_data['cube_ls'] colors = geometry_data['colors'] max_outputs = geometry_data['max_outputs'] for step in range(3): cube[0].paint_uniform_color(colors[step][0]) cube[1].paint_uniform_color(colors[step][1]) cube_summary = to_dict_batch(cube) # Randomly convert to PyTorch, Open3D, Numpy tensors, or use property # reference if step > 0: cube_summary['vertex_positions'] = 0 cube_summary['vertex_normals'] = 0 cube_summary['vertex_colors'] = rng.choice(tensor_converter)( cube_summary['vertex_colors']) else: for prop, tensor in cube_summary.items(): cube_summary[prop] = rng.choice(tensor_converter)(tensor) writer.add_3d('cube', cube_summary, step=step, max_outputs=max_outputs) cube_summary.pop('triangle_indices') # Convert to PointCloud writer.add_3d('cube_pcd', cube_summary, step=step, max_outputs=max_outputs) cube_ls[0].paint_uniform_color(colors[step][0]) cube_ls[1].paint_uniform_color(colors[step][1]) cube_ls_summary = to_dict_batch(cube_ls) for prop, tensor in cube_ls_summary.items(): cube_ls_summary[prop] = rng.choice(tensor_converter)(tensor) writer.add_3d('cube_ls', cube_ls_summary, step=step, max_outputs=max_outputs) sleep(0.25) # msgpack writing disk flush time dirpath_ref = [ logdir, os.path.join(logdir, 'plugins'), os.path.join(logdir, 'plugins/Open3D') ] filenames_ref = [['events.out.tfevents.*'], [], ['cube.*.msgpack']] dirpath, filenames = [], [] for dp, unused_dn, fn in os.walk(logdir): dirpath.append(dp) filenames.append(fn) assert (dirpath[:2] == dirpath_ref[:2] and dirpath[2][0][:20] == dirpath_ref[2][0][:20]) assert filenames[0][0][:20] == filenames_ref[0][0][:20] assert set(x.split('.')[0] for x in filenames[2]) == set( ('cube', 'cube_pcd', 'cube_ls')) assert filenames_ref[2][0][-8:] == '.msgpack' # Note: The event file written during this test cannot be reliably verified # in the same Python process, since it's usually buffered by GFile / Python # / OS and written to disk in increments of the filesystem blocksize. # Complete write is guaranteed after Python has exited. shutil.rmtree(logdir)