Beispiel #1
0
    def parse_ply_file_extended(ifp):

        logger.info("Parse PLY File: ...")

        ply_data = PlyData.read(ifp)

        (
            vertices,
            ply_data_vertex_dtype,
            ply_data_vertex_data_dtype,
        ) = PLYFileHandler.__ply_data_vertices_to_vetex_list(ply_data)
        (
            faces,
            ply_data_face_type,
            ply_data_face_data_type,
        ) = PLYFileHandler.__ply_data_faces_to_face_list(ply_data)

        logger.info("Parse PLY File: Done")

        # return always 6 arguments. However, the latter may be empty
        return (
            vertices,
            ply_data_vertex_dtype,
            ply_data_vertex_data_dtype,
            faces,
            ply_data_face_type,
            ply_data_face_data_type,
        )
    def refine_mesh(
        self,
        openmvs_workspace_dp,
        openmvs_ifn,
        openmvs_ofn,
        lazy=False,
        mesh_ifp=None,
        use_cuda=False,
    ):
        # logger.info('refine_mesh: ...')

        # https://github.com/cdcseacave/openMVS/blob/master/apps/RefineMesh/RefineMesh.cpp
        # https://github.com/cdcseacave/openMVS/wiki/Usage
        if (not os.path.isfile(os.path.join(openmvs_workspace_dp, openmvs_ofn))
                or not lazy):
            refine_mesh_call = [
                self.refine_mesh_fp,
                "-i",
                openmvs_ifn,
                "-w",
                openmvs_workspace_dp,
                "-o",
                openmvs_ofn,
                "--use-cuda",
                str(int(use_cuda)),
            ]

            if mesh_ifp is not None:
                refine_mesh_call += ["--mesh-file", mesh_ifp]

            logger.info(str(refine_mesh_call))
            refine_mesh_proc = subprocess.Popen(refine_mesh_call)
            refine_mesh_proc.wait()
Beispiel #3
0
    def compute_cleaned_mesh(
        self,
        mesh_ifp,
        mesh_ofp,
        threshold=1.0,
        component_size=1000,
        delete_color=True,
        delete_scale=True,
        delete_conf=True,
    ):
        logger.info("compute_cleaned_mesh: ...")
        clean_call = [
            self.meshclean_fp,
            # Threshold on the geometry confidence [1.0]
            # -t, --threshold=ARG
            "--threshold=" + str(threshold),
            # Minimum number of vertices per component [1000]
            # -c, --component-size=ARG
            "--component-size=" + str(component_size),
        ]
        if delete_color:
            clean_call += ["--delete-color"]
        if delete_scale:
            clean_call += ["--delete-scale"]
        if delete_conf:
            clean_call += ["--delete-conf"]

        clean_call += [mesh_ifp, mesh_ofp]

        subprocess.call(clean_call)
        logger.info("compute_cleaned_mesh: Done")
Beispiel #4
0
    def write_camera_ply_file(ofp, cameras, plain_text_output=True):

        ply_data_vertex_data_dtype_list = [
            ("x", "<f4"),
            ("y", "<f4"),
            ("z", "<f4"),
        ]
        ply_data_vertex_data_dtype_list += [
            ("red", "u1"),
            ("green", "u1"),
            ("blue", "u1"),
        ]
        ply_data_vertex_data_dtype_list += [
            ("nx", "<f4"),
            ("ny", "<f4"),
            ("nz", "<f4"),
        ]

        ply_data_vertex_data_dtype = np.dtype(ply_data_vertex_data_dtype_list)

        output_ply_data_vertex_element = (
            PLYFileHandler.__cameras_2_ply_vertex_element(
                cameras, ply_data_vertex_data_dtype))

        # [('x', '<f4'), ('y', '<f4'), ('z', '<f4'), ('red', 'u1'), ('green', 'u1'), ('blue', 'u1')]

        logger.info("Write (Camera) File With Vertices Only (no faces)")
        output_data = PlyData([output_ply_data_vertex_element],
                              text=plain_text_output)

        output_data.write(ofp)
    def convert_colmap_to_openMVS(
        self,
        colmap_dense_idp,
        openmvs_workspace_dp,
        openmvs_ofn,
        image_folder="images/",
        lazy=False,
    ):

        # logger.info('convert_colmap_to_openMVS: ...')
        openmvs_ofp = os.path.join(openmvs_workspace_dp, openmvs_ofn)
        if not os.path.isfile(openmvs_ofp) or not lazy:
            colmap_to_openmvs_call = [
                self.interface_colmap_fp,
                "-i",
                colmap_dense_idp,
                "--image-folder",
                image_folder,
                "-w",
                openmvs_workspace_dp,
                "-o",
                openmvs_ofn,
            ]

            logger.info(str(colmap_to_openmvs_call))
            colmap_to_openmvs_proc = subprocess.Popen(colmap_to_openmvs_call)
            colmap_to_openmvs_proc.wait()
