From fb85b754fb7c5e0180ce8da87b207ceb662bbfaa Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 23 Jan 2024 17:03:36 -0500 Subject: [PATCH 1/2] Classify point cloud before generating derivative outputs --- VERSION | 2 +- opendm/config.py | 4 ++-- opendm/point_cloud.py | 28 ++++++++++++++++++++++++++++ stages/odm_dem.py | 29 +---------------------------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/VERSION b/VERSION index fa7adc7a..18091983 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.5 +3.4.0 diff --git a/opendm/config.py b/opendm/config.py index 3f51ff20..3db8151f 100755 --- a/opendm/config.py +++ b/opendm/config.py @@ -60,14 +60,14 @@ rerun_stages = { 'orthophoto_no_tiled': 'odm_orthophoto', 'orthophoto_png': 'odm_orthophoto', 'orthophoto_resolution': 'odm_orthophoto', - 'pc_classify': 'odm_dem', + 'pc_classify': 'odm_georeferencing', 'pc_copc': 'odm_georeferencing', 'pc_csv': 'odm_georeferencing', 'pc_ept': 'odm_georeferencing', 'pc_filter': 'openmvs', 'pc_las': 'odm_georeferencing', 'pc_quality': 'opensfm', - 'pc_rectify': 'odm_dem', + 'pc_rectify': 'odm_georeferencing', 'pc_sample': 'odm_filterpoints', 'pc_skip_geometric': 'openmvs', 'primary_band': 'dataset', diff --git a/opendm/point_cloud.py b/opendm/point_cloud.py index abe7ee91..0c16c493 100644 --- a/opendm/point_cloud.py +++ b/opendm/point_cloud.py @@ -9,6 +9,8 @@ from opendm.concurrency import parallel_map from opendm.utils import double_quote from opendm.boundary import as_polygon, as_geojson from opendm.dem.pdal import run_pipeline +from opendm.opc import classify +from opendm.dem import commands def ply_info(input_ply): if not os.path.exists(input_ply): @@ -274,6 +276,32 @@ def merge_ply(input_point_cloud_files, output_file, dims=None): system.run(' '.join(cmd)) def post_point_cloud_steps(args, tree, rerun=False): + # Classify and rectify before generating derivate files + if args.pc_classify: + pc_classify_marker = os.path.join(tree.odm_georeferencing, 'pc_classify_done.txt') + + if not io.file_exists(pc_classify_marker) or rerun: + log.ODM_INFO("Classifying {} using Simple Morphological Filter (1/2)".format(tree.odm_georeferencing_model_laz)) + commands.classify(tree.odm_georeferencing_model_laz, + args.smrf_scalar, + args.smrf_slope, + args.smrf_threshold, + args.smrf_window + ) + + log.ODM_INFO("Classifying {} using OpenPointClass (2/2)".format(tree.odm_georeferencing_model_laz)) + classify(tree.odm_georeferencing_model_laz, args.max_concurrency) + + with open(pc_classify_marker, 'w') as f: + f.write('Classify: smrf\n') + f.write('Scalar: {}\n'.format(args.smrf_scalar)) + f.write('Slope: {}\n'.format(args.smrf_slope)) + f.write('Threshold: {}\n'.format(args.smrf_threshold)) + f.write('Window: {}\n'.format(args.smrf_window)) + + if args.pc_rectify: + commands.rectify(tree.odm_georeferencing_model_laz) + # XYZ point cloud output if args.pc_csv: log.ODM_INFO("Creating CSV file (XYZ format)") diff --git a/stages/odm_dem.py b/stages/odm_dem.py index 1146879a..6964e036 100755 --- a/stages/odm_dem.py +++ b/stages/odm_dem.py @@ -12,7 +12,6 @@ from opendm.cropper import Cropper from opendm import pseudogeo from opendm.tiles.tiler import generate_dem_tiles from opendm.cogeo import convert_to_cogeo -from opendm.opc import classify class ODMDEMStage(types.ODM_Stage): def process(self, args, outputs): @@ -35,7 +34,6 @@ class ODMDEMStage(types.ODM_Stage): ignore_resolution=ignore_resolution and args.ignore_gsd, has_gcp=reconstruction.has_gcp()) - log.ODM_INFO('Classify: ' + str(args.pc_classify)) log.ODM_INFO('Create DSM: ' + str(args.dsm)) log.ODM_INFO('Create DTM: ' + str(args.dtm)) log.ODM_INFO('DEM input file {0} found: {1}'.format(dem_input, str(pc_model_found))) @@ -45,34 +43,9 @@ class ODMDEMStage(types.ODM_Stage): if not io.dir_exists(odm_dem_root): system.mkdir_p(odm_dem_root) - if args.pc_classify and pc_model_found: - pc_classify_marker = os.path.join(odm_dem_root, 'pc_classify_done.txt') - - if not io.file_exists(pc_classify_marker) or self.rerun(): - log.ODM_INFO("Classifying {} using Simple Morphological Filter (1/2)".format(dem_input)) - commands.classify(dem_input, - args.smrf_scalar, - args.smrf_slope, - args.smrf_threshold, - args.smrf_window - ) - - log.ODM_INFO("Classifying {} using OpenPointClass (2/2)".format(dem_input)) - classify(dem_input, args.max_concurrency) - - with open(pc_classify_marker, 'w') as f: - f.write('Classify: smrf\n') - f.write('Scalar: {}\n'.format(args.smrf_scalar)) - f.write('Slope: {}\n'.format(args.smrf_slope)) - f.write('Threshold: {}\n'.format(args.smrf_threshold)) - f.write('Window: {}\n'.format(args.smrf_window)) - progress = 20 self.update_progress(progress) - if args.pc_rectify: - commands.rectify(dem_input) - # Do we need to process anything here? if (args.dsm or args.dtm) and pc_model_found: dsm_output_filename = os.path.join(odm_dem_root, 'dsm.tif') @@ -120,7 +93,7 @@ class ODMDEMStage(types.ODM_Stage): if args.cog: convert_to_cogeo(dem_geotiff_path, max_workers=args.max_concurrency) - progress += 30 + progress += 40 self.update_progress(progress) else: log.ODM_WARNING('Found existing outputs in: %s' % odm_dem_root) From 9fd3bf3eddbc856511eb931613b6157606c99f6c Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 23 Jan 2024 22:24:38 +0000 Subject: [PATCH 2/2] Improve SRT parser to handle abs_alt altitude reference --- opendm/video/srtparser.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/opendm/video/srtparser.py b/opendm/video/srtparser.py index c7188f86..fc5bf061 100644 --- a/opendm/video/srtparser.py +++ b/opendm/video/srtparser.py @@ -54,8 +54,10 @@ class SrtFileParser: if not self.gps_data: for d in self.data: lat, lon, alt = d.get('latitude'), d.get('longitude'), d.get('altitude') + if alt is None: + alt = 0 tm = d.get('start') - + if lat is not None and lon is not None: if self.ll_to_utm is None: self.ll_to_utm, self.utm_to_ll = location.utm_transformers_from_ll(lon, lat) @@ -127,6 +129,13 @@ class SrtFileParser: # 00:00:35,000 --> 00:00:36,000 # F/6.3, SS 60, ISO 100, EV 0, RTK (120.083799, 30.213635, 28), HOME (120.084146, 30.214243, 103.55m), D 75.36m, H 76.19m, H.S 0.30m/s, V.S 0.00m/s, F.PRY (-5.3°, 2.1°, 28.3°), G.PRY (-40.0°, 0.0°, 28.2°) + # DJI Unknown Model #1 + # 1 + # 00:00:00,000 --> 00:00:00,033 + # SrtCnt : 1, DiffTime : 33ms + # 2024-01-18 10:23:26.397 + # [iso : 150] [shutter : 1/5000.0] [fnum : 170] [ev : 0] [ct : 5023] [color_md : default] [focal_len : 240] [dzoom_ratio: 10000, delta:0],[latitude: -22.724555] [longitude: -47.602414] [rel_alt: 0.300 abs_alt: 549.679] + with open(self.filename, 'r') as f: iso = None @@ -211,4 +220,5 @@ class SrtFileParser: ("altitude: ([\d\.\-]+)", lambda v: float(v) if v != 0 else None), ("GPS \([\d\.\-]+,? [\d\.\-]+,? ([\d\.\-]+)\)", lambda v: float(v) if v != 0 else None), ("RTK \([-+]?\d+\.\d+, [-+]?\d+\.\d+, (-?\d+)\)", lambda v: float(v) if v != 0 else None), + ("abs_alt: ([\d\.\-]+)", lambda v: float(v) if v != 0 else None), ], line) \ No newline at end of file