OpenDroneMap-ODM/scripts/odm_orthophoto.py

133 wiersze
6.0 KiB
Python
Czysty Zwykły widok Historia

2019-04-22 19:14:39 +00:00
import os
2015-12-01 16:26:13 +00:00
from opendm import io
from opendm import log
from opendm import system
from opendm import context
2016-02-23 17:47:43 +00:00
from opendm import types
2018-08-08 19:41:08 +00:00
from opendm import gsd
from opendm import orthophoto
from opendm.concurrency import get_max_memory
2018-01-04 17:08:59 +00:00
from opendm.cropper import Cropper
from opendm.cutline import compute_cutline
2016-02-23 17:47:43 +00:00
2015-12-01 16:26:13 +00:00
2019-04-22 19:14:39 +00:00
class ODMOrthoPhotoStage(types.ODM_Stage):
def process(self, args, outputs):
tree = outputs['tree']
reconstruction = outputs['reconstruction']
verbose = '-verbose' if args.verbose else ''
2015-12-01 16:26:13 +00:00
# define paths and create working directories
system.mkdir_p(tree.odm_orthophoto)
2015-12-01 16:26:13 +00:00
2019-04-22 19:14:39 +00:00
if not io.file_exists(tree.odm_orthophoto_file) or self.rerun():
2016-02-23 17:47:43 +00:00
# odm_orthophoto definitions
kwargs = {
'bin': context.odm_modules_path,
'log': tree.odm_orthophoto_log,
'ortho': tree.odm_orthophoto_file,
'corners': tree.odm_orthophoto_corners,
'res': 1.0 / (gsd.cap_resolution(args.orthophoto_resolution, tree.opensfm_reconstruction, ignore_gsd=args.ignore_gsd) / 100.0),
2016-12-11 22:16:11 +00:00
'verbose': verbose
}
# Have geo coordinates?
georef = reconstruction.georef
# Check if the georef object is initialized
# (during a --rerun this might not be)
# TODO: we should move this to a more central
# location (perhaps during the dataset initialization)
if georef and not georef.utm_east_offset:
2019-02-15 17:15:01 +00:00
georeferencing_dir = tree.odm_georeferencing if args.use_3dmesh and not args.skip_3dmodel else tree.odm_25dgeoreferencing
odm_georeferencing_model_txt_geo_file = os.path.join(georeferencing_dir, tree.odm_georeferencing_model_txt_geo)
if io.file_exists(odm_georeferencing_model_txt_geo_file):
georef.extract_offsets(odm_georeferencing_model_txt_geo_file)
else:
log.ODM_WARNING('Cannot read UTM offset from {}. An orthophoto will not be generated.'.format(odm_georeferencing_model_txt_geo_file))
if georef:
if args.use_3dmesh:
2017-04-05 18:27:52 +00:00
kwargs['model_geo'] = os.path.join(tree.odm_texturing, tree.odm_georeferencing_model_obj_geo)
else:
kwargs['model_geo'] = os.path.join(tree.odm_25dtexturing, tree.odm_georeferencing_model_obj_geo)
else:
if args.use_3dmesh:
kwargs['model_geo'] = os.path.join(tree.odm_texturing, tree.odm_textured_model_obj)
else:
kwargs['model_geo'] = os.path.join(tree.odm_25dtexturing, tree.odm_textured_model_obj)
2016-02-23 17:47:43 +00:00
# run odm_orthophoto
system.run('{bin}/odm_orthophoto -inputFile {model_geo} '
2016-12-11 22:16:11 +00:00
'-logFile {log} -outputFile {ortho} -resolution {res} {verbose} '
'-outputCornerFile {corners}'.format(**kwargs))
2016-02-23 17:47:43 +00:00
2018-01-30 20:04:26 +00:00
# Create georeferenced GeoTiff
geotiffcreated = False
if georef and georef.projection and georef.utm_east_offset and georef.utm_north_offset:
2018-01-30 20:04:26 +00:00
ulx = uly = lrx = lry = 0.0
with open(tree.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(georef.utm_east_offset)
lry = float(tokens[1]) + \
float(georef.utm_north_offset)
lrx = float(tokens[2]) + \
float(georef.utm_east_offset)
uly = float(tokens[3]) + \
float(georef.utm_north_offset)
log.ODM_INFO('Creating GeoTIFF')
orthophoto_vars = orthophoto.get_orthophoto_vars(args)
2018-01-30 20:04:26 +00:00
kwargs = {
'ulx': ulx,
'uly': uly,
'lrx': lrx,
'lry': lry,
'vars': ' '.join(['-co %s=%s' % (k, orthophoto_vars[k]) for k in orthophoto_vars]),
2018-01-30 20:04:26 +00:00
'proj': georef.projection.srs,
'png': tree.odm_orthophoto_file,
'tiff': tree.odm_orthophoto_tif,
'log': tree.odm_orthophoto_tif_log,
'max_memory': get_max_memory(),
2018-01-30 20:04:26 +00:00
}
system.run('gdal_translate -a_ullr {ulx} {uly} {lrx} {lry} '
'{vars} '
2018-01-30 20:04:26 +00:00
'-a_srs \"{proj}\" '
'--config GDAL_CACHEMAX {max_memory}% '
2018-01-30 20:04:26 +00:00
'{png} {tiff} > {log}'.format(**kwargs))
bounds_file_path = os.path.join(tree.odm_georeferencing, 'odm_georeferenced_model.bounds.gpkg')
# Cutline computation, before cropping
# We want to use the full orthophoto, not the cropped one.
2019-04-29 21:35:12 +00:00
if args.orthophoto_cutline:
compute_cutline(tree.odm_orthophoto_tif,
bounds_file_path,
os.path.join(tree.odm_orthophoto, "cutline.gpkg"),
args.max_concurrency)
2018-01-30 20:04:26 +00:00
if args.crop > 0:
Cropper.crop(bounds_file_path, tree.odm_orthophoto_tif, orthophoto_vars)
if args.build_overviews:
orthophoto.build_overviews(tree.odm_orthophoto_tif)
2018-01-30 20:04:26 +00:00
geotiffcreated = True
if not geotiffcreated:
log.ODM_WARNING('No geo-referenced orthophoto created due '
'to missing geo-referencing or corner coordinates.')
2016-02-23 17:47:43 +00:00
else:
log.ODM_WARNING('Found a valid orthophoto in: %s' % tree.odm_orthophoto_file)