Beispiel #6
0
def convert_vissat_config_json_to_geojson(vissat_config_json_ifp, geojson_ofp):

    with open(vissat_config_json_ifp) as json_file:
        vissat_config_json = json.load(json_file)

    bbx_utm = vissat_config_json["bounding_box"]
    zone_number = bbx_utm["zone_number"]
    hemisphere = bbx_utm["hemisphere"]
    ul_easting = bbx_utm["ul_easting"]
    ul_northing = bbx_utm["ul_northing"]

    logger.info("utm: {}".format(
        ([ul_easting, ul_northing, zone_number, hemisphere])))

    # See write_aoi() in stereo_pipeline.py
    lr_easting = ul_easting + bbx_utm["width"]
    lr_northing = ul_northing - bbx_utm["height"]

    # compute a lat_lon bbx
    corners_easting = [ul_easting, lr_easting, lr_easting, ul_easting]
    corners_northing = [ul_northing, ul_northing, lr_northing, lr_northing]
    corners_lat = []
    corners_lon = []
    northern = True if hemisphere == "N" else False
    for i in range(4):
        lat, lon = utm.to_latlon(
            corners_easting[i],
            corners_northing[i],
            zone_number,
            northern=northern,
        )
        corners_lat.append(lat)
        corners_lon.append(lon)
    lat_min = min(corners_lat)
    lat_max = max(corners_lat)
    lon_min = min(corners_lon)
    lon_max = max(corners_lon)

    lat, lon = utm_to_latlon(ul_easting, ul_northing, zone_number, hemisphere)
    logger.info("lat lon: {}".format([lat, lon]))

    vertex_list = [
        (lon_min, lat_min),
        (lon_min, lat_max),
        (lon_max, lat_max),
        (lon_max, lat_min),
    ]

    # A LineString only marks the border of the area (but is not a closed
    # shape, i.e. no loop).
    # my_linestring = geojson.LineString(vertex_list)
    # geojson_str = geojson.dumps(my_linestring, sort_keys=True)

    # A polygon is filled by default in QGIS (style can be changed in the
    # raster layer properties)
    my_polygon = geojson.Polygon([vertex_list])
    geojson_str = geojson.dumps(my_polygon, sort_keys=True)

    with open(geojson_ofp, "w") as geojson_file:
        geojson_file.write(geojson_str)
Beispiel #7
0
    def write_colmap_model(odp,
                           cameras,
                           points,
                           colmap_camera_model_name="SIMPLE_PINHOLE"):
        logger.info("Write Colmap model folder: " + odp)

        if not os.path.isdir(odp):
            os.mkdir(odp)

        # From ssr\ext\read_write_model.py
        #   CameraModel = collections.namedtuple(
        #       "CameraModel", ["model_id", "model_name", "num_params"])
        #   Camera = collections.namedtuple(
        #       "Camera", ["id", "model", "width", "height", "params"])
        #   BaseImage = collections.namedtuple(
        #       "Image", ["id", "qvec", "tvec", "camera_id", "name", "xys", "point3D_ids"])
        #   Point3D = collections.namedtuple(
        #       "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"])

        (
            colmap_cams,
            colmap_images,
        ) = ColmapFileHandler.convert_cams_to_colmap_cams_and_colmap_images(
            cameras, colmap_camera_model_name)

        colmap_points3D = ColmapFileHandler.convert_points_to_colmap_points(
            points)

        write_model(colmap_cams,
                    colmap_images,
                    colmap_points3D,
                    odp,
                    ext=".txt")
Beispiel #8
0
    def parse_colmap_model_folder(model_idp, image_idp):

        logger.info("Parse Colmap model folder: " + model_idp)

        ifp_s = os.listdir(model_idp)

        if (len(
                set(ifp_s).intersection(
                    ["cameras.txt", "images.txt", "points3D.txt"])) == 3):
            ext = ".txt"
        elif (len(
                set(ifp_s).intersection(
                    ["cameras.bin", "images.bin", "points3D.bin"])) == 3):
            ext = ".bin"
        else:
            assert False  # No valid model folder

        # Cameras represent information about the camera model.
        # Images contain pose information.
        id_to_col_cameras, id_to_col_images, id_to_col_points3D = read_model(
            model_idp, ext=ext)
        cameras = ColmapFileHandler.convert_colmap_cams_to_cams(
            id_to_col_cameras, id_to_col_images, image_idp)
        points3D = ColmapFileHandler.convert_colmap_points_to_points(
            id_to_col_points3D)

        return cameras, points3D
