ign-pdal-tools 1.15.6__py3-none-any.whl → 1.15.8__py3-none-any.whl
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.6.dist-info → ign_pdal_tools-1.15.8.dist-info}/METADATA +1 -1
- {ign_pdal_tools-1.15.6.dist-info → ign_pdal_tools-1.15.8.dist-info}/RECORD +9 -9
- {ign_pdal_tools-1.15.6.dist-info → ign_pdal_tools-1.15.8.dist-info}/WHEEL +1 -1
- pdaltools/_version.py +1 -1
- pdaltools/color.py +108 -26
- pdaltools/las_comparison.py +70 -14
- pdaltools/las_merge.py +66 -31
- {ign_pdal_tools-1.15.6.dist-info → ign_pdal_tools-1.15.8.dist-info}/licenses/LICENSE.md +0 -0
- {ign_pdal_tools-1.15.6.dist-info → ign_pdal_tools-1.15.8.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
ign_pdal_tools-1.15.
|
|
2
|
-
pdaltools/_version.py,sha256=
|
|
1
|
+
ign_pdal_tools-1.15.8.dist-info/licenses/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
|
|
2
|
+
pdaltools/_version.py,sha256=ka-Hq8wFue3GxbOFYtvl29usecZ_BEmqujBzCGJyZ9U,75
|
|
3
3
|
pdaltools/add_points_in_pointcloud.py,sha256=lDxePBBRTKSEKC3BgrVLWUEMN8vCM4xNgsJfbIz4GRw,12988
|
|
4
|
-
pdaltools/color.py,sha256=
|
|
4
|
+
pdaltools/color.py,sha256=zUNN9BxpajgkisoQ_TC0wBEQqou3gKo8x1KH9EtoRnE,12495
|
|
5
5
|
pdaltools/create_random_laz.py,sha256=w0P4e3-bzaiKl_osmyFdOcKODRUadU7G4ez9fLvCDrs,6028
|
|
6
6
|
pdaltools/download_image.py,sha256=RgR9iHbw1kr1rb5aumbNwNyLk3BgM86EV3MssXiVaGU,7869
|
|
7
7
|
pdaltools/las_add_buffer.py,sha256=WXUkMSRX8T-Xj5il9F_uv7uKSqwUmv5P3AUcHXQVQDE,11343
|
|
8
8
|
pdaltools/las_clip.py,sha256=GvEOYu8RXV68e35kU8i42GwSkbo4P9TvmS6rkrdPmFM,1034
|
|
9
|
-
pdaltools/las_comparison.py,sha256=
|
|
9
|
+
pdaltools/las_comparison.py,sha256=ZbWqAjDJ90r3bwzRzMY1nGbpPXMHb52AlQFn1Aoy4jA,7431
|
|
10
10
|
pdaltools/las_info.py,sha256=xZlTsdLS3I9_xeqGJyOOpJNJrqF82JBhlMhtYabOuw0,9845
|
|
11
|
-
pdaltools/las_merge.py,sha256=
|
|
11
|
+
pdaltools/las_merge.py,sha256=MYv4M9WM86Vqb-icPM6hGwdSxY6YuJxhpkR1FDouzsk,5692
|
|
12
12
|
pdaltools/las_remove_dimensions.py,sha256=f8imGhN6LNTuQ1GMJQRzIIV3Wab_oRPOyEnKi1CgfiM,2318
|
|
13
13
|
pdaltools/las_rename_dimension.py,sha256=AWYx0Jd5YHWng-CY2yIV8iRTR_bMxhvwGz1MO5sYTWc,2889
|
|
14
14
|
pdaltools/pcd_info.py,sha256=NIAH5KGikVDQLlbCcw9FuaPqe20UZvRfkHsDZd5kmZA,3210
|
|
@@ -16,7 +16,7 @@ pdaltools/replace_area_in_pointcloud.py,sha256=V8aFRSxrqJtsUufoA_5g9ysPl-Wp17_TX
|
|
|
16
16
|
pdaltools/replace_attribute_in_las.py,sha256=MHpIizSupgWtbizteoRH8FKDE049hrAh4v_OhmRmSPU,4318
|
|
17
17
|
pdaltools/standardize_format.py,sha256=-ukrz5gY0mq071fN7EXbB9ANS44IEmgpKQrrjzOnqhE,4455
|
|
18
18
|
pdaltools/unlock_file.py,sha256=3BplGrcKJ7lpPj1lHTG4ODeuGDXjmeoMeSl3q2Qn2XA,1980
|
|
19
|
-
ign_pdal_tools-1.15.
|
|
20
|
-
ign_pdal_tools-1.15.
|
|
21
|
-
ign_pdal_tools-1.15.
|
|
22
|
-
ign_pdal_tools-1.15.
|
|
19
|
+
ign_pdal_tools-1.15.8.dist-info/METADATA,sha256=YtXPvSSqPe7WRsckKRF4hbCPaCH8TEagbz8QnMi1T8Y,6146
|
|
20
|
+
ign_pdal_tools-1.15.8.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
21
|
+
ign_pdal_tools-1.15.8.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
|
|
22
|
+
ign_pdal_tools-1.15.8.dist-info/RECORD,,
|
pdaltools/_version.py
CHANGED
pdaltools/color.py
CHANGED
|
@@ -31,7 +31,7 @@ def match_min_max_with_pixel_size(min_d: float, max_d: float, pixel_per_meter: f
|
|
|
31
31
|
return min_d, max_d
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def color_from_stream(
|
|
35
35
|
input_file: str,
|
|
36
36
|
output_file: str,
|
|
37
37
|
proj="",
|
|
@@ -156,28 +156,58 @@ def color(
|
|
|
156
156
|
return tmp_ortho, tmp_ortho_irc
|
|
157
157
|
|
|
158
158
|
|
|
159
|
-
def
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
def color_from_files(
|
|
160
|
+
input_file: str,
|
|
161
|
+
output_file: str,
|
|
162
|
+
rgb_image: str,
|
|
163
|
+
irc_image: str,
|
|
164
|
+
color_rvb_enabled=True,
|
|
165
|
+
color_ir_enabled=True,
|
|
166
|
+
veget_index_file="",
|
|
167
|
+
vegetation_dim="Deviation",
|
|
168
|
+
):
|
|
169
|
+
pipeline = pdal.Reader.las(filename=input_file)
|
|
170
|
+
|
|
171
|
+
writer_extra_dims = "all"
|
|
172
|
+
|
|
173
|
+
if veget_index_file and veget_index_file != "":
|
|
174
|
+
print(f"Remplissage du champ {vegetation_dim} à partir du fichier {veget_index_file}")
|
|
175
|
+
pipeline |= pdal.Filter.colorization(raster=veget_index_file, dimensions=f"{vegetation_dim}:1:256.0")
|
|
176
|
+
writer_extra_dims = [f"{vegetation_dim}=ushort"]
|
|
177
|
+
|
|
178
|
+
# Warning: the initial color is multiplied by 256 despite its initial 8-bits encoding
|
|
179
|
+
# which turns it to a 0 to 255*256 range.
|
|
180
|
+
# It is kept this way because of other dependencies that have been tuned to fit this range
|
|
181
|
+
if color_rvb_enabled:
|
|
182
|
+
pipeline |= pdal.Filter.colorization(raster=rgb_image, dimensions="Red:1:256.0, Green:2:256.0, Blue:3:256.0")
|
|
183
|
+
if color_ir_enabled:
|
|
184
|
+
pipeline |= pdal.Filter.colorization(raster=irc_image, dimensions="Infrared:1:256.0")
|
|
185
|
+
|
|
186
|
+
pipeline |= pdal.Writer.las(
|
|
187
|
+
filename=output_file, extra_dims=writer_extra_dims, minor_version="4", dataformat_id="8", forward="all"
|
|
165
188
|
)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
189
|
+
|
|
190
|
+
print("Traitement du nuage de point")
|
|
191
|
+
pipeline.execute()
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def argument_parser():
|
|
195
|
+
parser = argparse.ArgumentParser("Colorize tool")
|
|
196
|
+
subparsers = parser.add_subparsers(required=True)
|
|
197
|
+
|
|
198
|
+
# first command is 'from_stream'
|
|
199
|
+
from_stream = subparsers.add_parser("from_stream", help="Images are downloaded from streams")
|
|
200
|
+
from_stream.add_argument(
|
|
201
|
+
"--proj", "-p", type=str, default="", help="Projection, default will use projection from metadata input"
|
|
175
202
|
)
|
|
176
|
-
|
|
177
|
-
|
|
203
|
+
from_stream.add_argument("--timeout", "-t", type=int, default=300, help="Timeout, in seconds")
|
|
204
|
+
from_stream.add_argument("--rvb", action="store_true", help="Colorize RVB")
|
|
205
|
+
from_stream.add_argument("--ir", action="store_true", help="Colorize IR")
|
|
206
|
+
from_stream.add_argument("--resolution", "-r", type=float, default=5, help="Resolution, in pixel per meter")
|
|
207
|
+
from_stream.add_argument(
|
|
208
|
+
"--check-images", "-c", action="store_true", help="Check that downloaded image is not white"
|
|
178
209
|
)
|
|
179
|
-
|
|
180
|
-
parser.add_argument(
|
|
210
|
+
from_stream.add_argument(
|
|
181
211
|
"--stream-RGB",
|
|
182
212
|
type=str,
|
|
183
213
|
default="ORTHOIMAGERY.ORTHOPHOTOS",
|
|
@@ -186,27 +216,49 @@ default stream (ORTHOIMAGERY.ORTHOPHOTOS) let the server choose the resolution
|
|
|
186
216
|
for 20cm resolution rasters, use HR.ORTHOIMAGERY.ORTHOPHOTOS
|
|
187
217
|
for 50 cm resolution rasters, use ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO""",
|
|
188
218
|
)
|
|
189
|
-
|
|
219
|
+
from_stream.add_argument(
|
|
190
220
|
"--stream-IRC",
|
|
191
221
|
type=str,
|
|
192
222
|
default="ORTHOIMAGERY.ORTHOPHOTOS.IRC",
|
|
193
223
|
help="""WMS raster stream for IRC colorization. Default to ORTHOIMAGERY.ORTHOPHOTOS.IRC
|
|
194
224
|
Documentation about possible stream : https://geoservices.ign.fr/services-web-experts-ortho""",
|
|
195
225
|
)
|
|
196
|
-
|
|
226
|
+
from_stream.add_argument(
|
|
197
227
|
"--size-max-GPF",
|
|
198
228
|
type=int,
|
|
199
229
|
default=5000,
|
|
200
230
|
help="Maximum edge size (in pixels) of downloaded images."
|
|
201
231
|
" If input file needs more, several images are downloaded and merged.",
|
|
202
232
|
)
|
|
233
|
+
add_common_options(from_stream)
|
|
234
|
+
from_stream.set_defaults(func=from_stream_func)
|
|
203
235
|
|
|
204
|
-
|
|
236
|
+
# second command is 'from_files'
|
|
237
|
+
from_files = subparsers.add_parser("from_files", help="Images are in directories from RGB/IRC")
|
|
238
|
+
from_files.add_argument("--image_RGB", type=str, required=True, help="RGB image filepath")
|
|
239
|
+
from_files.add_argument("--image_IRC", type=str, required=True, help="IRC image filepath")
|
|
240
|
+
add_common_options(from_files)
|
|
241
|
+
from_files.set_defaults(func=from_files_func)
|
|
205
242
|
|
|
243
|
+
return parser
|
|
206
244
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
245
|
+
|
|
246
|
+
def add_common_options(parser):
|
|
247
|
+
parser.add_argument("--input", "-i", type=str, required=True, help="Input file")
|
|
248
|
+
parser.add_argument("--output", "-o", type=str, default="", help="Output file")
|
|
249
|
+
parser.add_argument(
|
|
250
|
+
"--vegetation",
|
|
251
|
+
type=str,
|
|
252
|
+
default="",
|
|
253
|
+
help="Vegetation file (raster), value will be stored in 'vegetation_dim' field",
|
|
254
|
+
)
|
|
255
|
+
parser.add_argument(
|
|
256
|
+
"--vegetation_dim", type=str, default="Deviation", help="name of the extra_dim uses for the vegetation value"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def from_stream_func(args):
|
|
261
|
+
color_from_stream(
|
|
210
262
|
input_file=args.input,
|
|
211
263
|
output_file=args.output,
|
|
212
264
|
proj=args.proj,
|
|
@@ -221,3 +273,33 @@ if __name__ == "__main__":
|
|
|
221
273
|
stream_IRC=args.stream_IRC,
|
|
222
274
|
size_max_gpf=args.size_max_GPF,
|
|
223
275
|
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def from_files_func(args):
|
|
279
|
+
if args.image_RGB and args.image_RGB != "":
|
|
280
|
+
color_rvb_enabled = True
|
|
281
|
+
else:
|
|
282
|
+
color_rvb_enabled = False
|
|
283
|
+
if args.image_IRC and args.image_IRC != "":
|
|
284
|
+
color_irc_enabled = True
|
|
285
|
+
else:
|
|
286
|
+
color_irc_enabled = False
|
|
287
|
+
|
|
288
|
+
if not color_rvb_enabled and not color_irc_enabled:
|
|
289
|
+
raise ValueError("At least one of --rvb or --ir must be provided")
|
|
290
|
+
|
|
291
|
+
color_from_files(
|
|
292
|
+
input_file=args.input,
|
|
293
|
+
output_file=args.output,
|
|
294
|
+
rgb_image=args.image_RGB,
|
|
295
|
+
irc_image=args.image_IRC,
|
|
296
|
+
color_rvb_enabled=color_rvb_enabled,
|
|
297
|
+
color_ir_enabled=color_irc_enabled,
|
|
298
|
+
veget_index_file=args.vegetation,
|
|
299
|
+
vegetation_dim=args.vegetation_dim,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
if __name__ == "__main__":
|
|
304
|
+
args = argument_parser.parse_args()
|
|
305
|
+
args.func(args)
|
pdaltools/las_comparison.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import argparse
|
|
2
|
-
from
|
|
3
|
-
from typing import Tuple
|
|
2
|
+
from typing import Tuple, Dict, Optional
|
|
4
3
|
|
|
5
4
|
import laspy
|
|
6
5
|
import numpy as np
|
|
7
6
|
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
8
9
|
|
|
9
|
-
def compare_las_dimensions(file1: Path, file2: Path, dimensions: list = None) -> Tuple[bool, int, float]:
|
|
10
|
+
def compare_las_dimensions(file1: Path, file2: Path, dimensions: list = None, precision: Optional[Dict[str, float]] = None) -> Tuple[bool, int, float]:
|
|
10
11
|
"""
|
|
11
12
|
Compare specified dimensions between two LAS files.
|
|
12
13
|
If no dimensions are specified, compares all available dimensions.
|
|
@@ -16,6 +17,8 @@ def compare_las_dimensions(file1: Path, file2: Path, dimensions: list = None) ->
|
|
|
16
17
|
file1: Path to the first LAS file
|
|
17
18
|
file2: Path to the second LAS file
|
|
18
19
|
dimensions: List of dimension names to compare (optional)
|
|
20
|
+
precision: Dictionary mapping dimension names to tolerance values for float comparison.
|
|
21
|
+
If None or dimension not in dict, uses exact comparison (default: None)
|
|
19
22
|
|
|
20
23
|
Returns:
|
|
21
24
|
bool: True if all specified dimensions are identical, False otherwise
|
|
@@ -59,20 +62,42 @@ def compare_las_dimensions(file1: Path, file2: Path, dimensions: list = None) ->
|
|
|
59
62
|
# Compare each dimension
|
|
60
63
|
for dim in dimensions:
|
|
61
64
|
try:
|
|
65
|
+
|
|
62
66
|
# Get sorted dimension arrays
|
|
63
67
|
dim1 = np.array(las1[dim])[sort_idx1]
|
|
64
68
|
dim2 = np.array(las2[dim])[sort_idx2]
|
|
65
69
|
|
|
70
|
+
# Get precision for this dimension (if specified)
|
|
71
|
+
dim_precision = None
|
|
72
|
+
if precision is not None and dim in precision:
|
|
73
|
+
dim_precision = precision[dim]
|
|
74
|
+
|
|
66
75
|
# Compare dimensions
|
|
67
|
-
if not
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
print(f"
|
|
75
|
-
|
|
76
|
+
if dim_precision is not None:
|
|
77
|
+
# Use tolerance-based comparison for floats
|
|
78
|
+
are_equal = np.allclose(dim1, dim2, rtol=0, atol=dim_precision)
|
|
79
|
+
if not are_equal:
|
|
80
|
+
# Find differences
|
|
81
|
+
diff_mask = ~np.isclose(dim1, dim2, rtol=0, atol=dim_precision)
|
|
82
|
+
diff_indices = np.where(diff_mask)[0]
|
|
83
|
+
print(f"Found {len(diff_indices)} points with different {dim} (tolerance={dim_precision}):")
|
|
84
|
+
for idx in diff_indices[:10]: # Show first 10 differences
|
|
85
|
+
diff_value = abs(dim1[idx] - dim2[idx])
|
|
86
|
+
print(f"Point {idx}: file1={dim1[idx]}, file2={dim2[idx]}, diff={diff_value}")
|
|
87
|
+
if len(diff_indices) > 10:
|
|
88
|
+
print(f"... and {len(diff_indices) - 10} more differences")
|
|
89
|
+
return False, len(diff_indices), 100 * len(diff_indices) / len(las1)
|
|
90
|
+
else:
|
|
91
|
+
# Exact comparison
|
|
92
|
+
if not np.array_equal(dim1, dim2):
|
|
93
|
+
# Find differences
|
|
94
|
+
diff_indices = np.where(dim1 != dim2)[0]
|
|
95
|
+
print(f"Found {len(diff_indices)} points with different {dim}:")
|
|
96
|
+
for idx in diff_indices[:10]: # Show first 10 differences
|
|
97
|
+
print(f"Point {idx}: file1={dim1[idx]}, file2={dim2[idx]}")
|
|
98
|
+
if len(diff_indices) > 10:
|
|
99
|
+
print(f"... and {len(diff_indices) - 10} more differences")
|
|
100
|
+
return False, len(diff_indices), 100 * len(diff_indices) / len(las1)
|
|
76
101
|
|
|
77
102
|
except KeyError:
|
|
78
103
|
print(f"Dimension '{dim}' not found in one or both files")
|
|
@@ -93,12 +118,32 @@ def compare_las_dimensions(file1: Path, file2: Path, dimensions: list = None) ->
|
|
|
93
118
|
|
|
94
119
|
# Update main function to use the new compare function
|
|
95
120
|
def main():
|
|
96
|
-
parser = argparse.ArgumentParser(
|
|
121
|
+
parser = argparse.ArgumentParser(
|
|
122
|
+
description="Compare dimensions between two LAS files",
|
|
123
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
124
|
+
epilog="""
|
|
125
|
+
Examples:
|
|
126
|
+
# Compare all dimensions with exact match
|
|
127
|
+
python las_comparison.py file1.las file2.las
|
|
128
|
+
|
|
129
|
+
# Compare specific dimensions with precision per dimension
|
|
130
|
+
python las_comparison.py file1.las file2.las --dimensions X Y Z --precision X=0.001 Y=0.001 Z=0.0001
|
|
131
|
+
|
|
132
|
+
# Compare all dimensions with precision for specific ones
|
|
133
|
+
python las_comparison.py file1.las file2.las --precision X=0.001 Y=0.001
|
|
134
|
+
"""
|
|
135
|
+
)
|
|
97
136
|
parser.add_argument("file1", type=str, help="Path to first LAS file")
|
|
98
137
|
parser.add_argument("file2", type=str, help="Path to second LAS file")
|
|
99
138
|
parser.add_argument(
|
|
100
139
|
"--dimensions", nargs="*", help="List of dimensions to compare. If not specified, compares all dimensions."
|
|
101
140
|
)
|
|
141
|
+
parser.add_argument(
|
|
142
|
+
"--precision", nargs="*", metavar="DIM=VAL",
|
|
143
|
+
help="Tolerance for float comparison per dimension (format: DIMENSION=PRECISION). "
|
|
144
|
+
"Example: --precision X=0.001 Y=0.001 Z=0.0001. "
|
|
145
|
+
"Dimensions not specified will use exact comparison."
|
|
146
|
+
)
|
|
102
147
|
|
|
103
148
|
args = parser.parse_args()
|
|
104
149
|
|
|
@@ -109,7 +154,18 @@ def main():
|
|
|
109
154
|
print("Error: One or both files do not exist")
|
|
110
155
|
exit(1)
|
|
111
156
|
|
|
112
|
-
|
|
157
|
+
# Parse precision dictionary from command line arguments
|
|
158
|
+
precision_dict = None
|
|
159
|
+
if args.precision:
|
|
160
|
+
precision_dict = {}
|
|
161
|
+
for prec_spec in args.precision:
|
|
162
|
+
try:
|
|
163
|
+
dim_name, prec_value = prec_spec.split('=', 1)
|
|
164
|
+
precision_dict[dim_name] = float(prec_value)
|
|
165
|
+
except ValueError:
|
|
166
|
+
parser.error(f"Invalid precision format: '{prec_spec}'. Expected format: DIMENSION=PRECISION (e.g., X=0.001)")
|
|
167
|
+
|
|
168
|
+
result = compare_las_dimensions(file1, file2, args.dimensions, precision_dict)
|
|
113
169
|
print(f"Dimensions comparison result: {'identical' if result[0] else 'different'}")
|
|
114
170
|
return result
|
|
115
171
|
|
pdaltools/las_merge.py
CHANGED
|
@@ -6,20 +6,25 @@ import pdal
|
|
|
6
6
|
from pdaltools.las_info import parse_filename
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def
|
|
9
|
+
def create_filenames_suffixes(file: str, tile_width: int = 1000, tile_coord_scale: int = 1000):
|
|
10
10
|
"""Generate the name of the tiles around the input LIDAR tile
|
|
11
11
|
It supposes that the file names are formatted as {prefix1}_{prefix2}_{coordx}_{coordy}_{suffix}
|
|
12
12
|
with coordx and coordy having at least 4 digits
|
|
13
13
|
|
|
14
14
|
For example Semis_2021_0000_1111_LA93_IGN69.las
|
|
15
15
|
|
|
16
|
+
Generates only the suffix part of the filename, for example, for file like above, it will generate:
|
|
17
|
+
_0000_1112_LA93_IGN69.las
|
|
18
|
+
_0001_1112_LA93_IGN69.las
|
|
19
|
+
...
|
|
20
|
+
|
|
16
21
|
Args:
|
|
17
22
|
file(str): name of LIDAR file
|
|
18
23
|
tile width (int): width of tiles in meters (usually 1000m)
|
|
19
24
|
tile_coord_scale (int) : scale used in the filename to describe coordinates in meters
|
|
20
25
|
(usually 1000m)
|
|
21
26
|
Returns:
|
|
22
|
-
list_input(list): List of LIDAR's
|
|
27
|
+
list_input(list): List of LIDAR's filename suffix.
|
|
23
28
|
"""
|
|
24
29
|
|
|
25
30
|
# Create name of LIDAR tiles who cercle the tile
|
|
@@ -27,42 +32,52 @@ def create_filenames(file: str, tile_width: int = 1000, tile_coord_scale: int =
|
|
|
27
32
|
_prefix, coord_x, coord_y, _suffix = parse_filename(file)
|
|
28
33
|
offset = int(tile_width / tile_coord_scale)
|
|
29
34
|
# On left
|
|
30
|
-
_tile_hl = f"
|
|
31
|
-
_tile_ml = f"
|
|
32
|
-
_tile_bl = f"
|
|
35
|
+
_tile_hl = f"_{(coord_x - offset):04d}_{(coord_y + offset):04d}_{_suffix}"
|
|
36
|
+
_tile_ml = f"_{(coord_x - offset):04d}_{coord_y:04d}_{_suffix}"
|
|
37
|
+
_tile_bl = f"_{(coord_x - offset):04d}_{(coord_y - offset):04d}_{_suffix}"
|
|
33
38
|
# On Right
|
|
34
|
-
_tile_hr = f"
|
|
35
|
-
_tile_mr = f"
|
|
36
|
-
_tile_br = f"
|
|
39
|
+
_tile_hr = f"_{(coord_x + offset):04d}_{(coord_y + offset):04d}_{_suffix}"
|
|
40
|
+
_tile_mr = f"_{(coord_x + offset):04d}_{coord_y:04d}_{_suffix}"
|
|
41
|
+
_tile_br = f"_{(coord_x + offset):04d}_{(coord_y - offset):04d}_{_suffix}"
|
|
37
42
|
# Above
|
|
38
|
-
_tile_a = f"
|
|
43
|
+
_tile_a = f"_{coord_x:04d}_{(coord_y + offset):04d}_{_suffix}"
|
|
39
44
|
# Below
|
|
40
|
-
_tile_b = f"
|
|
45
|
+
_tile_b = f"_{coord_x:04d}_{(coord_y - offset):04d}_{_suffix}"
|
|
41
46
|
# Return the severals tile's names
|
|
42
47
|
return _tile_hl, _tile_ml, _tile_bl, _tile_a, _tile_b, _tile_hr, _tile_mr, _tile_br
|
|
43
48
|
|
|
44
49
|
|
|
45
|
-
def
|
|
46
|
-
"""
|
|
50
|
+
def match_suffix_with_filenames(suffix_list: list, all_files: list, las_dir: str):
|
|
51
|
+
"""Match suffix list with real filenames
|
|
47
52
|
Args:
|
|
48
|
-
|
|
53
|
+
suffix_list (list): List of suffix patterns to match
|
|
54
|
+
all_files (list): List of all files in las_dir
|
|
55
|
+
las_dir (str): Directory of pointclouds
|
|
49
56
|
|
|
50
57
|
Returns:
|
|
51
|
-
|
|
58
|
+
las_list(List): List of matched files
|
|
52
59
|
"""
|
|
53
|
-
|
|
54
|
-
for
|
|
55
|
-
if
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
las_list = []
|
|
61
|
+
for suffix in suffix_list:
|
|
62
|
+
matches = [filename for filename in all_files if filename.endswith(suffix)]
|
|
63
|
+
if len(matches) == 0:
|
|
64
|
+
logging.info(f"NOK : {suffix}")
|
|
58
65
|
else:
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
# in case of multiple matches, select the most recent year (ex: Semis_2021_ before Semis_2020_ )
|
|
67
|
+
matches.sort(reverse=True)
|
|
68
|
+
selected = matches[0]
|
|
69
|
+
if len(matches) > 1:
|
|
70
|
+
logging.warning(f"Multiple matches for {suffix} : {matches} ; taking {selected}")
|
|
61
71
|
|
|
72
|
+
# Append full path
|
|
73
|
+
las_list.append(os.path.join(las_dir, selected))
|
|
74
|
+
return las_list
|
|
62
75
|
|
|
63
|
-
|
|
76
|
+
|
|
77
|
+
def create_tiles_list(all_files, las_dir, input_file, tile_width=1000, tile_coord_scale=1000):
|
|
64
78
|
"""Return the paths of 8 tiles around the tile + the input tile
|
|
65
79
|
Args:
|
|
80
|
+
all_files (list): list of all files in las_dir
|
|
66
81
|
las_dir (str): directory of pointclouds
|
|
67
82
|
input_file (str): path to queried LIDAR tile
|
|
68
83
|
tile_width (int): Width of a tile(in the reference unit: 1m)
|
|
@@ -70,19 +85,39 @@ def create_list(las_dir, input_file, tile_width=1000, tile_coord_scale=1000):
|
|
|
70
85
|
1000 * 1m (with 1m being the reference)
|
|
71
86
|
|
|
72
87
|
Returns:
|
|
73
|
-
list_files
|
|
88
|
+
list_files: list of tiles
|
|
74
89
|
"""
|
|
75
90
|
|
|
76
|
-
# Return list 8 tiles around the tile
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
# Return list 8 tiles around the tile, but only the suffix part of the name.
|
|
92
|
+
suffix_list = create_filenames_suffixes(os.path.basename(input_file), tile_width, tile_coord_scale)
|
|
93
|
+
|
|
94
|
+
# Match suffix patterns with real files
|
|
95
|
+
list_files = match_suffix_with_filenames(suffix_list, all_files, las_dir)
|
|
96
|
+
|
|
82
97
|
# Appending queried tile to list
|
|
83
|
-
|
|
98
|
+
list_files.append(input_file)
|
|
99
|
+
|
|
100
|
+
return list_files
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def create_list(las_dir, input_file, tile_width=1000, tile_coord_scale=1000):
|
|
104
|
+
"""Return the paths of 8 tiles around the tile + the input tile
|
|
105
|
+
Args:
|
|
106
|
+
las_dir (str): directory of pointclouds
|
|
107
|
+
input_file (str): path to queried LIDAR tile
|
|
108
|
+
tile_width (int): Width of a tile(in the reference unit: 1m)
|
|
109
|
+
tile_coord_scale (int): Scale used in filename to describe coordinates (usually kilometers)
|
|
110
|
+
1000 * 1m (with 1m being the reference)
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
list_files: list of tiles
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
# list files on the disk
|
|
117
|
+
all_files = os.listdir(las_dir)
|
|
84
118
|
|
|
85
|
-
|
|
119
|
+
# call the function with the list of files
|
|
120
|
+
return create_tiles_list(all_files, las_dir, input_file, tile_width, tile_coord_scale)
|
|
86
121
|
|
|
87
122
|
|
|
88
123
|
def las_merge(las_dir, input_file, merge_file, tile_width=1000, tile_coord_scale=1000):
|
|
File without changes
|
|
File without changes
|