Beispiel #1
0
    def process(self, args, outputs):
        tree = outputs['tree']

        if outputs['large']:
            if not os.path.exists(tree.submodels_path):
                log.ODM_ERROR(
                    "We reached the merge stage, but %s folder does not exist. Something must have gone wrong at an earlier stage. Check the log and fix possible problem before restarting?" % tree.submodels_path)
                exit(1)

            # Merge point clouds
            if args.merge in ['all', 'pointcloud']:
                if not io.file_exists(tree.odm_georeferencing_model_laz) or self.rerun():
                    all_point_clouds = get_submodel_paths(tree.submodels_path, "odm_georeferencing",
                                                          "odm_georeferenced_model.laz")

                    try:
                        point_cloud.merge(all_point_clouds, tree.odm_georeferencing_model_laz)
                        point_cloud.post_point_cloud_steps(args, tree)
                    except Exception as e:
                        log.ODM_WARNING("Could not merge point cloud: %s (skipping)" % str(e))
                else:
                    log.ODM_WARNING("Found merged point cloud in %s" % tree.odm_georeferencing_model_laz)

            self.update_progress(25)

            # Merge crop bounds
            merged_bounds_file = os.path.join(tree.odm_georeferencing, 'odm_georeferenced_model.bounds.gpkg')
            if not io.file_exists(merged_bounds_file) or self.rerun():
                all_bounds = get_submodel_paths(tree.submodels_path, 'odm_georeferencing',
                                                'odm_georeferenced_model.bounds.gpkg')
                log.ODM_INFO("Merging all crop bounds: %s" % all_bounds)
                if len(all_bounds) > 0:
                    # Calculate a new crop area
                    # based on the convex hull of all crop areas of all submodels
                    # (without a buffer, otherwise we are double-cropping)
                    Cropper.merge_bounds(all_bounds, merged_bounds_file, 0)
                else:
                    log.ODM_WARNING("No bounds found for any submodel.")

            # Merge orthophotos
            if args.merge in ['all', 'orthophoto']:
                if not io.dir_exists(tree.odm_orthophoto):
                    system.mkdir_p(tree.odm_orthophoto)

                if not io.file_exists(tree.odm_orthophoto_tif) or self.rerun():
                    all_orthos_and_ortho_cuts = get_all_submodel_paths(tree.submodels_path,
                                                                       os.path.join("odm_orthophoto",
                                                                                    "odm_orthophoto_feathered.tif"),
                                                                       os.path.join("odm_orthophoto",
                                                                                    "odm_orthophoto_cut.tif"),
                                                                       )

                    if len(all_orthos_and_ortho_cuts) > 1:
                        log.ODM_INFO(
                            "Found %s submodels with valid orthophotos and cutlines" % len(all_orthos_and_ortho_cuts))

                        # TODO: histogram matching via rasterio
                        # currently parts have different color tones

                        if io.file_exists(tree.odm_orthophoto_tif):
                            os.remove(tree.odm_orthophoto_tif)

                        orthophoto_vars = orthophoto.get_orthophoto_vars(args)
                        orthophoto.merge(all_orthos_and_ortho_cuts, tree.odm_orthophoto_tif, orthophoto_vars)
                        orthophoto.post_orthophoto_steps(args, merged_bounds_file, tree.odm_orthophoto_tif,
                                                         tree.orthophoto_tiles)
                    elif len(all_orthos_and_ortho_cuts) == 1:
                        # Simply copy
                        log.ODM_WARNING("A single orthophoto/cutline pair was found between all submodels.")
                        shutil.copyfile(all_orthos_and_ortho_cuts[0][0], tree.odm_orthophoto_tif)
                    else:
                        log.ODM_WARNING(
                            "No orthophoto/cutline pairs were found in any of the submodels. No orthophoto will be generated.")
                else:
                    log.ODM_WARNING("Found merged orthophoto in %s" % tree.odm_orthophoto_tif)

            self.update_progress(75)

            # Merge DEMs
            def merge_dems(dem_filename, human_name):
                if not io.dir_exists(tree.path('odm_dem')):
                    system.mkdir_p(tree.path('odm_dem'))

                dem_file = tree.path("odm_dem", dem_filename)
                if not io.file_exists(dem_file) or self.rerun():
                    all_dems = get_submodel_paths(tree.submodels_path, "odm_dem", dem_filename)
                    log.ODM_INFO("Merging %ss" % human_name)

                    # Merge
                    dem_vars = utils.get_dem_vars(args)
                    eu_map_source = None  # Default

                    # Use DSM's euclidean map for DTMs
                    # (requires the DSM to be computed)
                    if human_name == "DTM":
                        eu_map_source = "dsm"

                    euclidean_merge_dems(all_dems, dem_file, dem_vars, euclidean_map_source=eu_map_source)

                    if io.file_exists(dem_file):
                        # Crop
                        if args.crop > 0:
                            Cropper.crop(merged_bounds_file, dem_file, dem_vars,
                                         keep_original=not args.optimize_disk_space)
                        log.ODM_INFO("Created %s" % dem_file)

                        if args.tiles:
                            generate_dem_tiles(dem_file, tree.path("%s_tiles" % human_name.lower()),
                                               args.max_concurrency)
                    else:
                        log.ODM_WARNING("Cannot merge %s, %s was not created" % (human_name, dem_file))

                else:
                    log.ODM_WARNING("Found merged %s in %s" % (human_name, dem_filename))

            if args.merge in ['all', 'dem'] and args.dsm:
                merge_dems("dsm.tif", "DSM")

            if args.merge in ['all', 'dem'] and args.dtm:
                merge_dems("dtm.tif", "DTM")

            self.update_progress(95)

            # Merge reports
            if not io.dir_exists(tree.odm_report):
                system.mkdir_p(tree.odm_report)

            geojson_shots = tree.path(tree.odm_report, "shots.geojson")
            if not io.file_exists(geojson_shots) or self.rerun():
                geojson_shots_files = get_submodel_paths(tree.submodels_path, "odm_report", "shots.geojson")
                log.ODM_INFO("Merging %s shots.geojson files" % len(geojson_shots_files))
                merge_geojson_shots(geojson_shots_files, geojson_shots)
            else:
                log.ODM_WARNING("Found merged shots.geojson in %s" % tree.odm_report)

            # Stop the pipeline short! We're done.
            self.next_stage = None
        else:
            log.ODM_INFO("Normal dataset, nothing to merge.")
            self.progress = 0.0