Beispiel #9
0
    def __ply_data_faces_to_face_list(ply_data):
        faces = []
        ply_data_face_type = None
        ply_data_face_data_type = None
        if "face" in ply_data:
            # read faces
            ply_data_face_type = ply_data["face"].dtype
            logger.info("Found " + str(len(ply_data["face"].data)) + " faces")
            for line in ply_data["face"].data["vertex_indices"]:
                current_face = Face()
                current_face.vertex_indices = np.array(
                    [line[0], line[1], line[2]])
                faces.append(current_face)

            ply_data_face_data_type = [("vertex_indices", "i4", (3, ))]
            face_names = ply_data["face"].data.dtype.names
            if ("red" in face_names and "green" in face_names
                    and "blue" in face_names):
                ply_data_face_data_type = [
                    ("vertex_indices", "i4", (3, )),
                    ("red", "u1"),
                    ("green", "u1"),
                    ("blue", "u1"),
                ]

        return faces, ply_data_face_type, ply_data_face_data_type
    def compute_texturing_with_mve(colmap_idp,
                                   mesh_ifp,
                                   texturing_odp,
                                   lazy=True):
        logger.info("compute_texturing_with_mve: ...")
        logger.info(f"colmap_idp: {colmap_idp}")
        logger.info(f"mesh_ifp: {mesh_ifp}")
        logger.info(f"texturing_odp: {texturing_odp}")

        mve_odp = os.path.dirname(texturing_odp)
        mve_mvs_reconstructor = MVEMVSReconstructor()

        # Import the colmap reconstruction into MVE exactly once,
        # since it is identical for all reconstructions.
        if not os.path.isdir(mve_odp):
            mve_mvs_reconstructor.create_scene_from_sfm_result(
                colmap_idp, mve_odp, downscale_level=-1, lazy=lazy)

        mve_mvs_reconstructor.compute_texture(
            mve_workspace=mve_odp,
            mesh_cleaned_ply_ifp=mesh_ifp,
            mesh_textured_odp=texturing_odp,
        )

        logger.info("compute_texturing_with_mve: Done")
Beispiel #11
0
 def compute_fssr_mesh_from_point_cloud(
     self, mve_point_cloud_with_scale_ply_fp, mesh_ply_fp
 ):
     logger.info("compute_mesh_from_point_cloud: ...")
     subprocess.call(
         [self.fssrecon_fp, mve_point_cloud_with_scale_ply_fp, mesh_ply_fp]
     )
     logger.info("compute_mesh_from_point_cloud: Done")
Beispiel #12
0
 def import_images_to_scene(self, image_idp):
     logger.info("import_images_to_scene: ...")
     make_scene_call = [
         self.make_scene_fp,
         "--images-only",
         image_idp,
         self.workspace_folder,
     ]
     logger.vinfo("make_scene_call", make_scene_call)
     subprocess.call(make_scene_call)
Beispiel #13
0
    def compute_mesh_with_openmvs(colmap_idp,
                                  odp,
                                  mesh_ply_ofn,
                                  plain_mesh_ply_ofn,
                                  lazy=False):

        logger.info("compute_mesh_with_openmvs: ...")

        # https://github.com/cdcseacave/openMVS/wiki/Usage
        #   Exporting and Viewing Results
        #   Each of the following commands also writes a PLY file that can be
        #   used with many third-party tools. Alternatively, Viewer can be used
        #   to export the MVS projects to PLY or OBJ formats.

        interface_mvs_fn = "interface_colmap.mvs"
        # This will create a "plain_mesh.ply" file
        mesh_mvs_fn = os.path.splitext(mesh_ply_ofn)[0] + ".mvs"

        openmvs_mvs_reconstructor = OpenMVSReconstructor()
        # This step already imports the dense point cloud computed by colmap
        # (Stored in fused.ply and fused.ply.vis)
        openmvs_mvs_reconstructor.convert_colmap_to_openMVS(
            colmap_dense_idp=colmap_idp,
            openmvs_workspace_dp=odp,
            openmvs_ofn=interface_mvs_fn,
            image_folder="images/",
            lazy=lazy,
        )

        logger.vinfo("ofp", os.path.join(odp, mesh_ply_ofn))
        # Adjust the default parameters (min_point_distance=2.5,
        # smoothing_iterations=2) to improve satellite reconstruction results
        min_point_distance = 0
        smoothing_iterations = 0

        openmvs_mvs_reconstructor.reconstruct_mesh(
            odp,
            interface_mvs_fn,
            mesh_mvs_fn,
            # OpenMVS Default Value: min_point_distance=2.5
            min_point_distance=min_point_distance,
            # Clean options:
            # OpenMVS Default Value: decimate_value=1.0
            decimate_value=1.0,
            # OpenMVS Default Value: smoothing_iterations=2
            smoothing_iterations=smoothing_iterations,
            lazy=lazy,
        )
        mesh_ply_ofp = os.path.join(odp, mesh_ply_ofn)
        plain_mesh_ply_ofp = os.path.join(odp, plain_mesh_ply_ofn)
        meshlab = Meshlab()
        meshlab.remove_color(mesh_ply_ofp, plain_mesh_ply_ofp)

        logger.info("compute_mesh_with_openmvs: Done")
