Example #1
0
    def __init__(self, root_path, gcp_file=None, geo_file=None):
        # root path to the project
        self.root_path = io.absolute_path_file(root_path)
        self.input_images = os.path.join(self.root_path, 'images')

        # modules paths

        # here are defined where all modules should be located in
        # order to keep track all files al directories during the
        # whole reconstruction process.
        self.dataset_raw = os.path.join(self.root_path, 'images')
        self.opensfm = os.path.join(self.root_path, 'opensfm')
        self.openmvs = os.path.join(self.opensfm, 'undistorted', 'openmvs')
        self.odm_meshing = os.path.join(self.root_path, 'odm_meshing')
        self.odm_texturing = os.path.join(self.root_path, 'odm_texturing')
        self.odm_25dtexturing = os.path.join(self.root_path,
                                             'odm_texturing_25d')
        self.odm_georeferencing = os.path.join(self.root_path,
                                               'odm_georeferencing')
        self.odm_filterpoints = os.path.join(self.root_path,
                                             'odm_filterpoints')
        self.odm_orthophoto = os.path.join(self.root_path, 'odm_orthophoto')
        self.odm_report = os.path.join(self.root_path, 'odm_report')

        # important files paths

        # benchmarking
        self.benchmarking = os.path.join(self.root_path, 'benchmark.txt')
        self.dataset_list = os.path.join(self.root_path, 'img_list.txt')

        # opensfm
        self.opensfm_image_list = os.path.join(self.opensfm, 'image_list.txt')
        self.opensfm_reconstruction = os.path.join(self.opensfm,
                                                   'reconstruction.json')
        self.opensfm_reconstruction_nvm = os.path.join(
            self.opensfm, 'undistorted/reconstruction.nvm')
        self.opensfm_geocoords_reconstruction = os.path.join(
            self.opensfm, 'reconstruction.geocoords.json')
        self.opensfm_topocentric_reconstruction = os.path.join(
            self.opensfm, 'reconstruction.topocentric.json')

        # OpenMVS
        self.openmvs_model = os.path.join(self.openmvs,
                                          'scene_dense_dense_filtered.ply')

        # filter points
        self.filtered_point_cloud = os.path.join(self.odm_filterpoints,
                                                 "point_cloud.ply")

        # odm_meshing
        self.odm_mesh = os.path.join(self.odm_meshing, 'odm_mesh.ply')
        self.odm_meshing_log = os.path.join(self.odm_meshing,
                                            'odm_meshing_log.txt')
        self.odm_25dmesh = os.path.join(self.odm_meshing, 'odm_25dmesh.ply')
        self.odm_25dmeshing_log = os.path.join(self.odm_meshing,
                                               'odm_25dmeshing_log.txt')

        # texturing
        self.odm_textured_model_obj = 'odm_textured_model_geo.obj'

        # odm_georeferencing
        self.odm_georeferencing_coords = os.path.join(self.odm_georeferencing,
                                                      'coords.txt')
        self.odm_georeferencing_gcp = gcp_file or io.find(
            'gcp_list.txt', self.root_path)
        self.odm_georeferencing_gcp_utm = os.path.join(self.odm_georeferencing,
                                                       'gcp_list_utm.txt')
        self.odm_geo_file = geo_file or io.find('geo.txt', self.root_path)

        self.odm_georeferencing_proj = 'proj.txt'
        self.odm_georeferencing_model_txt_geo = os.path.join(
            self.odm_georeferencing, 'odm_georeferencing_model_geo.txt')
        self.odm_georeferencing_xyz_file = os.path.join(
            self.odm_georeferencing, 'odm_georeferenced_model.csv')
        self.odm_georeferencing_model_laz = os.path.join(
            self.odm_georeferencing, 'odm_georeferenced_model.laz')
        self.odm_georeferencing_model_las = os.path.join(
            self.odm_georeferencing, 'odm_georeferenced_model.las')

        # odm_orthophoto
        self.odm_orthophoto_render = os.path.join(self.odm_orthophoto,
                                                  'odm_orthophoto_render.tif')
        self.odm_orthophoto_tif = os.path.join(self.odm_orthophoto,
                                               'odm_orthophoto.tif')
        self.odm_orthophoto_corners = os.path.join(
            self.odm_orthophoto, 'odm_orthophoto_corners.txt')
        self.odm_orthophoto_log = os.path.join(self.odm_orthophoto,
                                               'odm_orthophoto_log.txt')
        self.odm_orthophoto_tif_log = os.path.join(self.odm_orthophoto,
                                                   'gdal_translate_log.txt')

        # tiles
        self.orthophoto_tiles = os.path.join(self.root_path,
                                             "orthophoto_tiles")

        # Split-merge
        self.submodels_path = os.path.join(self.root_path, 'submodels')

        # Tiles
        self.entwine_pointcloud = self.path("entwine_pointcloud")
        self.ogc_tiles = self.path("3d_tiles")
