ign-pdal-tools 1.15.3__tar.gz → 1.15.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/PKG-INFO +1 -1
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/ign_pdal_tools.egg-info/PKG-INFO +1 -1
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/_version.py +1 -1
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/replace_area_in_pointcloud.py +59 -6
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_replace_area_in_pointcloud.py +19 -1
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/LICENSE.md +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/README.md +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/ign_pdal_tools.egg-info/SOURCES.txt +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/ign_pdal_tools.egg-info/dependency_links.txt +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/ign_pdal_tools.egg-info/top_level.txt +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/add_points_in_pointcloud.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/color.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/create_random_laz.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/download_image.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_add_buffer.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_clip.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_comparison.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_info.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_merge.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_remove_dimensions.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/las_rename_dimension.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/pcd_info.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/replace_attribute_in_las.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/standardize_format.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pdaltools/unlock_file.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/pyproject.toml +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/setup.cfg +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_add_points_in_pointcloud.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_color.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_create_random_laz.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_download_image.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_add_buffer.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_clip.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_comparison.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_info.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_merge.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_remove_dimensions.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_las_rename_dimension.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_pcd_info.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_pdal.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_replace_attribute_in_las.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_standardize_format.py +0 -0
- {ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/test/test_unlock.py +0 -0
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
5
|
+
import time
|
|
2
6
|
import warnings
|
|
3
7
|
|
|
8
|
+
import geopandas as gpd
|
|
4
9
|
import numpy as np
|
|
5
10
|
import pdal
|
|
6
11
|
from numpy.lib import recfunctions as rfn
|
|
7
12
|
from osgeo import gdal
|
|
13
|
+
from shapely.geometry import box
|
|
8
14
|
|
|
9
|
-
from pdaltools.las_info import
|
|
15
|
+
from pdaltools.las_info import (
|
|
16
|
+
get_bounds_from_header_info,
|
|
17
|
+
get_writer_parameters_from_reader_metadata,
|
|
18
|
+
las_info_metadata,
|
|
19
|
+
)
|
|
10
20
|
|
|
11
21
|
|
|
12
22
|
def argument_parser():
|
|
@@ -139,6 +149,18 @@ def pipeline_read_from_DSM(dsm, ground_mask, classification):
|
|
|
139
149
|
return pipeline
|
|
140
150
|
|
|
141
151
|
|
|
152
|
+
def clip_area(area_input, area_output, las_file):
|
|
153
|
+
start = time.time()
|
|
154
|
+
gdf = gpd.read_file(area_input)
|
|
155
|
+
minx, maxx, miny, maxy = get_bounds_from_header_info(las_info_metadata(las_file))
|
|
156
|
+
selection = gdf[gdf.intersects(box(minx, miny, maxx, maxy))]
|
|
157
|
+
num_polygon = len(selection)
|
|
158
|
+
selection.to_file(area_output)
|
|
159
|
+
end = time.time()
|
|
160
|
+
print(f"Create replacement area cropped: {num_polygon} polygons in {end-start:.2f} seconds")
|
|
161
|
+
return num_polygon
|
|
162
|
+
|
|
163
|
+
|
|
142
164
|
def replace_area(
|
|
143
165
|
target_cloud, pipeline_source, replacement_area, output_cloud, source_pdal_filter="", target_pdal_filter=""
|
|
144
166
|
):
|
|
@@ -147,6 +169,24 @@ def replace_area(
|
|
|
147
169
|
print("output cloud: ", output_cloud)
|
|
148
170
|
print("source pdal filter: ", source_pdal_filter)
|
|
149
171
|
print("target pdal filter: ", target_pdal_filter)
|
|
172
|
+
|
|
173
|
+
start = time.time()
|
|
174
|
+
tmpdir = tempfile.mkdtemp()
|
|
175
|
+
replacement_name, ext = os.path.splitext(os.path.basename(replacement_area))
|
|
176
|
+
las_name, _ = os.path.splitext(os.path.basename(target_cloud))
|
|
177
|
+
replacement_area_crop = os.path.join(tmpdir, f"{replacement_name}_{las_name}{ext}")
|
|
178
|
+
print("replacement area crop: ", replacement_area_crop)
|
|
179
|
+
|
|
180
|
+
num_polygon = clip_area(replacement_area, replacement_area_crop, target_cloud)
|
|
181
|
+
if num_polygon == 0:
|
|
182
|
+
print("No polygon inside target cloud, output file is target cloud. We copy target in output.")
|
|
183
|
+
|
|
184
|
+
shutil.copy2(src=target_cloud, dst=output_cloud)
|
|
185
|
+
end = time.time()
|
|
186
|
+
print("all steps done in ", f"{end-start:.2f}", " seconds")
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
replacement_area = replacement_area_crop
|
|
150
190
|
crops = []
|
|
151
191
|
# pipeline to read target_cloud and remove points inside the polygon
|
|
152
192
|
pipeline_target = pdal.Pipeline()
|
|
@@ -159,7 +199,10 @@ def replace_area(
|
|
|
159
199
|
pipeline_target |= pdal.Filter.overlay(column="fid", dimension="geometryFid", datasource=replacement_area)
|
|
160
200
|
# Keep only points out of the area
|
|
161
201
|
pipeline_target |= pdal.Filter.expression(expression="geometryFid==-1", tag="A")
|
|
162
|
-
pipeline_target.execute()
|
|
202
|
+
target_count = pipeline_target.execute()
|
|
203
|
+
|
|
204
|
+
t1 = time.time()
|
|
205
|
+
print(f"Step 1: target count: {target_count} points in {t1-start:.2f} seconds")
|
|
163
206
|
|
|
164
207
|
# get input dimensions dtype from target
|
|
165
208
|
if pipeline_target.arrays:
|
|
@@ -170,7 +213,10 @@ def replace_area(
|
|
|
170
213
|
pipeline_target2 |= pdal.Reader.las(filename=target_cloud)
|
|
171
214
|
pipeline_target2.execute()
|
|
172
215
|
input_dim_dtype = pipeline_target2.arrays[0].dtype
|
|
216
|
+
t1_bis = time.time()
|
|
217
|
+
print(f"Step 1-bis: re-read to have dimensions: {t1_bis-t1:.2f} seconds")
|
|
173
218
|
|
|
219
|
+
t2 = time.time()
|
|
174
220
|
# get input dimensions names
|
|
175
221
|
input_dimensions = list(input_dim_dtype.fields.keys())
|
|
176
222
|
|
|
@@ -178,7 +224,7 @@ def replace_area(
|
|
|
178
224
|
output_dimensions = [dim for dim in input_dimensions if dim not in "geometryFid"]
|
|
179
225
|
|
|
180
226
|
# add target to the result after keeping only the expected dimensions
|
|
181
|
-
if
|
|
227
|
+
if target_count:
|
|
182
228
|
target_cloud_pruned = pipeline_target.arrays[0][output_dimensions]
|
|
183
229
|
crops.append(target_cloud_pruned)
|
|
184
230
|
|
|
@@ -190,10 +236,13 @@ def replace_area(
|
|
|
190
236
|
pipeline_source |= pdal.Filter.overlay(column="fid", dimension="geometryFid", datasource=replacement_area)
|
|
191
237
|
# Keep only points in the area
|
|
192
238
|
pipeline_source |= pdal.Filter.expression(expression="geometryFid>=0", tag="B")
|
|
193
|
-
pipeline_source.execute()
|
|
239
|
+
source_count = pipeline_source.execute()
|
|
240
|
+
|
|
241
|
+
t3 = time.time()
|
|
242
|
+
print(f"Step 2: source count: {source_count} points in {t3-t2:.2f} seconds")
|
|
194
243
|
|
|
195
244
|
# add source to the result
|
|
196
|
-
if
|
|
245
|
+
if source_count:
|
|
197
246
|
# eventually add dimensions in source to have same dimensions as target cloud
|
|
198
247
|
# we do that in numpy (instead of PDAL filter) to keep dimension types
|
|
199
248
|
source_cloud_crop = pipeline_source.arrays[0]
|
|
@@ -219,7 +268,11 @@ def replace_area(
|
|
|
219
268
|
|
|
220
269
|
writer_params = get_writer_params(target_cloud)
|
|
221
270
|
pipeline |= pdal.Writer.las(filename=output_cloud, **writer_params)
|
|
222
|
-
pipeline.execute()
|
|
271
|
+
points = pipeline.execute()
|
|
272
|
+
|
|
273
|
+
end = time.time()
|
|
274
|
+
print(f"Step 3: merge: { points }, points in {end-t3:.2f} seconds")
|
|
275
|
+
print("all steps done in ", f"{end-start:.2f}", " seconds")
|
|
223
276
|
|
|
224
277
|
|
|
225
278
|
if __name__ == "__main__":
|
|
@@ -325,7 +325,7 @@ def test_main_from_cloud_with_filter():
|
|
|
325
325
|
assert get_nb_points(output_file) == 6390
|
|
326
326
|
|
|
327
327
|
|
|
328
|
-
def
|
|
328
|
+
def test_main_from_DSM_light():
|
|
329
329
|
output_file = os.path.join(TMP_PATH, "main_from_DSM", "output_main_from_DSM.laz")
|
|
330
330
|
os.makedirs(os.path.dirname(output_file))
|
|
331
331
|
cmd = (
|
|
@@ -338,3 +338,21 @@ def test_main_from_DSM():
|
|
|
338
338
|
# same result as test_from_DMS
|
|
339
339
|
counts = compute_count_one_file(output_file, "Classification")
|
|
340
340
|
assert counts == {"1": 3841, "2": 2355, str(SOURCE_CLASSIF): 45}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def test_main_from_DSM_light_replace_all():
|
|
344
|
+
output_file = os.path.join(TMP_PATH, "main_from_DSM_replace_around", "output_main_from_DSM.laz")
|
|
345
|
+
os.makedirs(os.path.dirname(output_file))
|
|
346
|
+
|
|
347
|
+
# use replacement area bigger than the tile
|
|
348
|
+
REPLACE_AREA_2 = os.path.join(INPUT_DIR, "replace_area_2.geojson")
|
|
349
|
+
cmd = (
|
|
350
|
+
f"from_DSM -d {SOURCE_DSM} -g {SOURCE_GROUND_MASK} -c {SOURCE_CLASSIF} -t {TARGET_CLOUD} -r {REPLACE_AREA_2}"
|
|
351
|
+
f" -o {output_file}"
|
|
352
|
+
).split()
|
|
353
|
+
args = argument_parser().parse_args(cmd)
|
|
354
|
+
args.func(args)
|
|
355
|
+
|
|
356
|
+
# only have points from source
|
|
357
|
+
counts = compute_count_one_file(output_file, "Classification")
|
|
358
|
+
assert counts == {str(SOURCE_CLASSIF): 81}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ign_pdal_tools-1.15.3 → ign_pdal_tools-1.15.5}/ign_pdal_tools.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|