Beispiel #14
0
    def parse_ply_file(ifp):
        logger.info("Parse PLY File: ...")
        logger.vinfo("ifp", ifp)
        ply_data = PlyData.read(ifp)

        vertices, _, _ = PLYFileHandler.__ply_data_vertices_to_vetex_list(
            ply_data)
        faces, _, _ = PLYFileHandler.__ply_data_faces_to_face_list(ply_data)

        logger.info("Parse PLY File: Done")

        return vertices, faces
def create_config_from_template(config_template_ifp, config_fp):
    config_template_ifp = os.path.abspath(config_template_ifp)
    config_fp = os.path.abspath(config_fp)
    if not os.path.isfile(config_fp):
        logger.info(f"Config file {config_fp} not found")
        logger.info(
            f"Creating config file at {config_fp} from template {config_template_ifp}"
        )
        copyfile(config_template_ifp, config_fp)
        return True
    else:
        return False
Beispiel #16
0
    def compute_depth_maps(self, downscale_level=0):
        logger.info("compute_depth_maps: ...")

        downscale_s_str = "-s" + str(downscale_level)
        dm_recon_call = [
            self.dm_recon_fp,
            downscale_s_str,
            self.workspace_folder,
        ]
        logger.vinfo("dm_recon_call", dm_recon_call)
        subprocess.call(dm_recon_call)
        logger.info("compute_depth_maps: ...")
Beispiel #17
0
    def compute_mesh_with_mve(
        colmap_idp,
        odp,
        mesh_ply_ofn,
        plain_mesh_ply_ofn,
        meshing_algo,
        lazy=False,
    ):
        logger.info("compute_mesh_with_mve: ...")
        mesh_ply_ofp = os.path.join(odp, mesh_ply_ofn)
        plain_mesh_ply_ofp = os.path.join(odp, plain_mesh_ply_ofn)
        downscale_level = 0

        mve_mvs_reconstructor = MVEMVSReconstructor()
        mve_mvs_reconstructor.create_scene_from_sfm_result(
            colmap_idp, odp, downscale_level=downscale_level, lazy=lazy)
        mve_mvs_reconstructor.compute_dense_point_cloud_from_depth_maps(
            odp,
            downscale_level=downscale_level,
            view_ids=None,
            fssr_output=True,
            lazy=lazy,
        )

        meshlab = Meshlab()
        if meshing_algo == "fssr":
            mve_mvs_reconstructor.compute_fssr_reconstruction(
                odp, mesh_ply_ofp=mesh_ply_ofp, lazy=lazy)
            stem, ext = os.path.splitext(mesh_ply_ofp)
            cleaned_mesh_ply_ofp = stem + "_cleaned" + ext
            mve_mvs_reconstructor.compute_clean_mesh(
                odp,
                mesh_ply_ifp=mesh_ply_ofp,
                mesh_cleaned_ply_ofp=cleaned_mesh_ply_ofp,
                delete_color=False,
                lazy=lazy,
            )
            meshlab.remove_color(cleaned_mesh_ply_ofp, plain_mesh_ply_ofp)
        elif meshing_algo == "gdmr":
            mve_mvs_reconstructor.compute_gdmr_reconstruction(
                odp, mesh_ply_ofp=mesh_ply_ofp, lazy=lazy)
            meshlab.remove_color(mesh_ply_ofp, plain_mesh_ply_ofp)
        else:
            logger.vinfo("meshing_algo", meshing_algo)
            assert False

        logger.vinfo("ofp", mesh_ply_ofp)
        logger.info("compute_mesh_with_mve: Done")