def process(args, tree, reconstruction, current_path):
	odm_orthophoto = io.join_paths(current_path, 'orthophoto')
	odm_orthophoto_path = odm_orthophoto
	odm_orthophoto_render = io.join_paths(odm_orthophoto_path, 'odm_orthophoto_render.tif')
	odm_orthophoto_tif = io.join_paths(odm_orthophoto_path, 'odm_orthophoto.tif')
	odm_orthophoto_corners = io.join_paths(odm_orthophoto_path, 'odm_orthophoto_corners.tif')
	odm_orthophoto_log = io.join_paths(odm_orthophoto_path, 'odm_orthophoto_log.tif')		
        odm_orthophoto_tif_log = io.join_paths(odm_orthophoto_path, 'gdal_translate_log.txt')
	odm_25dgeoreferencing = io.join_paths(current_path, 'odm_georeferencing')
	odm_georeferencing = io.join_paths(current_path, 'odm_georeferencing')

	odm_georeferencing_coords = io.join_paths(
            odm_georeferencing, 'coords.txt')
        odm_georeferencing_gcp = io.find('gcp_list.txt', current_path)
        odm_georeferencing_gcp_utm = io.join_paths(odm_georeferencing, 'gcp_list_utm.txt')
        odm_georeferencing_utm_log = io.join_paths(
            odm_georeferencing, 'odm_georeferencing_utm_log.txt')
        odm_georeferencing_log = 'odm_georeferencing_log.txt'
        odm_georeferencing_transform_file = 'odm_georeferencing_transform.txt'
        odm_georeferencing_proj = 'proj.txt'
        odm_georeferencing_model_txt_geo = 'odm_georeferencing_model_geo.txt'
        odm_georeferencing_model_obj_geo = 'odm_textured_model_geo.obj'
        odm_georeferencing_xyz_file = io.join_paths(
            odm_georeferencing, 'odm_georeferenced_model.csv')
        odm_georeferencing_las_json = io.join_paths(
            odm_georeferencing, 'las.json')
        odm_georeferencing_model_laz = io.join_paths(
            odm_georeferencing, 'odm_georeferenced_model.laz')
        odm_georeferencing_model_las = io.join_paths(
            odm_georeferencing, 'odm_georeferenced_model.las')
        odm_georeferencing_dem = io.join_paths(
            odm_georeferencing, 'odm_georeferencing_model_dem.tif')

        opensfm_reconstruction = io.join_paths(current_path,'reconstruction.json')
	odm_texturing = io.join_paths(current_path,'mvs')
	odm_textured_model_obj = io.join_paths(odm_texturing, 'odm_textured_model.obj')
	images_dir = io.join_paths(current_path, 'images')
        tree = tree
	opensfm_bundle = os.path.join(current_path, 'opensfm', 'bundle_r000.out')
	opensfm_bundle_list = os.path.join(current_path, 'opensfm', 'list_r000.out')
	opensfm_transformation = os.path.join(current_path, 'opensfm', 'geocoords_transformation.txt')
	filtered_point_cloud = os.path.join(current_path, 'filterpoints', 'point_cloud.ply')
        

        doPointCloudGeo = True
        transformPointCloud = True
        verbose =''

        class nonloc:
            runs = []

        def add_run(primary=True, band=None):
            subdir = ""
            if not primary and band is not None:
                subdir = band

            # Make sure 2.5D mesh is georeferenced before the 3D mesh
            # Because it will be used to calculate a transform
            # for the point cloud. If we use the 3D model transform,
            # DEMs and orthophoto might not align!
	    b = True
            if b:
                nonloc.runs += [{
                    'georeferencing_dir': os.path.join(odm_georeferencing, subdir),
                    'texturing_dir': os.path.join(odm_texturing, subdir),
                }]
            
            if not args.skip_3dmodel and (primary or args.use_3dmesh):
                nonloc.runs += [{
                    'georeferencing_dir': odm_georeferencing,
                    'texturing_dir': os.path.join(odm_texturing, subdir),
                }]
        
        if reconstruction.multi_camera:
            for band in reconstruction.multi_camera:
                primary = band == reconstruction.multi_camera[0]
                add_run(primary, band['name'].lower())
        else:
            add_run()

        #progress_per_run = 100.0 / len(nonloc.runs)
        #progress = 0.0

        for r in nonloc.runs:
            if not io.dir_exists(r['georeferencing_dir']):
                system.mkdir_p(r['georeferencing_dir'])

            odm_georeferencing_model_obj_geo = os.path.join(r['texturing_dir'], odm_georeferencing_model_obj_geo)
            odm_georeferencing_model_obj = os.path.join(r['texturing_dir'], odm_textured_model_obj)
            odm_georeferencing_log = os.path.join(r['georeferencing_dir'], odm_georeferencing_log)
            odm_georeferencing_transform_file = os.path.join(r['georeferencing_dir'], odm_georeferencing_transform_file)
            odm_georeferencing_model_txt_geo_file = os.path.join(r['georeferencing_dir'], odm_georeferencing_model_txt_geo)
	    pio = True
	    
	    if pio:
            #if not io.file_exists(odm_georeferencing_model_obj_geo) or \
               #not io.file_exists(odm_georeferencing_model_laz)

                # odm_georeference definitions
		
                kwargs = {
                    'bin': context.odm_modules_path,
                    'input_pc_file': filtered_point_cloud,
                    'bundle': opensfm_bundle,
                    'imgs': images_dir,
                    'imgs_list': opensfm_bundle_list,
                    'model': odm_georeferencing_model_obj,
                    'log': odm_georeferencing_log,
                    'input_trans_file': opensfm_transformation,
                    'transform_file': odm_georeferencing_transform_file,
                    'coords': odm_georeferencing_coords,
                    'output_pc_file': odm_georeferencing_model_laz,
                    'geo_sys': odm_georeferencing_model_txt_geo_file,
                    'model_geo': odm_georeferencing_model_obj_geo,
                    'verbose': verbose
                }

                if transformPointCloud:
                    kwargs['pc_params'] = '-inputPointCloudFile {input_pc_file} -outputPointCloudFile {output_pc_file}'.format(**kwargs)

                    if reconstruction.is_georeferenced():
                        kwargs['pc_params'] += ' -outputPointCloudSrs %s' % pipes.quote(reconstruction.georef.proj4())
                    else:
                        log.ODM_WARNING('NO SRS: The output point cloud will not have a SRS.')
                else:
                    kwargs['pc_params'] = ''
 
                if io.file_exists(opensfm_transformation) and io.file_exists(odm_georeferencing_coords):
                    log.ODM_INFO('Running georeferencing with OpenSfM transformation matrix')
                    system.run('{bin}/odm_georef -bundleFile {bundle} -inputTransformFile {input_trans_file} -inputCoordFile {coords} '
                               '-inputFile {model} -outputFile {model_geo} '
                               '{pc_params} {verbose} '
                               '-logFile {log} -outputTransformFile {transform_file} -georefFileOutputPath {geo_sys}'.format(**kwargs))
                elif io.file_exists(odm_georeferencing_coords):
		    print('running georeferencing')
                    log.ODM_INFO('Running georeferencing with generated coords file.')
                    system.run('{bin}/odm_georef -bundleFile {bundle} -inputCoordFile {coords} '
                               '-inputFile {model} -outputFile {model_geo} '
                               '{pc_params} {verbose} '
                               '-logFile {log} -outputTransformFile {transform_file} -georefFileOutputPath {geo_sys}'.format(**kwargs))
                else:
                    log.ODM_WARNING('Georeferencing failed. Make sure your '
                                    'photos have geotags in the EXIF or you have '
                                    'provided a GCP file. ')
                    doPointCloudGeo = False # skip the rest of the georeferencing

                if doPointCloudGeo:
                    reconstruction.georef.extract_offsets(odm_georeferencing_model_txt_geo_file)
                    point_cloud.post_point_cloud_steps(args, tree)
                    
                    if args.crop > 0:
                        log.ODM_INFO("Calculating cropping area and generating bounds shapefile from point cloud")
                        cropper = Cropper(odm_georeferencing, 'odm_georeferenced_model')
                        
                        decimation_step = 40 if args.fast_orthophoto or args.use_opensfm_dense else 90
                        
                        # More aggressive decimation for large datasets
                        if not args.fast_orthophoto:
                            decimation_step *= int(len(reconstruction.photos) / 1000) + 1

                        cropper.create_bounds_gpkg(odm_georeferencing_model_laz, args.crop, 
                                                    decimation_step=decimation_step)

                    # Do not execute a second time, since
                    # We might be doing georeferencing for
                    # multiple models (3D, 2.5D, ...)
                    doPointCloudGeo = False
                    transformPointCloud = False
            else:
                log.ODM_WARNING('Found a valid georeferenced model in: %s'
                                % odm_georeferencing_model_laz)

            if args.optimize_disk_space and io.file_exists(odm_georeferencing_model_laz) and io.file_exists(filtered_point_cloud):
                os.remove(filtered_point_cloud)
