| import sys |
| sys.path.append("..") |
|
|
| import imageio |
| import numpy as np |
| import os |
|
|
| from plyfile import PlyData, PlyElement |
| from pycolmap import SceneManager |
| from scipy.ndimage.interpolation import zoom |
|
|
|
|
| |
|
|
| def main(args): |
| suffix = ".photometric.bin" if args.photometric else ".geometric.bin" |
|
|
| image_file = os.path.join(args.dense_folder, "images", args.image_filename) |
| depth_file = os.path.join( |
| args.dense_folder, args.stereo_folder, "depth_maps", |
| args.image_filename + suffix) |
| if args.save_normals: |
| normals_file = os.path.join( |
| args.dense_folder, args.stereo_folder, "normal_maps", |
| args.image_filename + suffix) |
|
|
| |
| scene_manager = SceneManager(os.path.join(args.dense_folder, "sparse")) |
| scene_manager.load_cameras() |
| scene_manager.load_images() |
|
|
| image_id, image = scene_manager.get_image_from_name(args.image_filename) |
| camera = scene_manager.cameras[image.camera_id] |
| rotation_camera_from_world = image.R() |
| camera_center = image.C() |
|
|
| |
| image = imageio.imread(image_file) |
|
|
| with open(depth_file, "rb") as fid: |
| w = int("".join(iter(lambda: fid.read(1), "&"))) |
| h = int("".join(iter(lambda: fid.read(1), "&"))) |
| c = int("".join(iter(lambda: fid.read(1), "&"))) |
| depth_map = np.fromfile(fid, np.float32).reshape(h, w) |
| if (h, w) != image.shape[:2]: |
| depth_map = zoom( |
| depth_map, |
| (float(image.shape[0]) / h, float(image.shape[1]) / w), |
| order=0) |
|
|
| if args.save_normals: |
| with open(normals_file, "rb") as fid: |
| w = int("".join(iter(lambda: fid.read(1), "&"))) |
| h = int("".join(iter(lambda: fid.read(1), "&"))) |
| c = int("".join(iter(lambda: fid.read(1), "&"))) |
| normals = np.fromfile( |
| fid, np.float32).reshape(c, h, w).transpose([1, 2, 0]) |
| if (h, w) != image.shape[:2]: |
| normals = zoom( |
| normals, |
| (float(image.shape[0]) / h, float(image.shape[1]) / w, 1.), |
| order=0) |
|
|
| if args.min_depth is not None: |
| depth_map[depth_map < args.min_depth] = 0. |
| if args.max_depth is not None: |
| depth_map[depth_map > args.max_depth] = 0. |
|
|
| |
| |
| points3D = np.dstack(camera.get_image_grid() + [depth_map]) |
| points3D[:,:,:2] *= depth_map[:,:,np.newaxis] |
|
|
| |
| points3D = points3D.astype(np.float32).reshape(-1, 3) |
| if args.save_normals: |
| normals = normals.astype(np.float32).reshape(-1, 3) |
| image = image.reshape(-1, 3) |
| if image.dtype != np.uint8: |
| if image.max() <= 1: |
| image = (image * 255.).astype(np.uint8) |
| else: |
| image = image.astype(np.uint8) |
|
|
| if args.world_space: |
| points3D = points3D.dot(rotation_camera_from_world) + camera_center |
| if args.save_normals: |
| normals = normals.dot(rotation_camera_from_world) |
|
|
| if args.save_normals: |
| vertices = np.rec.fromarrays( |
| tuple(points3D.T) + tuple(normals.T) + tuple(image.T), |
| names="x,y,z,nx,ny,nz,red,green,blue") |
| else: |
| vertices = np.rec.fromarrays( |
| tuple(points3D.T) + tuple(image.T), names="x,y,z,red,green,blue") |
| vertices = PlyElement.describe(vertices, "vertex") |
| PlyData([vertices]).write(args.output_filename) |
|
|
|
|
| |
|
|
| if __name__ == "__main__": |
| import argparse |
|
|
| parser = argparse.ArgumentParser( |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
|
|
| parser.add_argument("dense_folder", type=str) |
| parser.add_argument("image_filename", type=str) |
| parser.add_argument("output_filename", type=str) |
|
|
| parser.add_argument( |
| "--photometric", default=False, action="store_true", |
| help="use photometric depthmap instead of geometric") |
|
|
| parser.add_argument( |
| "--world_space", default=False, action="store_true", |
| help="apply the camera->world extrinsic transformation to the result") |
|
|
| parser.add_argument( |
| "--save_normals", default=False, action="store_true", |
| help="load the estimated normal map and save as part of the PLY") |
|
|
| parser.add_argument( |
| "--stereo_folder", type=str, default="stereo", |
| help="folder in the dense workspace containing depth and normal maps") |
|
|
| parser.add_argument( |
| "--min_depth", type=float, default=None, |
| help="set pixels with depth less than this value to zero depth") |
|
|
| parser.add_argument( |
| "--max_depth", type=float, default=None, |
| help="set pixels with depth greater than this value to zero depth") |
|
|
| args = parser.parse_args() |
|
|
| main(args) |
|
|