Beispiel #18
0
    def process_mve_create_scene_tasks(self, mve_create_scene_tasks):
        for mve_create_scene_task in mve_create_scene_tasks:

            logger.info("Perform Create Scene Task: ...")
            self.workspace_folder = mve_create_scene_task.mve_model_dir
            self.create_scene_from_sfm_result(
                mve_create_scene_task.model_file_path
            )
            logger.info("Perform Create Scene Task: Done")

            mve_point_cloud_ply_ofp = os.path.join(
                self.workspace_folder,
                mve_create_scene_task.mve_point_cloud_name,
            )

            self.compute_dense_point_cloud_from_depth_maps(
                mve_point_cloud_ply_ofp
            )
    def reconstruct_mesh_with_delaunay(
        self,
        reconstruction_idp,
        mesh_ply_ofp,
        max_proj_dist=None,
        max_depth_dist=None,
        lazy=False,
    ):

        logger.info("reconstruct_mesh: ...")

        assert os.path.isdir(self.colmap_exe_dp)
        assert os.path.isfile(os.path.join(self.colmap_exe_dp, "colmap"))
        if not os.path.isfile(mesh_ply_ofp) or not lazy:
            os.environ["PATH"] += os.pathsep + self.colmap_exe_dp

            dense_mesher_call = [
                "colmap",
                "delaunay_mesher",
                "--input_path",
                reconstruction_idp,
                "--output_path",
                mesh_ply_ofp,
                "--input_type",
                "dense",
            ]

            if max_proj_dist is not None:
                dense_mesher_call += [
                    "--DelaunayMeshing.max_proj_dist",
                    str(max_proj_dist),
                ]

            if max_depth_dist is not None:
                dense_mesher_call += [
                    "--DelaunayMeshing.max_depth_dist",
                    str(max_depth_dist),
                ]

            logger.vinfo("dense_mesher_call: ", dense_mesher_call)
            subprocess.call(dense_mesher_call)

        logger.info("reconstruct_mesh: Done")
Beispiel #20
0
    def create_textured_mesh_from_nvm_and_mesh(
        self,
        nvm_ifp,
        untextured_mesh_ifp,
        mve_workspace,
        texture_odp,
        lazy=True,
    ):

        logger.info("create_textured_mesh_from_nvm: ...")
        mve_creator = MVECreator(workspace_dp=mve_workspace)
        if not lazy or not os.path.isdir(mve_workspace):
            mve_creator.create_scene_from_sfm_result(nvm_ifp)

        texrecon = MVETexrecon()
        texrecon.create_textured_mesh(
            mve_workspace, untextured_mesh_ifp, texture_odp
        )
        logger.info("create_textured_mesh_from_nvm: Done")
    def texture_mesh(
        self,
        openmvs_workspace_dp,
        openmvs_ifn,
        openmvs_ofn,
        export_type,
        lazy=False,
    ):
        # export_type: '.ply' or '.obj'
        logger.info("texture_mesh: ...")

        if not (export_type == "ply" or export_type == "obj"):
            logger.vinfo("export_type", export_type)
            assert False

        export_file = os.path.splitext(openmvs_ofn)[0] + "." + export_type

        if (not os.path.isfile(openmvs_ofn) or not os.path.isfile(export_file)
                or not lazy):
            texture_mesh_call = [
                self.texture_mesh_fp,
                "-i",
                openmvs_ifn,
                "-w",
                openmvs_workspace_dp,
                "-o",
                openmvs_ofn,
                "--export-type",
                export_type,
            ]

            logger.info(str(texture_mesh_call))
            pRecons = subprocess.Popen(texture_mesh_call)
            pRecons.wait()
        logger.info("texture_mesh: Done")
    def convert_visualsfm_to_openMVS(self, nvm_ifp, image_idp,
                                     openmvs_workspace_temp, openmvs_ofp):

        logger.info("convert_visualsfm_to_openMVS: ...")

        for possible_img_file in os.listdir(image_idp):
            img_ifp = os.path.join(image_idp, possible_img_file)
            img_ofp = os.path.join(openmvs_workspace_temp, possible_img_file)
            if os.path.isfile(img_ifp) and not os.path.isfile(img_ofp):
                shutil.copyfile(img_ifp, img_ofp)

        # InterfaceVisualSFM scene.nvm
        visualsfm_to_openmvs_call = [
            self.interface_visualsfm_fp,
            "-i",
            nvm_ifp,
            "-w",
            openmvs_workspace_temp,
            "-o",
            openmvs_ofp,
        ]

        logger.info(str(visualsfm_to_openmvs_call))
        visualsfm_to_openmvs_proc = subprocess.Popen(visualsfm_to_openmvs_call)
        visualsfm_to_openmvs_proc.wait()
        logger.info("convert_visualsfm_to_openMVS: Done")
    def densify_point_cloud(self,
                            openmvs_workspace_dp,
                            openmvs_ifn,
                            openmvs_ofn,
                            lazy=False):
        logger.info("densify_point_cloud: ...")

        # The workspace folder defined by "-w"
        # MUST BE THE FOLDER WHICH CONTAINS THE *.mvs file

        if (not os.path.isfile(os.path.join(openmvs_workspace_dp, openmvs_ofn))
                or not lazy):
            densify_point_cloud_call = [
                self.densify_point_cloud_fp,
                "-i",
                openmvs_ifn,
                "-w",
                openmvs_workspace_dp,
                "-o",
                openmvs_ofn,
            ]

            logger.info(str(densify_point_cloud_call))
            densify_proc = subprocess.Popen(densify_point_cloud_call)
            densify_proc.wait()
        logger.info("densify_point_cloud: Done ")