Beispiel #2
0
    def process(self, args, outputs):
        tree = outputs['tree']
        reconstruction = outputs['reconstruction']

        # Export GCP information if available

        gcp_export_file = tree.path("odm_georeferencing", "ground_control_points.gpkg")
        gcp_gml_export_file = tree.path("odm_georeferencing", "ground_control_points.gml")
        gcp_geojson_export_file = tree.path("odm_georeferencing", "ground_control_points.geojson")

        if reconstruction.has_gcp() and (not io.file_exists(gcp_export_file) or self.rerun()):
            octx = OSFMContext(tree.opensfm)
            gcps = octx.ground_control_points(reconstruction.georef.proj4())

            if len(gcps):
                gcp_schema = {
                    'geometry': 'Point',
                    'properties': OrderedDict([
                        ('id', 'str'),
                        ('observations_count', 'int'),
                        ('observations_list', 'str'),
                        ('error_x', 'float'),
                        ('error_y', 'float'),
                        ('error_z', 'float'),
                    ])
                }

                # Write GeoPackage
                with fiona.open(gcp_export_file, 'w', driver="GPKG", 
                                crs=fiona.crs.from_string(reconstruction.georef.proj4()),
                                schema=gcp_schema) as f:
                    for gcp in gcps:
                        f.write({
                            'geometry': {
                                'type': 'Point',
                                'coordinates': gcp['coordinates'],
                            },
                            'properties': OrderedDict([
                                ('id', gcp['id']),
                                ('observations_count', len(gcp['observations'])),
                                ('observations_list', ",".join([obs['shot_id'] for obs in gcp['observations']])),
                                ('error_x', gcp['error'][0]),
                                ('error_y', gcp['error'][1]),
                                ('error_z', gcp['error'][2]),
                            ])
                        })
                
                # Write GML
                try:
                    system.run('ogr2ogr -of GML "{}" "{}"'.format(gcp_gml_export_file, gcp_export_file))
                except Exception as e:
                    log.ODM_WARNING("Cannot generate ground control points GML file: %s" % str(e))
            
                # Write GeoJSON
                geojson = {
                    'type': 'FeatureCollection',
                    'features': []
                }

                from_srs = CRS.from_proj4(reconstruction.georef.proj4())
                to_srs = CRS.from_epsg(4326)
                transformer = location.transformer(from_srs, to_srs)

                for gcp in gcps:
                    properties = gcp.copy()
                    del properties['coordinates']

                    geojson['features'].append({
                        'type': 'Feature',
                        'geometry': {
                            'type': 'Point',
                            'coordinates': transformer.TransformPoint(*gcp['coordinates']),
                        },
                        'properties': properties
                    })
                
                with open(gcp_geojson_export_file, 'w') as f:
                    f.write(json.dumps(geojson, indent=4))

            else:
                log.ODM_WARNING("GCPs could not be loaded for writing to %s" % gcp_export_file)

        if not io.file_exists(tree.odm_georeferencing_model_laz) or self.rerun():
            cmd = ('pdal translate -i "%s" -o \"%s\"' % (tree.filtered_point_cloud, tree.odm_georeferencing_model_laz))
            stages = ["ferry"]
            params = [
                '--filters.ferry.dimensions="views => UserData"',
                '--writers.las.compression="lazip"',
            ]

            if reconstruction.is_georeferenced():
                log.ODM_INFO("Georeferencing point cloud")

                stages.append("transformation")
                params += [
                    '--filters.transformation.matrix="1 0 0 %s 0 1 0 %s 0 0 1 0 0 0 0 1"' % reconstruction.georef.utm_offset(),
                    '--writers.las.offset_x=%s' % reconstruction.georef.utm_east_offset,
                    '--writers.las.offset_y=%s' % reconstruction.georef.utm_north_offset,
                    '--writers.las.scale_x=0.001',
                    '--writers.las.scale_y=0.001',
                    '--writers.las.scale_z=0.001',
                    '--writers.las.offset_z=0',
                    '--writers.las.a_srs="%s"' % reconstruction.georef.proj4()
                ]

                if reconstruction.has_gcp() and io.file_exists(gcp_gml_export_file):
                    log.ODM_INFO("Embedding GCP info in point cloud")
                    params += [
                        '--writers.las.vlrs="{\\\"filename\\\": \\\"%s\\\", \\\"user_id\\\": \\\"ODM_GCP\\\", \\\"description\\\": \\\"Ground Control Points (GML)\\\"}"' % gcp_gml_export_file.replace(os.sep, "/")
                    ]
                
                system.run(cmd + ' ' + ' '.join(stages) + ' ' + ' '.join(params))

                self.update_progress(50)

                if args.crop > 0:
                    log.ODM_INFO("Calculating cropping area and generating bounds shapefile from point cloud")
                    cropper = Cropper(tree.odm_georeferencing, 'odm_georeferenced_model')
                    
                    if args.fast_orthophoto:
                        decimation_step = 4
                    else:
                        decimation_step = 40
                    
                    # More aggressive decimation for large datasets
                    if not args.fast_orthophoto:
                        decimation_step *= int(len(reconstruction.photos) / 1000) + 1
                        decimation_step = min(decimation_step, 95)
                        
                    try:
                        cropper.create_bounds_gpkg(tree.odm_georeferencing_model_laz, args.crop, 
                                                    decimation_step=decimation_step)
                    except:
                        log.ODM_WARNING("Cannot calculate crop bounds! We will skip cropping")
                        args.crop = 0
                
                if 'boundary' in outputs and args.crop == 0:
                    log.ODM_INFO("Using boundary JSON as cropping area")
                    
                    bounds_base, _ = os.path.splitext(tree.odm_georeferencing_model_laz)
                    bounds_json = bounds_base + ".bounds.geojson"
                    bounds_gpkg = bounds_base + ".bounds.gpkg"
                    export_to_bounds_files(outputs['boundary'], reconstruction.get_proj_srs(), bounds_json, bounds_gpkg)
            else:
                log.ODM_INFO("Converting point cloud (non-georeferenced)")
                system.run(cmd + ' ' + ' '.join(stages) + ' ' + ' '.join(params))
        
            point_cloud.post_point_cloud_steps(args, tree, self.rerun())
        else:
            log.ODM_WARNING('Found a valid georeferenced model in: %s'
                            % tree.odm_georeferencing_model_laz)
        
        if args.optimize_disk_space and io.file_exists(tree.odm_georeferencing_model_laz) and io.file_exists(tree.filtered_point_cloud):
            os.remove(tree.filtered_point_cloud)
