From 79a641435632d0502426e055ea83bdd1ab20af12 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Mon, 28 Oct 2019 09:53:46 -0400 Subject: [PATCH] Added --pc-sample --- modules/odm_filterpoints/src/main.cpp | 30 ++++++++++++++++++--------- opendm/config.py | 8 +++++++ opendm/point_cloud.py | 16 ++++++++++---- stages/odm_filterpoints.py | 6 +++++- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/modules/odm_filterpoints/src/main.cpp b/modules/odm_filterpoints/src/main.cpp index 07c940c3..a4497c1e 100644 --- a/modules/odm_filterpoints/src/main.cpp +++ b/modules/odm_filterpoints/src/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "CmdLineParser.h" #include "Logger.h" #include "FloatPlyReader.hpp" @@ -15,12 +16,13 @@ cmdLineParameter< char* > cmdLineParameter< float > StandardDeviation( "sd" ) , MeanK ( "meank" ) , - Confidence ( "confidence" ); + Confidence ( "confidence" ) , + Sample ( "sample" ); cmdLineReadable Verbose( "verbose" ); cmdLineReadable* params[] = { - &InputFile , &OutputFile , &StandardDeviation, &MeanK, &Confidence, &Verbose , + &InputFile , &OutputFile , &StandardDeviation, &MeanK, &Confidence, &Sample, &Verbose , NULL }; @@ -66,33 +68,41 @@ int main(int argc, char **argv) { pdal::PointTable table; pdal::FloatPlyReader plyReader; + pdal::Stage *currentStage = &plyReader; plyReader.setOptions(inPlyOpts); pdal::RangeFilter confidenceFilter; if (Confidence.set){ + logWriter("Filtering confidence\n"); + pdal::Options confidenceFilterOpts; float confidenceValue = std::min(1.0f, std::max(Confidence.value, 0.0f)); std::ostringstream confidenceLimit; confidenceLimit << "confidence[" << confidenceValue << ":1]"; confidenceFilterOpts.add("limits", confidenceLimit.str()); - confidenceFilter.setInput(plyReader); + confidenceFilter.setInput(*currentStage); + currentStage = &confidenceFilter; confidenceFilter.setOptions(confidenceFilterOpts); } + pdal::SampleFilter sampleFilter; + if (Sample.set && Sample.value > 0.0f){ + logWriter("Radius sampling\n"); + pdal::Options sampleFilterOpts; + sampleFilterOpts.add("radius", Sample.value); + sampleFilter.setOptions(sampleFilterOpts); + sampleFilter.setInput(*currentStage); + currentStage = &sampleFilter; + } + pdal::Options outlierOpts; outlierOpts.add("method", "statistical"); outlierOpts.add("mean_k", MeanK.value); outlierOpts.add("multiplier", StandardDeviation.value); pdal::OutlierFilter outlierFilter; - if (Confidence.set){ - logWriter("Filtering confidence\n"); - outlierFilter.setInput(confidenceFilter); - }else{ - outlierFilter.setInput(plyReader); - - } + outlierFilter.setInput(*currentStage); outlierFilter.setOptions(outlierOpts); pdal::Options rangeOpts; diff --git a/opendm/config.py b/opendm/config.py index fc0f111b..99277795 100644 --- a/opendm/config.py +++ b/opendm/config.py @@ -320,6 +320,14 @@ def config(): help='Filters the point cloud by removing points that deviate more than N standard deviations from the local mean. Set to 0 to disable filtering.' '\nDefault: ' '%(default)s') + + parser.add_argument('--pc-sample', + metavar='', + type=float, + default=0, + help='Filters the point cloud by keeping only a single point around a radius N (in meters). This can be useful to limit the output resolution of the point cloud. Set to 0 to disable sampling.' + '\nDefault: ' + '%(default)s') parser.add_argument('--smrf-scalar', metavar='', diff --git a/opendm/point_cloud.py b/opendm/point_cloud.py index 212982a9..fb5a594b 100644 --- a/opendm/point_cloud.py +++ b/opendm/point_cloud.py @@ -4,18 +4,23 @@ from opendm import log from opendm import context from opendm.system import run -def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=16, confidence=None, verbose=False): +def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=16, confidence=None, sample_radius=0, verbose=False): """ Filters a point cloud """ - if standard_deviation <= 0 or meank <= 0: + if (standard_deviation <= 0 or meank <= 0) and sample_radius <= 0: log.ODM_INFO("Skipping point cloud filtering") return - log.ODM_INFO("Filtering point cloud (statistical, meanK {}, standard deviation {})".format(meank, standard_deviation)) + if standard_deviation > 0 and meank > 0: + log.ODM_INFO("Filtering point cloud (statistical, meanK {}, standard deviation {})".format(meank, standard_deviation)) + if confidence: log.ODM_INFO("Keeping only points with > %s confidence" % confidence) + if sample_radius > 0: + log.ODM_INFO("Sampling points around a %sm radius" % sample_radius) + if not os.path.exists(input_point_cloud): log.ODM_ERROR("{} does not exist, cannot filter point cloud. The program will now exit.".format(input_point_cloud)) sys.exit(1) @@ -34,12 +39,15 @@ def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank= 'meank': meank, 'verbose': '-verbose' if verbose else '', 'confidence': '-confidence %s' % confidence if confidence else '', + 'sample': max(0, sample_radius) } system.run('{bin} -inputFile {inputFile} ' '-outputFile {outputFile} ' '-sd {sd} ' - '-meank {meank} {confidence} {verbose} '.format(**filterArgs)) + '-meank {meank} ' + '-sample {sample} ' + '{confidence} {verbose} '.format(**filterArgs)) # Remove input file, swap temp file if not os.path.exists(output_point_cloud): diff --git a/stages/odm_filterpoints.py b/stages/odm_filterpoints.py index 1f192072..5179b755 100644 --- a/stages/odm_filterpoints.py +++ b/stages/odm_filterpoints.py @@ -23,7 +23,11 @@ class ODMFilterPoints(types.ODM_Stage): else: inputPointCloud = tree.mve_model - point_cloud.filter(inputPointCloud, tree.filtered_point_cloud, standard_deviation=args.pc_filter, confidence=None, verbose=args.verbose) + point_cloud.filter(inputPointCloud, tree.filtered_point_cloud, + standard_deviation=args.pc_filter, + confidence=None, + sample_radius=args.pc_sample, + verbose=args.verbose) else: log.ODM_WARNING('Found a valid point cloud file in: %s' % tree.filtered_point_cloud)