Beispiel #24
0
    def compute_mesh_with_colmap(
        colmap_idp,
        mesh_odp,
        mesh_ply_ofn,
        plain_mesh_ply_ofn,
        meshing_algo,
        poisson_trim_thresh=10,
        lazy=False,
    ):
        """Poisson meshing works with a single point-cloud-ply-file, whereas
        delaunay meshing requires a full workspace.
        """
        logger.info("compute_mesh_with_colmap: ...")
        assert meshing_algo in ["poisson_mesher", "delaunay_mesher"]
        mesh_ply_ofp = os.path.join(mesh_odp, mesh_ply_ofn)
        logger.vinfo("ofp", mesh_ply_ofp)
        colmap_mvs_reconstructor = ColmapMVSReconstructor()
        if meshing_algo == "poisson_mesher":
            point_cloud_ply_ifp = os.path.join(colmap_idp, "fused.ply")
            colmap_mvs_reconstructor.reconstruct_mesh_with_poisson(
                point_cloud_ply_ifp,
                mesh_ply_ofp,
                poisson_trim_thresh,
                lazy=lazy,
            )
        elif meshing_algo == "delaunay_mesher":
            colmap_mvs_reconstructor.reconstruct_mesh_with_delaunay(
                colmap_idp,
                mesh_ply_ofp,
                # https://colmap.github.io/faq.html
                max_proj_dist=0,  # Colmap Default Value: 2.5
                lazy=lazy,
            )
        plain_mesh_ply_ofp = os.path.join(mesh_odp, plain_mesh_ply_ofn)
        meshlab = Meshlab()
        meshlab.remove_color(mesh_ply_ofp, plain_mesh_ply_ofp)

        logger.info("compute_mesh_with_colmap: Done")
Beispiel #25
0
    def compute_dense_point_cloud_from_depth_maps(
        self,
        mve_point_cloud_ply_ofp,
        downscale_level=0,
        view_ids=None,
        fssr_output=True,
    ):
        logger.info("compute_dense_point_cloud_from_depth_maps: ...")
        assert os.path.splitext(mve_point_cloud_ply_ofp)[1] == ".ply"

        scene2pset_call = [self.scene2pset_fp]
        if fssr_output:
            downscale_F_str = "-F" + str(downscale_level)
            scene2pset_call.append(downscale_F_str)
        if view_ids is not None:
            view_id_str = "--views=" + ",".join(map(str, view_ids))
            scene2pset_call.append(view_id_str)
        scene2pset_call.append(self.workspace_folder)
        scene2pset_call.append(mve_point_cloud_ply_ofp)
        logger.vinfo("scene2pset_call", scene2pset_call)
        subprocess.call(scene2pset_call)

        logger.info("compute_dense_point_cloud_from_depth_maps: Done")
