kopia lustrzana https://github.com/OpenDroneMap/ODM
Crop to boundary in filterpoints
rodzic
7f198d90ec
commit
43870b6411
|
@ -36,6 +36,20 @@ def load_boundary(boundary_json, reproject_to_proj4=None):
|
||||||
|
|
||||||
return coords
|
return coords
|
||||||
|
|
||||||
|
def boundary_offset(boundary, reconstruction_offset):
|
||||||
|
if boundary is None or reconstruction_offset is None:
|
||||||
|
return boundary
|
||||||
|
|
||||||
|
res = []
|
||||||
|
dims = len(boundary[0])
|
||||||
|
for c in boundary:
|
||||||
|
if dims == 2:
|
||||||
|
res.append((c[0] - reconstruction_offset[0], c[1] - reconstruction_offset[1]))
|
||||||
|
else:
|
||||||
|
res.append((c[0] - reconstruction_offset[0], c[1] - reconstruction_offset[1], c[2]))
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
def as_polygon(boundary):
|
def as_polygon(boundary):
|
||||||
return "POLYGON((" + ", ".join([" ".join(map(str, c)) for c in boundary]) + "))"
|
return "POLYGON((" + ", ".join([" ".join(map(str, c)) for c in boundary]) + "))"
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ def dem_to_mesh_gridded(inGeotiff, outMesh, maxVertexCount, verbose=False, maxCo
|
||||||
|
|
||||||
system.run('"{reconstructmesh}" -i "{infile}" '
|
system.run('"{reconstructmesh}" -i "{infile}" '
|
||||||
'-o "{outfile}" '
|
'-o "{outfile}" '
|
||||||
'--remove-spikes 0 --remove-spurious 20 --smooth 0 '
|
'--remove-spikes 0 --remove-spurious 0 --smooth 0 '
|
||||||
'--target-face-num {max_faces} '.format(**cleanupArgs))
|
'--target-face-num {max_faces} '.format(**cleanupArgs))
|
||||||
|
|
||||||
# Delete intermediate results
|
# Delete intermediate results
|
||||||
|
|
|
@ -7,6 +7,7 @@ from opendm import entwine
|
||||||
from opendm import io
|
from opendm import io
|
||||||
from opendm.concurrency import parallel_map
|
from opendm.concurrency import parallel_map
|
||||||
from opendm.utils import double_quote
|
from opendm.utils import double_quote
|
||||||
|
from opendm.boundary import as_polygon
|
||||||
|
|
||||||
def ply_info(input_ply):
|
def ply_info(input_ply):
|
||||||
if not os.path.exists(input_ply):
|
if not os.path.exists(input_ply):
|
||||||
|
@ -38,7 +39,8 @@ def ply_info(input_ply):
|
||||||
return {
|
return {
|
||||||
'has_normals': has_normals,
|
'has_normals': has_normals,
|
||||||
'vertex_count': vertex_count,
|
'vertex_count': vertex_count,
|
||||||
'has_views': has_views
|
'has_views': has_views,
|
||||||
|
'header_lines': i + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,7 +70,7 @@ def split(input_point_cloud, outdir, filename_template, capacity, dims=None):
|
||||||
return [os.path.join(outdir, f) for f in os.listdir(outdir)]
|
return [os.path.join(outdir, f) for f in os.listdir(outdir)]
|
||||||
|
|
||||||
|
|
||||||
def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=16, sample_radius=0, verbose=False, max_concurrency=1):
|
def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=16, sample_radius=0, boundary=None, verbose=False, max_concurrency=1):
|
||||||
"""
|
"""
|
||||||
Filters a point cloud
|
Filters a point cloud
|
||||||
"""
|
"""
|
||||||
|
@ -87,6 +89,10 @@ def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=
|
||||||
filters.append('outlier')
|
filters.append('outlier')
|
||||||
filters.append('range')
|
filters.append('range')
|
||||||
|
|
||||||
|
if boundary is not None:
|
||||||
|
log.ODM_INFO("Boundary {}".format(boundary))
|
||||||
|
filters.append('crop')
|
||||||
|
|
||||||
info = ply_info(input_point_cloud)
|
info = ply_info(input_point_cloud)
|
||||||
dims = "x=float,y=float,z=float,"
|
dims = "x=float,y=float,z=float,"
|
||||||
if info['has_normals']:
|
if info['has_normals']:
|
||||||
|
@ -117,6 +123,7 @@ def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=
|
||||||
standard_deviation=standard_deviation,
|
standard_deviation=standard_deviation,
|
||||||
meank=meank,
|
meank=meank,
|
||||||
sample_radius=sample_radius,
|
sample_radius=sample_radius,
|
||||||
|
boundary=boundary,
|
||||||
verbose=verbose,
|
verbose=verbose,
|
||||||
max_concurrency=1)
|
max_concurrency=1)
|
||||||
# Filter
|
# Filter
|
||||||
|
@ -159,6 +166,9 @@ def filter(input_point_cloud, output_point_cloud, standard_deviation=2.5, meank=
|
||||||
# Remove outliers
|
# Remove outliers
|
||||||
cmd += "--filters.range.limits=\"Classification![7:7]\" "
|
cmd += "--filters.range.limits=\"Classification![7:7]\" "
|
||||||
|
|
||||||
|
if 'crop' in filters:
|
||||||
|
cmd += "--filters.crop.polygon=\"%s\"" % as_polygon(boundary)
|
||||||
|
|
||||||
system.run(cmd)
|
system.run(cmd)
|
||||||
|
|
||||||
if not os.path.exists(output_point_cloud):
|
if not os.path.exists(output_point_cloud):
|
||||||
|
|
|
@ -159,6 +159,12 @@ class ODM_Reconstruction(object):
|
||||||
if self.is_georeferenced():
|
if self.is_georeferenced():
|
||||||
return self.georef.proj4()
|
return self.georef.proj4()
|
||||||
|
|
||||||
|
def get_proj_offset(self):
|
||||||
|
if self.is_georeferenced():
|
||||||
|
return (self.georef.utm_east_offset, self.georef.utm_north_offset)
|
||||||
|
else:
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
def get_photo(self, filename):
|
def get_photo(self, filename):
|
||||||
for p in self.photos:
|
for p in self.photos:
|
||||||
if p.filename == filename:
|
if p.filename == filename:
|
||||||
|
|
|
@ -160,4 +160,5 @@ class ODMLoadDatasetStage(types.ODM_Stage):
|
||||||
if reconstruction.is_georeferenced():
|
if reconstruction.is_georeferenced():
|
||||||
outputs['boundary'] = boundary.load_boundary(args.boundary, reconstruction.get_proj_srs())
|
outputs['boundary'] = boundary.load_boundary(args.boundary, reconstruction.get_proj_srs())
|
||||||
else:
|
else:
|
||||||
|
args.boundary = None
|
||||||
log.ODM_WARNING("Reconstruction is not georeferenced, but boundary file provided (will ignore boundary file)")
|
log.ODM_WARNING("Reconstruction is not georeferenced, but boundary file provided (will ignore boundary file)")
|
||||||
|
|
|
@ -6,6 +6,7 @@ from opendm import system
|
||||||
from opendm import context
|
from opendm import context
|
||||||
from opendm import point_cloud
|
from opendm import point_cloud
|
||||||
from opendm import types
|
from opendm import types
|
||||||
|
from opendm.boundary import boundary_offset
|
||||||
|
|
||||||
class ODMFilterPoints(types.ODM_Stage):
|
class ODMFilterPoints(types.ODM_Stage):
|
||||||
def process(self, args, outputs):
|
def process(self, args, outputs):
|
||||||
|
@ -24,6 +25,7 @@ class ODMFilterPoints(types.ODM_Stage):
|
||||||
point_cloud.filter(inputPointCloud, tree.filtered_point_cloud,
|
point_cloud.filter(inputPointCloud, tree.filtered_point_cloud,
|
||||||
standard_deviation=args.pc_filter,
|
standard_deviation=args.pc_filter,
|
||||||
sample_radius=args.pc_sample,
|
sample_radius=args.pc_sample,
|
||||||
|
boundary=boundary_offset(outputs.get('boundary'), reconstruction.get_proj_offset()),
|
||||||
verbose=args.verbose,
|
verbose=args.verbose,
|
||||||
max_concurrency=args.max_concurrency)
|
max_concurrency=args.max_concurrency)
|
||||||
|
|
||||||
|
|
|
@ -128,12 +128,6 @@ class ODMGeoreferencingStage(types.ODM_Stage):
|
||||||
'--writers.las.vlrs="{\\\"filename\\\": \\\"%s\\\", \\\"user_id\\\": \\\"ODM_GCP\\\", \\\"description\\\": \\\"Ground Control Points (GML)\\\"}"' % gcp_gml_export_file.replace(os.sep, "/")
|
'--writers.las.vlrs="{\\\"filename\\\": \\\"%s\\\", \\\"user_id\\\": \\\"ODM_GCP\\\", \\\"description\\\": \\\"Ground Control Points (GML)\\\"}"' % gcp_gml_export_file.replace(os.sep, "/")
|
||||||
]
|
]
|
||||||
|
|
||||||
if 'boundary' in outputs:
|
|
||||||
stages.append("crop")
|
|
||||||
params += [
|
|
||||||
'--filters.crop.polygon="%s"' % as_polygon(outputs['boundary'])
|
|
||||||
]
|
|
||||||
|
|
||||||
system.run(cmd + ' ' + ' '.join(stages) + ' ' + ' '.join(params))
|
system.run(cmd + ' ' + ' '.join(stages) + ' ' + ' '.join(params))
|
||||||
|
|
||||||
self.update_progress(50)
|
self.update_progress(50)
|
||||||
|
|
Ładowanie…
Reference in New Issue