def parse_synth_out(synth_out_ifp): points3D = [] with open(synth_out_ifp, "r") as input_file: meta_data_line = input_file.readline() num_cameras, num_points = MVEFileHandler.readline_as_numbers( input_file, target_type=int) # The camera information provided in the synth_0.out file is incomplete # Thus, we use the camera information provided in the view folders # Consume the lines corresponding to the (incomplete) camera information for cam_idx in range(num_cameras): intrinsic_line = MVEFileHandler.readline_as_numbers( input_file, target_type=float) rotation_mat = MVEFileHandler.parse_rotation_matrix(input_file) camera_translation = np.asarray( MVEFileHandler.readline_as_numbers(input_file, target_type=float)) for point_idx in range(num_points): coord = MVEFileHandler.readline_as_numbers(input_file, target_type=float) color = MVEFileHandler.readline_as_numbers(input_file, target_type=int) measurement_line = MVEFileHandler.readline_as_numbers( input_file, target_type=int) point = Point(coord=coord, color=color, id=point_idx, scalars=[]) points3D.append(point) return points3D
def _parse_points_from_json_data(json_data, image_index_to_camera_index, op): points = [] is_valid_file = "structure" in json_data if not is_valid_file: log_report( "ERROR", "FILE FORMAT ERROR: Incorrect SfM/JSON file. Must contain " + " the SfM reconstruction results: structure.", op, ) return points structure = json_data["structure"] for json_point in structure: custom_point = Point( coord=np.array(json_point["X"], dtype=float), color=np.array(json_point["color"], dtype=int), id=int(json_point["landmarkId"]), scalars=[], ) points.append(custom_point) return points
def add_points_as_object_with_particle_system( points, reconstruction_collection, mesh_type="CUBE", point_extent=0.01, add_particle_color_emission=True, particle_overwrite_color=None, op=None, ): """Add a point cloud as particle system.""" log_report("INFO", "Adding Points as Particle System: ...", op) stop_watch = StopWatch() # The particle systems in Blender do not work for large particle numbers # (see https://developer.blender.org/T81103). Thus, we represent large # point clouds with multiple smaller particle systems. max_number_particles = 10000 particle_system_collection = add_collection("Particle System", reconstruction_collection) point_cloud_obj_list = [] for i in range(0, len(points), max_number_particles): particle_obj_name = f"Particle Shape {i}" particle_material_name = f"Point Cloud Material {i}" point_cloud_obj_name = f"Particle Point Cloud {i}" points_subset = points[i:i + max_number_particles] coords, colors = Point.split_points(points_subset, normalize_colors=True) particle_obj = _add_particle_obj( colors, particle_obj_name, particle_material_name, particle_overwrite_color, add_particle_color_emission, mesh_type, point_extent, particle_system_collection, ) point_cloud_obj = _add_particle_system_obj( coords, particle_obj, point_cloud_obj_name, particle_system_collection, ) point_cloud_obj_list.append(point_cloud_obj) bpy.context.view_layer.update() log_report("INFO", "Duration: " + str(stop_watch.get_elapsed_time()), op) log_report("INFO", "Adding Points as Particle System: Done", op) return point_cloud_obj_list
def get_selected_cameras_and_vertices_of_meshes(self, odp): """Get selected cameras and vertices.""" log_report("INFO", "get_selected_cameras_and_vertices_of_meshes: ...", self) cameras = [] points = [] point_index = 0 camera_index = 0 for obj in bpy.context.selected_objects: if obj.type == "CAMERA": obj_name = str(obj.name).replace(" ", "_") log_report("INFO", "obj_name: " + obj_name, self) calibration_mat = self._get_calibration_mat(obj) # log_report('INFO', 'calibration_mat:', self) # log_report('INFO', str(calibration_mat), self) camera_matrix_computer_vision = ( self._get_computer_vision_camera_matrix(obj)) cam = Camera() cam.id = camera_index cam.set_relative_fp(obj_name, Camera.IMAGE_FP_TYPE_NAME) cam.image_dp = odp cam.width = bpy.context.scene.render.resolution_x cam.height = bpy.context.scene.render.resolution_y cam.set_calibration(calibration_mat, radial_distortion=0) cam.set_4x4_cam_to_world_mat(camera_matrix_computer_vision) cameras.append(cam) camera_index += 1 else: if obj.data is not None: obj_points = [] for vert in obj.data.vertices: coord_world = obj.matrix_world @ vert.co obj_points.append( Point( coord=coord_world, color=[0, 255, 0], id=point_index, scalars=[], )) point_index += 1 points += obj_points log_report( "INFO", "get_selected_cameras_and_vertices_of_meshes: Done", self, ) return cameras, points
def _parse_points(json_data, op): points = [] json_points = json_data["points"] for point_id in json_points: json_point = json_points[point_id] custom_point = Point( coord=np.array(json_point["coordinates"], dtype=float), color=np.array(json_point["color"], dtype=int), id=point_id, scalars=[], ) points.append(custom_point) return points
def _convert_points(id_to_col_points3D): # From photogrammetry_importer\ext\read_write_model.py # Point3D = collections.namedtuple( # "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"]) col_points3D = id_to_col_points3D.values() points3D = [] for col_point3D in col_points3D: current_point = Point( coord=col_point3D.xyz, color=col_point3D.rgb, id=col_point3D.id, scalars=None, ) points3D.append(current_point) return points3D
def _parse_nvm_points(input_file, num_3D_points): points = [] for point_index in range(num_3D_points): # From the VSFM docs: # <Point> = <XYZ> <RGB> <number of measurements> <List of Measurements> point_line = input_file.readline() point_line_elements = (point_line.rstrip()).split() xyz_vec = list(map(float, point_line_elements[0:3])) rgb_vec = list(map(int, point_line_elements[3:6])) current_point = Point(coord=xyz_vec, color=rgb_vec, id=point_index, scalars=None) points.append(current_point) return points
def draw_points( points, add_points_to_point_cloud_handle, reconstruction_collection=None, object_anchor_handle_name="OpenGL Point Cloud", op=None, ): """Draw points using OpenGL.""" log_report("INFO", "Add particle draw handlers", op) coords, colors = Point.split_points(points, normalize_colors=True) object_anchor_handle = _draw_coords_with_color( coords, colors, add_points_to_point_cloud_handle, reconstruction_collection, object_anchor_handle_name, op=op, ) return object_anchor_handle
def draw_points( op, points, add_points_to_point_cloud_handle, reconstruction_collection=None, object_anchor_handle_name="OpenGL Point Cloud", ): log_report("INFO", "Add particle draw handlers", op) coords, colors = Point.split_points(points) object_anchor_handle = draw_coords_with_color( op, coords, colors, add_points_to_point_cloud_handle, reconstruction_collection, object_anchor_handle_name, ) return object_anchor_handle
def add_points_as_mesh_vertices( points, reconstruction_collection, add_color_as_custom_property=True, op=None, ): """Add a point cloud as mesh.""" log_report("INFO", "Adding Points as Mesh: ...", op) stop_watch = StopWatch() point_cloud_obj_name = "Mesh Point Cloud" point_cloud_mesh = bpy.data.meshes.new(point_cloud_obj_name) point_cloud_mesh.update() point_cloud_mesh.validate() coords, colors = Point.split_points(points, normalize_colors=False) point_cloud_mesh.from_pydata(coords, [], []) point_cloud_obj = add_obj(point_cloud_mesh, point_cloud_obj_name, reconstruction_collection) if add_color_as_custom_property: point_cloud_obj["colors"] = colors log_report("INFO", "Duration: " + str(stop_watch.get_elapsed_time()), op) log_report("INFO", "Adding Points as Mesh: Done", op) return point_cloud_obj
def parse_point_data_file(ifp, op): log_report("INFO", "Parse Point Data File: ...") # https://pyntcloud.readthedocs.io/en/latest/io.html # https://www.cloudcompare.org/doc/wiki/index.php?title=FILE_I/O module_spec = importlib.util.find_spec("pyntcloud") if module_spec is None: log_report( "ERROR", "Importing this file type requires the pyntcloud library.", op, ) assert False from pyntcloud import PyntCloud assert os.path.isfile(ifp) ext = os.path.splitext(ifp)[1].lower() if ext in [".asc", ".pts"]: sep = " " data_semantics = ( PointDataFileHandler.get_data_semantics_from_ascii( ifp, sep, has_header=True)) names = PointDataFileHandler.convert_data_semantics_to_list( data_semantics) point_cloud = PyntCloud.from_file(ifp, sep=sep, header=0, names=names) pseudo_color = data_semantics.pseudo_color elif ext == ".csv": sep = "," data_semantics = ( PointDataFileHandler.get_data_semantics_from_ascii( ifp, sep, has_header=False)) names = PointDataFileHandler.convert_data_semantics_to_list( data_semantics) point_cloud = PyntCloud.from_file(ifp, sep=sep, header=0, names=names) pseudo_color = data_semantics.pseudo_color else: pseudo_color = False point_cloud = PyntCloud.from_file(ifp) xyz_arr = point_cloud.points.loc[:, ["x", "y", "z"]].to_numpy() if set(["red", "green", "blue"]).issubset(point_cloud.points.columns): color_arr = point_cloud.points.loc[:, ["red", "green", "blue" ]].to_numpy() if pseudo_color: color_arr *= 255 else: color_arr = np.ones_like(xyz_arr) * 255 num_points = xyz_arr.shape[0] points = [] for idx in range(num_points): point = Point( coord=xyz_arr[idx].astype("float64"), color=color_arr[idx].astype("int"), id=idx, scalars=dict(), ) points.append(point) log_report("INFO", f"Number Points {len(points)}") log_report("INFO", "Parse Point Data File: Done") return points
def __ply_data_vertices_to_vetex_list(ply_data): vertex_data_type_names = ply_data["vertex"].data.dtype.names use_color = False if ( "red" in vertex_data_type_names and "green" in vertex_data_type_names and "blue" in vertex_data_type_names ): use_color = True vertices = [] value_keys = [ x for x, y in sorted( ply_data["vertex"].data.dtype.fields.items(), key=lambda k: k[1], ) ] non_scalar_value_keys = [ "x", "y", "z", "red", "green", "blue", "nx", "ny", "nz", "measurements", ] scalar_value_keys = [ value_key for value_key in value_keys if not value_key in non_scalar_value_keys ] log_report( "INFO", "Found the following vertex properties: " + str(value_keys) ) # scalar_value_keys = [value_key for (value_key, some_value) in ] # logger.info(scalar_value_keys) log_report( "INFO", "Found " + str(len(ply_data["vertex"].data)) + " vertices" ) for point_index, line in enumerate(ply_data["vertex"].data): coord = np.array([line["x"], line["y"], line["z"]]) if use_color: color = np.array([line["red"], line["green"], line["blue"]]) else: color = np.array([255, 255, 255]) scalars = dict() for scalar_value_key in scalar_value_keys: scalars[scalar_value_key] = line[scalar_value_key] current_point = Point( coord=coord, color=color, id=point_index, scalars=None ) vertices.append(current_point) ply_data_vertex_dtype = ply_data["vertex"].dtype ply_data_vertex_data_dtype = ply_data["vertex"].data.dtype return vertices, ply_data_vertex_dtype, ply_data_vertex_data_dtype
def write_ply_file_from_vertex_mat(output_path_to_file, vertex_mat): vertices = [] for entry in vertex_mat: vertices.append(Point(coord=entry)) PLYFileHandler.write_ply_file(output_path_to_file, vertices)
def parse_points(json_data, op, view_index_to_absolute_fp=None): compute_color = True try: from PIL import Image, ImageFile ImageFile.LOAD_TRUNCATED_IMAGES = True except ImportError: log_report( "WARNING", "Can not compute point cloud color information, since Pillow is not installed.", op, ) compute_color = False if view_index_to_absolute_fp is None: log_report( "WARNING", "Can not compute point cloud color information, since path to images is not correctly set.", op, ) compute_color = False if compute_color: log_report( "INFO", "Try to collect color information from files (this might take a while)", op, ) view_index_to_image = {} for view_index, absolute_fp in view_index_to_absolute_fp.items(): if os.path.isfile(absolute_fp): pil_image = Image.open(absolute_fp) view_index_to_image[view_index] = pil_image else: log_report( "WARNING", "Can not compute point cloud color information, since image file path is incorrect.", op, ) compute_color = False break if compute_color: log_report( "INFO", "Compute color information from files (this might take a while)", op, ) points = [] structure = json_data["structure"] for json_point in structure: r = g = b = 0 # color information can only be computed if input files are provided if compute_color: for observation in json_point["value"]["observations"]: view_index = int(observation["key"]) # REMARK: The order of ndarray.shape (first height, then width) is complimentary to # pils image.size (first width, then height). # That means # height, width = segmentation_as_matrix.shape # width, height = image.size # Therefore: x_in_openmvg_file == x_image == y_ndarray # and y_in_openmvg_file == y_image == x_ndarray x_in_json_file = float( observation["value"]["x"][0]) # x has index 0 y_in_json_file = float( observation["value"]["x"][1]) # y has index 1 current_image = view_index_to_image[view_index] current_r, current_g, current_b = current_image.getpixel( (x_in_json_file, y_in_json_file)) r += current_r g += current_g b += current_b # normalize the rgb values amount_observations = len(json_point["value"]["observations"]) r /= amount_observations g /= amount_observations b /= amount_observations custom_point = Point( coord=np.array(json_point["value"]["X"], dtype=float), color=np.array([r, g, b], dtype=int), id=int(json_point["key"]), scalars=[], ) points.append(custom_point) return points