Beispiel #26
0
 def create_scene_from_sfm_result(self, sfm_fp_or_dp, downscale_level=None):
     # Input can be a nvm file or a colmap model folder
     assert self.workspace_folder is not None
     logger.info("Creating Scene: ...")
     logger.info("Input file/folder: " + sfm_fp_or_dp)
     logger.info("Output Path: " + self.workspace_folder)
     downscale_s_str = "-s" + str(downscale_level)
     make_scene_call = [
         self.make_scene_fp,
         downscale_s_str,
         sfm_fp_or_dp,
         self.workspace_folder,
     ]
     logger.vinfo("make_scene_call", make_scene_call)
     subprocess.call(make_scene_call)
     logger.info("Creating Scene: Done")
    def reconstruct_mesh_with_poisson(self, point_cloud_ply_ifp, mesh_ply_ofp,
                                      poisson_trim_thresh, lazy):
        logger.info("reconstruct_mesh: ...")
        logger.vinfo("mesh_ply_ofp", mesh_ply_ofp)

        assert os.path.isdir(self.colmap_exe_dp)
        assert os.path.isfile(os.path.join(self.colmap_exe_dp, "colmap"))
        if not os.path.isfile(mesh_ply_ofp) or not lazy:
            os.environ["PATH"] += os.pathsep + self.colmap_exe_dp
            trim_thresh_str = str(poisson_trim_thresh)
            dense_mesher_call = [
                "colmap",
                "poisson_mesher",
                "--input_path",
                point_cloud_ply_ifp,
                "--output_path",
                mesh_ply_ofp,
                "--PoissonMeshing.trim",
                trim_thresh_str,
            ]
            logger.vinfo("dense_mesher_call: ", dense_mesher_call)
            subprocess.call(dense_mesher_call)

        logger.info("reconstruct_mesh: Done")
Beispiel #28
0
    def write_ply_file(
        ofp,
        vertices,
        with_colors=True,
        with_normals=False,
        faces=None,
        plain_text_output=False,
        with_measurements=False,
    ):

        logger.info("write_ply_file: " + ofp)

        ply_data_vertex_data_dtype_list = PLYFileHandler.build_type_list(
            vertices, with_colors, with_normals, with_measurements)

        logger.vinfo("ply_data_vertex_data_dtype_list",
                     ply_data_vertex_data_dtype_list)

        output_ply_data_vertex_element = (
            PLYFileHandler.__vertices_to_ply_vertex_element(
                vertices, ply_data_vertex_data_dtype_list))

        if faces is None or len(faces) == 0:
            logger.info("Write File With Vertices Only (no faces)")
            output_data = PlyData([output_ply_data_vertex_element],
                                  text=plain_text_output)
        else:
            logger.info("Write File With Faces")
            logger.info("Number faces" + str(len(faces)))

            ply_data_face_data_type = [("vertex_indices", "i4", (3, ))]

            # we do not define colors for faces,
            # since we use the vertex colors to colorize the face

            output_ply_data_face_element = (
                PLYFileHandler.__faces_to_ply_face_element(
                    faces, ply_data_face_data_type))
            output_data = PlyData(
                [output_ply_data_vertex_element, output_ply_data_face_element],
                text=plain_text_output,
            )

        output_data.write(ofp)
Beispiel #29
0
    def get_option_value(self, option, target_type, section=None):
        """
        :param section:
        :param option:
        :param target_type:
        :return:
        """
        if section is None:
            section = SSRConfig.default_section

        try:
            if target_type == list:
                option_str = self.config.get(section, option)
                option_str = SSRConfig.detect_missing_commas(option_str)
                option_str = SSRConfig.remove_appended_commas(option_str)
                result = json.loads(option_str)
            else:
                option_str = self.config.get(section, option)
                option_str = option_str.split("#")[0].rstrip()
                if (
                    target_type == bool
                ):  # Allow True/False bool values in addition to 1/0
                    result = (
                        option_str == "True"
                        or option_str == "T"
                        or option_str == "1"
                    )
                else:
                    result = target_type(option_str)

        except configparser.NoOptionError as NoOptErr:
            logger.info("ERROR: " + str(NoOptErr))
            logger.info("CONFIG FILE: " + self.config_fp)
            assert False  # Option Missing
        except:
            logger.info("option_str: " + str(option_str))
            raise

        return result
