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)
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)
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")