Started adding odm_dem module

pull/612/head
Piero Toffanin 2017-06-23 11:20:46 -04:00
rodzic fed4cb95dc
commit af0c2c986f
7 zmienionych plików z 216 dodań i 24 usunięć

Wyświetl plik

@ -14,7 +14,7 @@ RUN apt-get install --no-install-recommends -y git cmake python-pip build-essent
libgtk2.0-dev libavcodec-dev libavformat-dev libswscale-dev python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libflann-dev \
libproj-dev libxext-dev liblapack-dev libeigen3-dev libvtk5-dev python-networkx libgoogle-glog-dev libsuitesparse-dev libboost-filesystem-dev libboost-iostreams-dev \
libboost-regex-dev libboost-python-dev libboost-date-time-dev libboost-thread-dev python-pyproj python-empy python-nose python-pyside python-pyexiv2 python-scipy \
jhead liblas-bin python-matplotlib libatlas-base-dev libgmp-dev libmpfr-dev swig2.0 python-wheel libboost-log-dev libxslt-dev
jhead liblas-bin python-matplotlib libatlas-base-dev libgmp-dev libmpfr-dev swig2.0 python-wheel libboost-log-dev
RUN apt-get remove libdc1394-22-dev
RUN pip install --upgrade pip

Wyświetl plik

