Skip to content

Commit 7e8eaa7

Browse files
authored
Merge pull request #42 from AutoModality/develop
Updates of band alignment, DEM generation, and texturing projection
2 parents afead50 + 60a9393 commit 7e8eaa7

File tree

11 files changed

+85
-30
lines changed

11 files changed

+85
-30
lines changed

contrib/pc2dem/pc2dem.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
args.type,
4848
output_type='idw' if args.type == 'dtm' else 'max',
4949
radiuses=list(map(str, radius_steps)),
50+
power=1,
5051
gapfill=args.gapfill_steps > 0,
5152
outdir=outdir,
5253
resolution=args.resolution,

opendm/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,12 @@ def config(argv=None, parser=None):
475475
help='Simple Morphological Filter window radius parameter (meters). '
476476
'Default: %(default)s')
477477

478+
parser.add_argument('--texturing-use-dtm',
479+
action=StoreTrue,
480+
nargs=0,
481+
default=False,
482+
help=('Choose to use 2.5D DSM or DTM to project textures. Default: %(default)s'))
483+
478484
parser.add_argument('--texturing-data-term',
479485
metavar='<string>',
480486
action=StoreValue,

opendm/dem/commands.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def rectify(lasFile, reclassify_threshold=5, min_area=750, min_points=500):
6666

6767
error = None
6868

69-
def create_dem(input_point_cloud, dem_type, output_type='max', radiuses=['0.56'], gapfill=True,
69+
def create_dem(input_point_cloud, dem_type, output_type='max', radiuses=['0.56'], power=1, gapfill=True,
7070
outdir='', resolution=0.1, max_workers=1, max_tile_size=4096,
7171
decimation=None, keep_unfilled_copy=False,
7272
apply_smoothing=True):
@@ -156,9 +156,9 @@ def create_dem(input_point_cloud, dem_type, output_type='max', radiuses=['0.56']
156156
def process_tile(q):
157157
log.ODM_INFO("Generating %s (%s, radius: %s, resolution: %s)" % (q['filename'], output_type, q['radius'], resolution))
158158

159-
d = pdal.json_gdal_base(q['filename'], output_type, q['radius'], resolution, q['bounds'])
159+
d = pdal.json_gdal_base(q['filename'], output_type, q['radius'], power, resolution, q['bounds'])
160160

161-
if dem_type == 'dtm':
161+
if dem_type == 'dtm' or dem_type == 'mesh_dtm':
162162
d = pdal.json_add_classification_filter(d, 2)
163163

164164
if decimation is not None:

opendm/dem/pdal.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ def json_base():
4949
return {'pipeline': []}
5050

5151

52-
def json_gdal_base(filename, output_type, radius, resolution=1, bounds=None):
52+
def json_gdal_base(filename, output_type, radius, power=1, resolution=1, bounds=None):
5353
""" Create initial JSON for PDAL pipeline containing a Writer element """
5454
json = json_base()
5555

5656
d = {
5757
'type': 'writers.gdal',
5858
'resolution': resolution,
5959
'radius': radius,
60+
'power': power, # IDW distance exponent
6061
'filename': filename,
6162
'output_type': output_type,
6263
'data_type': 'float'

opendm/mesh.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from scipy import signal
1010
import numpy as np
1111

12-
def create_25dmesh(inPointCloud, outMesh, radius_steps=["0.05"], dsm_resolution=0.05, depth=8, samples=1, maxVertexCount=100000, available_cores=None, method='gridded', smooth_dsm=True):
12+
def create_25dmesh(inPointCloud, outMesh, radius_steps=["0.05"], dsm_resolution=0.05, depth=8, samples=1, maxVertexCount=100000,
13+
available_cores=None, method='gridded', smooth_dsm=True, use_dtm=False):
1314
# Create DSM from point cloud
1415

1516
# Create temporary directory
@@ -22,11 +23,15 @@ def create_25dmesh(inPointCloud, outMesh, radius_steps=["0.05"], dsm_resolution=
2223

2324
log.ODM_INFO('Creating DSM for 2.5D mesh')
2425

26+
mesh_dem = 'mesh_dtm' if use_dtm else 'mesh_dsm'
27+
output_type = 'max' if use_dtm else 'idw'
28+
2529
commands.create_dem(
2630
inPointCloud,
27-
'mesh_dsm',
28-
output_type='idw',
31+
mesh_dem,
32+
output_type=output_type,
2933
radiuses=radius_steps,
34+
power=1,
3035
gapfill=True,
3136
outdir=tmp_directory,
3237
resolution=dsm_resolution,
@@ -35,9 +40,9 @@ def create_25dmesh(inPointCloud, outMesh, radius_steps=["0.05"], dsm_resolution=
3540
)
3641

3742
if method == 'gridded':
38-
mesh = dem_to_mesh_gridded(os.path.join(tmp_directory, 'mesh_dsm.tif'), outMesh, maxVertexCount, maxConcurrency=max(1, available_cores))
43+
mesh = dem_to_mesh_gridded(os.path.join(tmp_directory, mesh_dem + '.tif'), outMesh, maxVertexCount, maxConcurrency=max(1, available_cores))
3944
elif method == 'poisson':
40-
dsm_points = dem_to_points(os.path.join(tmp_directory, 'mesh_dsm.tif'), os.path.join(tmp_directory, 'dsm_points.ply'))
45+
dsm_points = dem_to_points(os.path.join(tmp_directory, mesh_dem + '.tif'), os.path.join(tmp_directory, 'dsm_points.ply'))
4146
mesh = screened_poisson_reconstruction(dsm_points, outMesh, depth=depth,
4247
samples=samples,
4348
maxVertexCount=maxVertexCount,

opendm/multispectral.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -552,16 +552,19 @@ def compute_using(algorithm):
552552
log.ODM_WARNING("Compute homography: %s" % str(e))
553553
return None, (None, None), None
554554

555-
def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=1000, termination_eps=1e-8, start_eps=1e-4, warp_matrix_init=None):
555+
def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=2000, termination_eps=1e-8, start_eps=1e-4, warp_matrix_init=None):
556556
# Major props to Alexander Reynolds for his insight into the pyramided matching process found at
557557
# https://stackoverflow.com/questions/45997891/cv2-motion-euclidean-for-the-warp-mode-in-ecc-image-alignment-method
558558
pyramid_levels = 0
559559
h,w = image_gray.shape
560560
min_dim = min(h, w)
561561

562-
number_of_iterations = 1000 if min_dim > 300 else 5000
563-
termination_eps = 1e-8 if min_dim > 300 else 1e-6
564-
gaussian_filter_size = 9 # if min_dim > 300 else 5
562+
if (min_dim <= 300):
563+
number_of_iterations = 5000
564+
termination_eps = 1e-6
565+
gaussian_filter_size = 9 # a constant since there is only one pyramid level
566+
else:
567+
gaussian_filter_size = 5 # will be increased in each pyramid level iteration
565568

566569
while min_dim > 300:
567570
min_dim /= 2.0
@@ -609,8 +612,9 @@ def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=1000,
609612
number_of_iterations, eps)
610613

611614
try:
615+
gaussian_filter_size = gaussian_filter_size + level * 2
612616
log.ODM_INFO("Computing ECC pyramid level %s using Gaussian filter size %s" % (level, gaussian_filter_size))
613-
_, warp_matrix = cv2.findTransformECC(ig, aig, warp_matrix, cv2.MOTION_HOMOGRAPHY, criteria, inputMask=None, gaussFiltSize=gaussian_filter_size)
617+
_, warp_matrix = cv2.findTransformECC(ig, aig, warp_matrix, cv2.MOTION_HOMOGRAPHY, criteria, inputMask=None, gaussFiltSize=gaussian_filter_size)
614618
except Exception as e:
615619
if level != pyramid_levels:
616620
log.ODM_INFO("Could not compute ECC warp_matrix at pyramid level %s, resetting matrix" % level)
@@ -625,7 +629,7 @@ def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=1000,
625629

626630
return warp_matrix
627631

628-
def find_features_homography(image_gray, align_image_gray, feature_retention=0.7, min_match_count=10):
632+
def find_features_homography(image_gray, align_image_gray, feature_retention=0.8, min_match_count=4):
629633

630634
# Detect SIFT features and compute descriptors.
631635
detector = cv2.SIFT_create() # edgeThreshold=10, contrastThreshold=0.1 (default 0.04)

opendm/point_cloud.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,12 @@ def filter(input_point_cloud, output_point_cloud, output_stats, standard_deviati
8989
log.ODM_INFO("Sampling points around a %sm radius" % sample_radius)
9090
args.append('--radius %s' % sample_radius)
9191

92-
meank = 16
93-
log.ODM_INFO("Filtering {} (statistical, meanK {}, standard deviation {})".format(input_point_cloud, meank, standard_deviation))
94-
args.append('--meank %s' % meank)
95-
args.append('--std %s' % standard_deviation)
96-
args.append('--stats "%s"' % output_stats)
92+
if standard_deviation > 0:
93+
meank = 16
94+
log.ODM_INFO("Filtering {} (statistical, meanK {}, standard deviation {})".format(input_point_cloud, meank, standard_deviation))
95+
args.append('--meank %s' % meank)
96+
args.append('--std %s' % standard_deviation)
97+
args.append('--stats "%s"' % output_stats)
9798

9899
if boundary is not None:
99100
log.ODM_INFO("Boundary {}".format(boundary))

opendm/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ def __init__(self, root_path, gcp_file = None, geo_file = None, align_file = Non
290290

291291
# filter points
292292
self.filtered_point_cloud = os.path.join(self.odm_filterpoints, "point_cloud.ply")
293+
self.filtered_point_cloud_classified = os.path.join(self.odm_filterpoints, "point_cloud_classified.ply")
293294
self.filtered_point_cloud_stats = os.path.join(self.odm_filterpoints, "point_cloud_stats.json")
294295

295296
# odm_meshing

stages/mvstex.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def add_run(nvm_file, primary=True, band=None):
3636
'model': tree.odm_mesh,
3737
'nadir': False,
3838
'primary': primary,
39+
'band': band,
3940
'nvm_file': nvm_file,
4041
'labeling_file': os.path.join(tree.odm_texturing, "odm_textured_model_geo_labeling.vec") if subdir else None
4142
}]
@@ -46,6 +47,7 @@ def add_run(nvm_file, primary=True, band=None):
4647
'model': tree.odm_25dmesh,
4748
'nadir': True,
4849
'primary': primary,
50+
'band': band,
4951
'nvm_file': nvm_file,
5052
'labeling_file': os.path.join(tree.odm_25dtexturing, "odm_textured_model_geo_labeling.vec") if subdir else None
5153
}]
@@ -80,6 +82,8 @@ def add_run(nvm_file, primary=True, band=None):
8082
os.unlink(unaligned_obj)
8183

8284
# Format arguments to fit Mvs-Texturing app
85+
dataTerm = args.texturing_data_term
86+
outlierRemovalType = args.texturing_outlier_removal_type
8387
skipGlobalSeamLeveling = ""
8488
skipLocalSeamLeveling = ""
8589
keepUnseenFaces = ""
@@ -94,13 +98,21 @@ def add_run(nvm_file, primary=True, band=None):
9498
if (r['nadir']):
9599
nadir = '--nadir_mode'
96100

101+
# thermal band
102+
if (r['band'] == 'lwir'):
103+
dataTerm = "gmi"
104+
outlierRemovalType = "none"
105+
skipGlobalSeamLeveling = ""
106+
skipLocalSeamLeveling = ""
107+
keepUnseenFaces = ""
108+
97109
# mvstex definitions
98110
kwargs = {
99111
'bin': context.mvstex_path,
100112
'out_dir': os.path.join(r['out_dir'], "odm_textured_model_geo"),
101113
'model': r['model'],
102-
'dataTerm': args.texturing_data_term,
103-
'outlierRemovalType': args.texturing_outlier_removal_type,
114+
'dataTerm': dataTerm,
115+
'outlierRemovalType': outlierRemovalType,
104116
'skipGlobalSeamLeveling': skipGlobalSeamLeveling,
105117
'skipLocalSeamLeveling': skipLocalSeamLeveling,
106118
'keepUnseenFaces': keepUnseenFaces,

stages/odm_dem.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def process(self, args, outputs):
102102
product,
103103
output_type=args.dtm_interpolation if product == 'dtm' else args.dsm_interpolation,
104104
radiuses=list(map(str, radius_steps)),
105+
power=2,
105106
gapfill=args.dem_gapfill_steps > 0,
106107
outdir=odm_dem_root,
107108
resolution=resolution / 100.0,

0 commit comments

Comments
 (0)