Example #3
0
def process(args, current_path, max_concurrency, reconstruction):
    #args = vars(args)
    orthophoto_cutline = True
    odm_orthophoto = io.join_paths(current_path, 'orthophoto')
    odm_orthophoto_path = odm_orthophoto
    odm_orthophoto_render = io.join_paths(odm_orthophoto_path,
                                          'odm_orthophoto_render.tif')
    odm_orthophoto_tif = io.join_paths(odm_orthophoto_path,
                                       'odm_orthophoto.tif')
    odm_orthophoto_corners = io.join_paths(odm_orthophoto_path,
                                           'odm_orthophoto_corners.tif')
    odm_orthophoto_log = io.join_paths(odm_orthophoto_path,
                                       'odm_orthophoto_log.tif')
    odm_orthophoto_tif_log = io.join_paths(odm_orthophoto_path,
                                           'gdal_translate_log.txt')
    odm_25dgeoreferencing = io.join_paths(current_path, 'odm_georeferencing')
    odm_georeferencing = io.join_paths(current_path, 'odm_georeferencing')

    odm_georeferencing_coords = io.join_paths(odm_georeferencing, 'coords.txt')
    odm_georeferencing_gcp = io.find('gcp_list.txt', current_path)
    odm_georeferencing_gcp_utm = io.join_paths(odm_georeferencing,
                                               'gcp_list_utm.txt')
    odm_georeferencing_utm_log = io.join_paths(
        odm_georeferencing, 'odm_georeferencing_utm_log.txt')
    odm_georeferencing_log = 'odm_georeferencing_log.txt'
    odm_georeferencing_transform_file = 'odm_georeferencing_transform.txt'
    odm_georeferencing_proj = 'proj.txt'
    odm_georeferencing_model_txt_geo = 'odm_georeferencing_model_geo.txt'
    odm_georeferencing_model_obj_geo = 'odm_textured_model_geo.obj'
    odm_georeferencing_xyz_file = io.join_paths(odm_georeferencing,
                                                'odm_georeferenced_model.csv')
    odm_georeferencing_las_json = io.join_paths(odm_georeferencing, 'las.json')
    odm_georeferencing_model_laz = io.join_paths(
        odm_georeferencing, 'odm_georeferenced_model.laz')
    odm_georeferencing_model_las = io.join_paths(
        odm_georeferencing, 'odm_georeferenced_model.las')
    odm_georeferencing_dem = io.join_paths(odm_georeferencing,
                                           'odm_georeferencing_model_dem.tif')

    opensfm_reconstruction = io.join_paths(current_path, 'reconstruction.json')
    odm_texturing = io.join_paths(current_path, 'mvs')
    odm_textured_model_obj = io.join_paths(odm_texturing,
                                           'odm_textured_model.obj')
    images_dir = io.join_paths(current_path, 'images')

    reconstruction = reconstruction

    verbose = ''
    #"-verbose"

    # define paths and create working directories
    system.mkdir_p(odm_orthophoto)

    if not io.file_exists(odm_orthophoto_tif):
        gsd_error_estimate = 0.1
        ignore_resolution = False
        if not reconstruction.is_georeferenced():
            # Match DEMs
            gsd_error_estimate = -3
            ignore_resolution = True
        orthophoto_resolution = 5
        resolution = 1.0 / (
            gsd.cap_resolution(orthophoto_resolution,
                               opensfm_reconstruction,
                               gsd_error_estimate=gsd_error_estimate,
                               ignore_gsd=True,
                               ignore_resolution=ignore_resolution,
                               has_gcp=reconstruction.has_gcp()) / 100.0)

        # odm_orthophoto definitions
        kwargs = {
            'bin': context.odm_modules_path,
            'log': odm_orthophoto_log,
            'ortho': odm_orthophoto_render,
            'corners': odm_orthophoto_corners,
            'res': resolution,
            'bands': '',
            'verbose': verbose
        }

        # Check if the georef object is initialized
        # (during a --rerun this might not be)
        # TODO: this should be moved to a more central location?
        if reconstruction.is_georeferenced(
        ) and not reconstruction.georef.valid_utm_offsets():
            georeferencing_dir = odm_georeferencing  #if args.use_3dmesh and not args.skip_3dmodel else odm_25dgeoreferencing
            odm_georeferencing_model_txt_geo_file = os.path.join(
                georeferencing_dir, odm_georeferencing_model_txt_geo)

            if io.file_exists(odm_georeferencing_model_txt_geo_file):
                reconstruction.georef.extract_offsets(
                    odm_georeferencing_model_txt_geo_file)
            else:
                log.ODM_WARNING('Cannot read UTM offset from {}.'.format(
                    odm_georeferencing_model_txt_geo_file))

        models = []

        base_dir = odm_texturing

        if reconstruction.is_georeferenced():
            model_file = odm_georeferencing_model_obj_geo
        else:
            model_file = odm_textured_model_obj

        if reconstruction.multi_camera:
            for band in reconstruction.multi_camera:
                primary = band == reconstruction.multi_camera[0]
                subdir = ""
                if not primary:
                    subdir = band['name'].lower()
                models.append(os.path.join(base_dir, subdir, model_file))
            kwargs['bands'] = '-bands %s' % (','.join([
                quote(b['name'].lower()) for b in reconstruction.multi_camera
            ]))
        else:
            models.append(os.path.join(base_dir, model_file))

        kwargs['models'] = ','.join(map(quote, models))

        # run odm_orthophoto
        system.run(
            '{bin}/odm_orthophoto -inputFiles {models} '
            '-logFile {log} -outputFile {ortho} -resolution {res} {verbose} '
            '-outputCornerFile {corners} {bands}'.format(**kwargs))

        # Create georeferenced GeoTiff
        geotiffcreated = False

        if reconstruction.is_georeferenced(
        ) and reconstruction.georef.valid_utm_offsets():
            ulx = uly = lrx = lry = 0.0
            with open(odm_orthophoto_corners) as f:
                for lineNumber, line in enumerate(f):
                    if lineNumber == 0:
                        tokens = line.split(' ')
                        if len(tokens) == 4:
                            ulx = float(tokens[0]) + \
                                float(reconstruction.georef.utm_east_offset)
                            lry = float(tokens[1]) + \
                                float(reconstruction.georef.utm_north_offset)
                            lrx = float(tokens[2]) + \
                                float(reconstruction.georef.utm_east_offset)
                            uly = float(tokens[3]) + \
                                float(reconstruction.georef.utm_north_offset)
            log.ODM_INFO('Creating GeoTIFF')

            orthophoto_vars = orthophoto.get_orthophoto_vars(args)

            kwargs = {
                'ulx':
                ulx,
                'uly':
                uly,
                'lrx':
                lrx,
                'lry':
                lry,
                'vars':
                ' '.join([
                    '-co %s=%s' % (k, orthophoto_vars[k])
                    for k in orthophoto_vars
                ]),
                'proj':
                reconstruction.georef.proj4(),
                'input':
                odm_orthophoto_render,
                'output':
                odm_orthophoto_tif,
                'log':
                odm_orthophoto_tif_log,
                'max_memory':
                get_max_memory(),
            }

            system.run('gdal_translate -a_ullr {ulx} {uly} {lrx} {lry} '
                       '{vars} '
                       '-a_srs \"{proj}\" '
                       '--config GDAL_CACHEMAX {max_memory}% '
                       '--config GDAL_TIFF_INTERNAL_MASK YES '
                       '{input} {output} > {log}'.format(**kwargs))

            bounds_file_path = os.path.join(
                odm_georeferencing, 'odm_georeferenced_model.bounds.gpkg')

            # Cutline computation, before cropping
            # We want to use the full orthophoto, not the cropped one.
            pio = True
            if pio:
                cutline_file = os.path.join(odm_orthophoto, "cutline.gpkg")

                compute_cutline(odm_orthophoto_tif,
                                bounds_file_path,
                                cutline_file,
                                max_concurrency,
                                tmpdir=os.path.join(odm_orthophoto,
                                                    "grass_cutline_tmpdir"),
                                scale=0.25)

                orthophoto.compute_mask_raster(odm_orthophoto_tif,
                                               cutline_file,
                                               os.path.join(
                                                   odm_orthophoto,
                                                   "odm_orthophoto_cut.tif"),
                                               blend_distance=20,
                                               only_max_coords_feature=True)

            orthophoto.post_orthophoto_steps(args, bounds_file_path,
                                             odm_orthophoto_tif)

            # Generate feathered orthophoto also
            if pio:
                orthophoto.feather_raster(odm_orthophoto_tif,
                                          os.path.join(
                                              odm_orthophoto,
                                              "odm_orthophoto_feathered.tif"),
                                          blend_distance=20)

            geotiffcreated = True
        if not geotiffcreated:
            if io.file_exists(odm_orthophoto_render):
                pseudogeo.add_pseudo_georeferencing(odm_orthophoto_render)
                log.ODM_INFO("Renaming %s --> %s" %
                             (odm_orthophoto_render, odm_orthophoto_tif))
                os.rename(odm_orthophoto_render, odm_orthophoto_tif)
            else:
                log.ODM_WARNING(
                    "Could not generate an orthophoto (it did not render)")
    else:
        log.ODM_WARNING('Found a valid orthophoto in: %s' % odm_orthophoto_tif)

    #generate png

    orthophoto.generate_png(odm_orthophoto_tif)