@ -89,8 +89,7 @@ install() {
echo "Installing lidar2dems Dependencies"
sudo apt-get install -y -qq swig2.0 \
python-wheel \
libboost-log-dev \
libxslt-dev
libboost-log-dev
sudo pip install -U https://github.com/pierotofy/gippy/archive/v0.3.9.tar.gz

Wyświetl plik

@ -10,7 +10,7 @@ import sys
# parse arguments
processopts = ['resize', 'opensfm', 'slam', 'cmvs', 'pmvs',
'odm_meshing', 'odm_25dmeshing', 'mvs_texturing', 'odm_georeferencing',
'odm_orthophoto']
'odm_dem', 'odm_orthophoto']
with open(io.join_paths(context.root_path, 'VERSION')) as version_file:
__version__ = version_file.read().strip()
@ -341,34 +341,77 @@ def config():
help=('Use this tag if you have a gcp_list.txt but '
'want to use the exif geotags instead'))
parser.add_argument('--dem',
parser.add_argument('--dtm',
action='store_true',
default=False,
help='Use this tag to build a DEM using a progressive '
'morphological filter in PDAL.')
help='Use this tag to build a DTM (Digital Terrain Model, ground only) using a progressive '
'morphological filter in PDAL. Check the --dem* parameters for fine tuning.')
parser.add_argument('--dsm',
action='store_true',
default=False,
help='Use this tag to build a DSM (Digital Surface Model, ground + objects) using a progressive '
'morphological filter in PDAL. Check the --dem* parameters for fine tuning.')
parser.add_argument('--dem-sample-radius',
metavar='<float>',
default=1.0,
type=float,
help='Minimum distance between samples for DEM '
parser.add_argument('--dem-gapfill-steps',
metavar='<positive integer>',
default=4,
type=int,
help='Number of steps used to fill areas with gaps. Set to 0 to disable gap filling. '
'Starting with a radius equal to the output resolution, N different DEMs are generated with '
'progressively bigger radius using the inverse distance weighted (IDW) algorithm '
'and merged together. Remaining gaps are then merged using linear interpolation. '
'generation.\nDefault=%(default)s')
parser.add_argument('--dem-resolution',
metavar='<float>',
type=float,
default=2,
default=0.1,
help='Length of raster cell edges in X/Y units.'
'\nDefault: %(default)s')
parser.add_argument('--dem-radius',
metavar='<float>',
parser.add_argument('--dem-maxangle',
metavar='<positive float>',
type=float,
default=0.5,
help='Radius about cell center bounding points to '
'use to calculate a cell value.\nDefault: '
default=20,
help='Points that are more than maxangle degrees off-nadir are discarded. '
'\nDefault: '
'%(default)s')
parser.add_argument('--dem-maxsd',
metavar='<positive float>',
type=float,
default=2.5,
help='Points that deviate more than maxsd standard deviations from the local mean '
'are discarded. \nDefault: '
'%(default)s')
parser.add_argument('--dem-approximate',
action='store_true',
default=False,
help='Use this tag use the approximate progressive '
'morphological filter in PDAL, which computes DEMs faster '
'but is not as accurate.')
parser.add_argument('--dem-decimation',
metavar='<positive integer>',
default=1,
type=int,
help='Decimate the points before generating the DEM. 1 is no decimation (full quality). '
'100 decimates ~99% of the points. Useful for speeding up '
'generation.\nDefault=%(default)s')
parser.add_argument('--dem-terrain-type',
metavar='<string>',
choices=['FlatNonForest', 'FlatForest', 'ComplexNonForest', 'ComplexForest'],
default='ComplexForest',
help='Specifies the type of terrain. This mainly helps reduce processing time. '
'FlatNonForest: Relatively flat region with little to no vegetation (slope 1, cell size 3)'
'FlatForest: Relatively flat region that is forested (slope 1, cell size 2)'
'ComplexNonForest: Varied terrain with little to no vegetation (slope 5, cell size 2)'
'ComplexForest: Varied terrain that is forested (slope 10, cell size 2)'
'\nDefault=%(default)s')
parser.add_argument('--orthophoto-resolution',
metavar='<float > 0.0>',
default=20.0,

Wyświetl plik

@ -15,8 +15,9 @@ tasks_dict = {'1': 'resize',
'5': 'odm_meshing',
'6': 'mvs_texturing',
'7': 'odm_georeferencing',
'8': 'odm_orthophoto',
'9': 'zip_results'}
'8': 'odm_dem',
'9': 'odm_orthophoto',
'10': 'zip_results'}
class ODMTaskManager(object):

Wyświetl plik

@ -435,3 +435,6 @@ class ODM_Tree(object):
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')
self.odm_orthophoto_gdaladdo_log = io.join_paths(self.odm_orthophoto, 'gdaladdo_log.txt')
def path(self, **args):
return io.join_paths(self.root_path, **args)

Wyświetl plik

@ -16,6 +16,7 @@ from odm_meshing import ODMeshingCell
from mvstex import ODMMvsTexCell
from odm_georeferencing import ODMGeoreferencingCell
from odm_orthophoto import ODMOrthoPhotoCell
from odm_dem import ODMDEMCell
class ODMApp(ecto.BlackBox):
@ -73,11 +74,8 @@ class ODMApp(ecto.BlackBox):
'georeferencing': ODMGeoreferencingCell(img_size=p.args.resize_to,
gcp_file=p.args.gcp,
use_exif=p.args.use_exif,
dem=p.args.dem,
sample_radius=p.args.dem_sample_radius,
gdal_res=p.args.dem_resolution,
gdal_radius=p.args.dem_radius,
verbose=p.args.verbose),
'dem': ODMDEMCell(verbose=p.args.verbose),
'orthophoto': ODMOrthoPhotoCell(resolution=p.args.orthophoto_resolution,
t_srs=p.args.orthophoto_target_srs,
no_tiled=p.args.orthophoto_no_tiled,

148
scripts/odm_dem.py 100644
Wyświetl plik

@ -0,0 +1,148 @@
import ecto, os
from opendm import io
from opendm import log
from opendm import system
from opendm import context
from opendm import types
class ODMDemCell(ecto.Cell):
def declare_params(self, params):
params.declare("verbose", 'print additional messages to console', False)
def declare_io(self, params, inputs, outputs):
inputs.declare("args", "The application arguments.", {})
def process(self, inputs, outputs):
# Benchmarking
start_time = system.now_raw()
log.ODM_INFO('Running ODM DEM Cell')
# get inputs
args = self.inputs.args
verbose = '-v' if self.params.verbose else ''
# define paths and create working directories
odm_dem_root = tree.path('odm_dem')
system.mkdir_p(odm_dem_root)
dsm_output_filename = os.path.join(odm_dem_root, )
# check if we rerun cell or not
rerun_cell = (args.rerun is not None and
args.rerun == 'odm_dem') or \
(args.rerun_all) or \
(args.rerun_from is not None and
'odm_dem' in args.rerun_from)
if not io.file_exists(tree.odm_orthophoto_file) or rerun_cell:
# 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': self.params.resolution,
'verbose': verbose
}
# Have geo coordinates?
if io.file_exists(tree.odm_georeferencing_coords):
if args.use_25dmesh:
kwargs['model_geo'] = os.path.join(tree.odm_25dtexturing, tree.odm_georeferencing_model_obj_geo)
else:
kwargs['model_geo'] = os.path.join(tree.odm_texturing, tree.odm_georeferencing_model_obj_geo)
else:
if args.use_25dmesh:
kwargs['model_geo'] = os.path.join(tree.odm_25dtexturing, tree.odm_textured_model_obj)
else:
kwargs['model_geo'] = os.path.join(tree.odm_texturing, tree.odm_textured_model_obj)
# run odm_orthophoto
system.run('{bin}/odm_orthophoto -inputFile {model_geo} '
'-logFile {log} -outputFile {ortho} -resolution {res} {verbose} '
'-outputCornerFile {corners}'.format(**kwargs))
if not io.file_exists(tree.odm_georeferencing_coords):
log.ODM_WARNING('No coordinates file. A georeferenced raster '
'will not be created')
else:
# Create georeferenced GeoTiff
geotiffcreated = False
georef = types.ODM_GeoRef()
# creates the coord refs # TODO I don't want to have to do this twice- after odm_georef
georef.parse_coordinate_system(tree.odm_georeferencing_coords)
if georef.epsg and georef.utm_east_offset and georef.utm_north_offset:
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')
kwargs = {
'ulx': ulx,
'uly': uly,
'lrx': lrx,
'lry': lry,
'tiled': '' if self.params.no_tiled else '-co TILED=yes ',
'compress': self.params.compress,
'predictor': '-co PREDICTOR=2 ' if self.params.compress in
['LZW', 'DEFLATE'] else '',
'epsg': georef.epsg,
't_srs': self.params.t_srs or "EPSG:{0}".format(georef.epsg),
'bigtiff': self.params.bigtiff,
'png': tree.odm_orthophoto_file,
'tiff': tree.odm_orthophoto_tif,
'log': tree.odm_orthophoto_tif_log
}
system.run('gdal_translate -a_ullr {ulx} {uly} {lrx} {lry} '
'{tiled} '
'-co BIGTIFF={bigtiff} '
'-co COMPRESS={compress} '
'{predictor} '
'-co BLOCKXSIZE=512 '
'-co BLOCKYSIZE=512 '
'-co NUM_THREADS=ALL_CPUS '
'-a_srs \"EPSG:{epsg}\" '
'{png} {tiff} > {log}'.format(**kwargs))
if self.params.build_overviews:
log.ODM_DEBUG("Building Overviews")
kwargs = {
'orthophoto': tree.odm_orthophoto_tif,
'log': tree.odm_orthophoto_gdaladdo_log
}
# Run gdaladdo
system.run('gdaladdo -ro -r average '
'--config BIGTIFF_OVERVIEW IF_SAFER '
'--config COMPRESS_OVERVIEW JPEG '
'{orthophoto} 2 4 8 16 > {log}'.format(**kwargs))
geotiffcreated = True
if not geotiffcreated:
log.ODM_WARNING('No geo-referenced orthophoto created due '
'to missing geo-referencing or corner coordinates.')
else:
log.ODM_WARNING('Found a valid orthophoto in: %s' % tree.odm_orthophoto_file)
if args.time:
system.benchmark(start_time, tree.benchmarking, 'Orthophoto')
log.ODM_INFO('Running ODM OrthoPhoto Cell - Finished')
return ecto.OK if args.end_with != 'odm_orthophoto' else ecto.QUIT