Beispiel #30
0
    def convert_depth_map_to_cam_coords(
        self,
        depth_map,
        depth_map_semantic,
        shift_to_pixel_center,  # False for Colmap, True for MVE
        depth_map_display_sparsity=100,
    ):

        assert 0 < depth_map_display_sparsity

        height, width = depth_map.shape
        logger.info("height " + str(height))
        logger.info("width " + str(width))

        if self.height == height and self.width == width:
            x_step_size = 1.0
            y_step_size = 1.0
        else:
            x_step_size = self.width / width
            y_step_size = self.height / height
            logger.info("x_step_size " + str(x_step_size))
            logger.info("y_step_size " + str(y_step_size))

        fx, fy, skew, cx, cy = self.split_intrinsic_mat(
            self.get_calibration_mat())
        logger.vinfo("fx, fy, skew, cx, cy: ", str([fx, fy, skew, cx, cy]))

        indices = np.indices((height, width))
        y_index_list = indices[0].flatten()
        x_index_list = indices[1].flatten()

        depth_values = depth_map.flatten()

        assert len(x_index_list) == len(y_index_list) == len(depth_values)

        if shift_to_pixel_center:
            # https://github.com/simonfuhrmann/mve/blob/master/libs/mve/depthmap.cc
            #  math::Vec3f v = invproj * math::Vec3f(
            #       (float)x + 0.5f, (float)y + 0.5f, 1.0f);
            u_index_coord_list = x_step_size * x_index_list + 0.5
            v_index_coord_list = y_step_size * y_index_list + 0.5
        else:
            # https://github.com/colmap/colmap/blob/dev/src/base/reconstruction.cc
            #   COLMAP assumes that the upper left pixel center is (0.5, 0.5)
            #   i.e. pixels are already shifted
            u_index_coord_list = x_step_size * x_index_list
            v_index_coord_list = y_step_size * y_index_list

        # The cannoncial vectors are defined according to p.155 of
        # "Multiple View Geometry" by Hartley and Zisserman using a canonical
        # focal length of 1 , i.e. vec = [(x - cx) / fx, (y - cy) / fy, 1]
        skew_correction = (cy - v_index_coord_list) * skew / (fx * fy)
        x_coords_canonical = (u_index_coord_list - cx) / fx + skew_correction
        y_coords_canonical = (v_index_coord_list - cy) / fy
        z_coords_canonical = np.ones(len(depth_values), dtype=float)

        # Determine non-background data
        # non_background_flags = np.logical_not(np.isnan(depth_values))
        depth_values_not_nan = np.nan_to_num(depth_values)
        non_background_flags = depth_values_not_nan > 0

        x_coords_canonical_filtered = x_coords_canonical[non_background_flags]
        y_coords_canonical_filtered = y_coords_canonical[non_background_flags]
        z_coords_canonical_filtered = z_coords_canonical[non_background_flags]
        depth_values_filtered = depth_values[non_background_flags]

        if depth_map_display_sparsity != 100:
            x_coords_canonical_filtered = x_coords_canonical_filtered[::
                                                                      depth_map_display_sparsity]
            y_coords_canonical_filtered = y_coords_canonical_filtered[::
                                                                      depth_map_display_sparsity]
            z_coords_canonical_filtered = z_coords_canonical_filtered[::
                                                                      depth_map_display_sparsity]
            depth_values_filtered = depth_values_filtered[::
                                                          depth_map_display_sparsity]

        if depth_map_semantic == Camera.DEPTH_MAP_WRT_CANONICAL_VECTORS:
            # In this case, the depth values are defined w.r.t. the canonical
            # vectors. This kind of depth data is used by Colmap.
            x_coords_filtered = (x_coords_canonical_filtered *
                                 depth_values_filtered)
            y_coords_filtered = (y_coords_canonical_filtered *
                                 depth_values_filtered)
            z_coords_filtered = (z_coords_canonical_filtered *
                                 depth_values_filtered)

        elif depth_map_semantic == Camera.DEPTH_MAP_WRT_UNIT_VECTORS:
            # In this case the depth values are defined w.r.t. the normalized
            # canonical vectors. This kind of depth data is used by MVE.
            cannonical_norms_filtered = np.linalg.norm(
                np.array(
                    [
                        x_coords_canonical_filtered,
                        y_coords_canonical_filtered,
                        z_coords_canonical_filtered,
                    ],
                    dtype=float,
                ),
                axis=0,
            )
            # Instead of normalizing the x,y and z component, we divide the
            # depth values by the corresponding norm.
            normalized_depth_values_filtered = (depth_values_filtered /
                                                cannonical_norms_filtered)
            x_coords_filtered = (x_coords_canonical_filtered *
                                 normalized_depth_values_filtered)
            y_coords_filtered = (y_coords_canonical_filtered *
                                 normalized_depth_values_filtered)
            z_coords_filtered = (z_coords_canonical_filtered *
                                 normalized_depth_values_filtered)

        else:
            assert False

        cam_coords = np.dstack(
            (x_coords_filtered, y_coords_filtered, z_coords_filtered))[0]

        return cam_coords