Example #4
0
File: types.py Project: sgrchen/ODM
    def __init__(self, root_path, gcp_file = None, geo_file = None):
        # root path to the project
        self.root_path = io.absolute_path_file(root_path)
        self.input_images = io.join_paths(self.root_path, 'images')

        # modules paths

        # here are defined where all modules should be located in
        # order to keep track all files al directories during the
        # whole reconstruction process.
        self.dataset_raw = io.join_paths(self.root_path, 'images')
        self.opensfm = io.join_paths(self.root_path, 'opensfm')
        self.mve = io.join_paths(self.root_path, 'mve')
        self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing')
        self.odm_texturing = io.join_paths(self.root_path, 'odm_texturing')
        self.odm_25dtexturing = io.join_paths(self.root_path, 'odm_texturing_25d')
        self.odm_georeferencing = io.join_paths(self.root_path, 'odm_georeferencing')
        self.odm_25dgeoreferencing = io.join_paths(self.root_path, 'odm_georeferencing_25d')
        self.odm_filterpoints = io.join_paths(self.root_path, 'odm_filterpoints')
        self.odm_orthophoto = io.join_paths(self.root_path, 'odm_orthophoto')
        self.odm_report = io.join_paths(self.root_path, 'odm_report')
        

        # important files paths

        # benchmarking
        self.benchmarking = io.join_paths(self.root_path, 'benchmark.txt')
        self.dataset_list = io.join_paths(self.root_path, 'img_list.txt')

        # opensfm
        self.opensfm_tracks = io.join_paths(self.opensfm, 'tracks.csv')
        self.opensfm_bundle = io.join_paths(self.opensfm, 'bundle_r000.out')
        self.opensfm_bundle_list = io.join_paths(self.opensfm, 'list_r000.out')
        self.opensfm_image_list = io.join_paths(self.opensfm, 'image_list.txt')
        self.opensfm_reconstruction = io.join_paths(self.opensfm, 'reconstruction.json')
        self.opensfm_reconstruction_nvm = io.join_paths(self.opensfm, 'undistorted/reconstruction.nvm')
        self.opensfm_model = io.join_paths(self.opensfm, 'undistorted/depthmaps/merged.ply')
        self.opensfm_transformation = io.join_paths(self.opensfm, 'geocoords_transformation.txt')

        # mve
        self.mve_model = io.join_paths(self.mve, 'mve_dense_point_cloud.ply')
        self.mve_views = io.join_paths(self.mve, 'views')

        # filter points
        self.filtered_point_cloud = io.join_paths(self.odm_filterpoints, "point_cloud.ply")

        # odm_meshing
        self.odm_mesh = io.join_paths(self.odm_meshing, 'odm_mesh.ply')
        self.odm_meshing_log = io.join_paths(self.odm_meshing, 'odm_meshing_log.txt')
        self.odm_25dmesh = io.join_paths(self.odm_meshing, 'odm_25dmesh.ply')
        self.odm_25dmeshing_log = io.join_paths(self.odm_meshing, 'odm_25dmeshing_log.txt')

        # texturing
        self.odm_texturing_undistorted_image_path = io.join_paths(
            self.odm_texturing, 'undistorted')
        self.odm_textured_model_obj = 'odm_textured_model.obj'
        self.odm_textured_model_mtl = 'odm_textured_model.mtl'
        # Log is only used by old odm_texturing
        self.odm_texuring_log = 'odm_texturing_log.txt'

        # odm_georeferencing
        self.odm_georeferencing_coords = io.join_paths(
            self.odm_georeferencing, 'coords.txt')
        self.odm_georeferencing_gcp = gcp_file or io.find('gcp_list.txt', self.root_path)
        self.odm_georeferencing_gcp_utm = io.join_paths(self.odm_georeferencing, 'gcp_list_utm.txt')
        self.odm_geo_file = geo_file or io.find('geo.txt', self.root_path)
        
        self.odm_georeferencing_utm_log = io.join_paths(
            self.odm_georeferencing, 'odm_georeferencing_utm_log.txt')
        self.odm_georeferencing_log = 'odm_georeferencing_log.txt'
        self.odm_georeferencing_transform_file = 'odm_georeferencing_transform.txt'
        self.odm_georeferencing_proj = 'proj.txt'
        self.odm_georeferencing_model_txt_geo = 'odm_georeferencing_model_geo.txt'
        self.odm_georeferencing_model_obj_geo = 'odm_textured_model_geo.obj'
        self.odm_georeferencing_xyz_file = io.join_paths(
            self.odm_georeferencing, 'odm_georeferenced_model.csv')
        self.odm_georeferencing_las_json = io.join_paths(
            self.odm_georeferencing, 'las.json')
        self.odm_georeferencing_model_laz = io.join_paths(
            self.odm_georeferencing, 'odm_georeferenced_model.laz')
        self.odm_georeferencing_model_las = io.join_paths(
            self.odm_georeferencing, 'odm_georeferenced_model.las')
        self.odm_georeferencing_dem = io.join_paths(
            self.odm_georeferencing, 'odm_georeferencing_model_dem.tif')

        # odm_orthophoto
        self.odm_orthophoto_render = io.join_paths(self.odm_orthophoto, 'odm_orthophoto_render.tif')
        self.odm_orthophoto_tif = io.join_paths(self.odm_orthophoto, 'odm_orthophoto.tif')
        self.odm_orthophoto_corners = io.join_paths(self.odm_orthophoto, 'odm_orthophoto_corners.txt')
        self.odm_orthophoto_log = io.join_paths(self.odm_orthophoto, 'odm_orthophoto_log.txt')
        self.odm_orthophoto_tif_log = io.join_paths(self.odm_orthophoto, 'gdal_translate_log.txt')

        # tiles
        self.orthophoto_tiles = io.join_paths(self.root_path, "orthophoto_tiles")

        # Split-merge 
        self.submodels_path = io.join_paths(self.root_path, 'submodels')

        # Tiles
        self.entwine_pointcloud = self.path("entwine_pointcloud")