Beispiel #3
0
    def process(self, args, outputs):
        tree = outputs['tree']
        reconstruction = outputs['reconstruction']

        if not io.file_exists(
                tree.odm_georeferencing_model_laz) or self.rerun():
            cmd = (
                'pdal translate -i "%s" -o \"%s\"' %
                (tree.filtered_point_cloud, tree.odm_georeferencing_model_laz))
            stages = ["ferry"]
            params = [
                '--filters.ferry.dimensions="views => UserData"',
                '--writers.las.compression="lazip"',
            ]

            if reconstruction.is_georeferenced():
                log.ODM_INFO("Georeferencing point cloud")

                stages.append("transformation")
                params += [
                    '--filters.transformation.matrix="1 0 0 %s 0 1 0 %s 0 0 1 0 0 0 0 1"'
                    % reconstruction.georef.utm_offset(),
                    '--writers.las.offset_x=%s' %
                    reconstruction.georef.utm_east_offset,
                    '--writers.las.offset_y=%s' %
                    reconstruction.georef.utm_north_offset,
                    '--writers.las.offset_z=0',
                    '--writers.las.a_srs="%s"' % reconstruction.georef.proj4()
                ]

                system.run(cmd + ' ' + ' '.join(stages) + ' ' +
                           ' '.join(params))

                self.update_progress(50)

                if args.crop > 0:
                    log.ODM_INFO(
                        "Calculating cropping area and generating bounds shapefile from point cloud"
                    )
                    cropper = Cropper(tree.odm_georeferencing,
                                      'odm_georeferenced_model')

                    if args.fast_orthophoto:
                        decimation_step = 10
                    else:
                        decimation_step = 40

                    # More aggressive decimation for large datasets
                    if not args.fast_orthophoto:
                        decimation_step *= int(
                            len(reconstruction.photos) / 1000) + 1
                        decimation_step = min(decimation_step, 95)

                    try:
                        cropper.create_bounds_gpkg(
                            tree.odm_georeferencing_model_laz,
                            args.crop,
                            decimation_step=decimation_step)
                    except:
                        log.ODM_WARNING(
                            "Cannot calculate crop bounds! We will skip cropping"
                        )
                        args.crop = 0
            else:
                log.ODM_INFO("Converting point cloud (non-georeferenced)")
                system.run(cmd + ' ' + ' '.join(stages) + ' ' +
                           ' '.join(params))

            point_cloud.post_point_cloud_steps(args, tree, self.rerun())
        else:
            log.ODM_WARNING('Found a valid georeferenced model in: %s' %
                            tree.odm_georeferencing_model_laz)

        if args.optimize_disk_space and io.file_exists(
                tree.odm_georeferencing_model_laz) and io.file_exists(
                    tree.filtered_point_cloud):
            os.remove(tree.filtered_point_cloud)
    def process(self, args, outputs):
        tree = outputs['tree']
        reconstruction = outputs['reconstruction']

        doPointCloudGeo = True
        transformPointCloud = True
        verbose = '-verbose' if self.params.get('verbose') else ''

        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!
            if not args.use_3dmesh:
                nonloc.runs += [{
                    'georeferencing_dir':
                    os.path.join(tree.odm_25dgeoreferencing, subdir),
                    'texturing_dir':
                    os.path.join(tree.odm_25dtexturing, subdir),
                }]

            if not args.skip_3dmodel and (primary or args.use_3dmesh):
                nonloc.runs += [{
                    'georeferencing_dir':
                    tree.odm_georeferencing,
                    'texturing_dir':
                    os.path.join(tree.odm_texturing, subdir),
                }]

        if reconstruction.multi_camera:
            for band in reconstruction.multi_camera:
                primary = band['name'] == get_primary_band_name(
                    reconstruction.multi_camera, args.primary_band)
                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'], tree.odm_georeferencing_model_obj_geo)
            odm_georeferencing_model_obj = os.path.join(
                r['texturing_dir'], tree.odm_textured_model_obj)
            odm_georeferencing_log = os.path.join(r['georeferencing_dir'],
                                                  tree.odm_georeferencing_log)
            odm_georeferencing_transform_file = os.path.join(
                r['georeferencing_dir'],
                tree.odm_georeferencing_transform_file)
            odm_georeferencing_model_txt_geo_file = os.path.join(
                r['georeferencing_dir'], tree.odm_georeferencing_model_txt_geo)

            if not io.file_exists(odm_georeferencing_model_obj_geo) or \
               not io.file_exists(tree.odm_georeferencing_model_laz) or self.rerun():

                # odm_georeference definitions
                kwargs = {
                    'bin': context.odm_modules_path,
                    'input_pc_file': tree.filtered_point_cloud,
                    'bundle': tree.opensfm_bundle,
                    'imgs': tree.dataset_raw,
                    'imgs_list': tree.opensfm_bundle_list,
                    'model': odm_georeferencing_model_obj,
                    'log': odm_georeferencing_log,
                    'input_trans_file': tree.opensfm_transformation,
                    'transform_file': odm_georeferencing_transform_file,
                    'coords': tree.odm_georeferencing_coords,
                    'output_pc_file': tree.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(
                        tree.opensfm_transformation) and io.file_exists(
                            tree.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(tree.odm_georeferencing_coords):
                    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(tree.odm_georeferencing,
                                          'odm_georeferenced_model')

                        if args.fast_orthophoto:
                            decimation_step = 10
                        else:
                            decimation_step = 40

                        # More aggressive decimation for large datasets
                        if not args.fast_orthophoto:
                            decimation_step *= int(
                                len(reconstruction.photos) / 1000) + 1
                            decimation_step = min(decimation_step, 95)

                        try:
                            cropper.create_bounds_gpkg(
                                tree.odm_georeferencing_model_laz,
                                args.crop,
                                decimation_step=decimation_step)
                        except:
                            log.ODM_WARNING(
                                "Cannot calculate crop bounds! We will skip cropping"
                            )
                            args.crop = 0

                    # 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' %
                                tree.odm_georeferencing_model_laz)

            if args.optimize_disk_space and io.file_exists(
                    tree.odm_georeferencing_model_laz) and io.file_exists(
                        tree.filtered_point_cloud):
                os.remove(tree.filtered_point_cloud)

            progress += progress_per_run
            self.update_progress(progress)
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)