ign-pdal-tools 1.12.3__tar.gz → 1.14.0__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.12.3 → ign_pdal_tools-1.14.0}/PKG-INFO +2 -1
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/README.md +1 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/PKG-INFO +2 -1
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/SOURCES.txt +4 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/_version.py +1 -1
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/add_points_in_pointcloud.py +1 -1
- ign_pdal_tools-1.14.0/pdaltools/color.py +223 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/create_random_laz.py +36 -14
- ign_pdal_tools-1.12.3/pdaltools/color.py → ign_pdal_tools-1.14.0/pdaltools/download_image.py +55 -227
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_rename_dimension.py +8 -0
- ign_pdal_tools-1.14.0/pdaltools/replace_area_in_pointcloud.py +79 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_add_points_in_pointcloud.py +11 -0
- ign_pdal_tools-1.14.0/test/test_color.py +198 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_create_random_laz.py +43 -2
- ign_pdal_tools-1.12.3/test/test_color.py → ign_pdal_tools-1.14.0/test/test_download_image.py +37 -119
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_add_buffer.py +1 -1
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_rename_dimension.py +34 -16
- ign_pdal_tools-1.14.0/test/test_replace_area_in_pointcloud.py +118 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/LICENSE.md +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/dependency_links.txt +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/top_level.txt +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_add_buffer.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_clip.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_comparison.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_info.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_merge.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_remove_dimensions.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/pcd_info.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/replace_attribute_in_las.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/standardize_format.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/unlock_file.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pyproject.toml +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/setup.cfg +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_clip.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_comparison.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_info.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_merge.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_remove_dimensions.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_pcd_info.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_pdal_custom.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_replace_attribute_in_las.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_standardize_format.py +0 -0
- {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_unlock.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ign-pdal-tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.0
|
|
4
4
|
Summary: Library for common LAS files manipulation with PDAL
|
|
5
5
|
Author-email: Guillaume Liegard <guillaume.liegard@ign.fr>
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -68,6 +68,7 @@ pcd_infos.get_pointcloud_origin_from_tile_width(points, tile_width=1000)
|
|
|
68
68
|
* [las_clip.py](pdaltools/las_clip.py): crop a LAS file using 2d bounding box
|
|
69
69
|
* [las_merge.py](pdaltools/las_merge.py): merge a LAS file with its neighbors according to their filenames
|
|
70
70
|
* [las_add_buffer.py](pdaltools/las_add_buffer.py): add points to a LAS file from a buffer (border) from its neighbors (using filenames to locate neighbors)
|
|
71
|
+
* [replace_area_in_pointcloud.py](pdaltools/replace_area_in_pointcloud.py): replace the points from a LAS file by the points of another LAS file inside areas defined in a vector file (geojson, shapefile)
|
|
71
72
|
|
|
72
73
|
**WARNING**: In `las_merge.py` and `las_add_buffer.py`, filenames are used to get the LAS files extents
|
|
73
74
|
and to find neighbors.
|
|
@@ -59,6 +59,7 @@ pcd_infos.get_pointcloud_origin_from_tile_width(points, tile_width=1000)
|
|
|
59
59
|
* [las_clip.py](pdaltools/las_clip.py): crop a LAS file using 2d bounding box
|
|
60
60
|
* [las_merge.py](pdaltools/las_merge.py): merge a LAS file with its neighbors according to their filenames
|
|
61
61
|
* [las_add_buffer.py](pdaltools/las_add_buffer.py): add points to a LAS file from a buffer (border) from its neighbors (using filenames to locate neighbors)
|
|
62
|
+
* [replace_area_in_pointcloud.py](pdaltools/replace_area_in_pointcloud.py): replace the points from a LAS file by the points of another LAS file inside areas defined in a vector file (geojson, shapefile)
|
|
62
63
|
|
|
63
64
|
**WARNING**: In `las_merge.py` and `las_add_buffer.py`, filenames are used to get the LAS files extents
|
|
64
65
|
and to find neighbors.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ign-pdal-tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.0
|
|
4
4
|
Summary: Library for common LAS files manipulation with PDAL
|
|
5
5
|
Author-email: Guillaume Liegard <guillaume.liegard@ign.fr>
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -68,6 +68,7 @@ pcd_infos.get_pointcloud_origin_from_tile_width(points, tile_width=1000)
|
|
|
68
68
|
* [las_clip.py](pdaltools/las_clip.py): crop a LAS file using 2d bounding box
|
|
69
69
|
* [las_merge.py](pdaltools/las_merge.py): merge a LAS file with its neighbors according to their filenames
|
|
70
70
|
* [las_add_buffer.py](pdaltools/las_add_buffer.py): add points to a LAS file from a buffer (border) from its neighbors (using filenames to locate neighbors)
|
|
71
|
+
* [replace_area_in_pointcloud.py](pdaltools/replace_area_in_pointcloud.py): replace the points from a LAS file by the points of another LAS file inside areas defined in a vector file (geojson, shapefile)
|
|
71
72
|
|
|
72
73
|
**WARNING**: In `las_merge.py` and `las_add_buffer.py`, filenames are used to get the LAS files extents
|
|
73
74
|
and to find neighbors.
|
|
@@ -9,6 +9,7 @@ pdaltools/_version.py
|
|
|
9
9
|
pdaltools/add_points_in_pointcloud.py
|
|
10
10
|
pdaltools/color.py
|
|
11
11
|
pdaltools/create_random_laz.py
|
|
12
|
+
pdaltools/download_image.py
|
|
12
13
|
pdaltools/las_add_buffer.py
|
|
13
14
|
pdaltools/las_clip.py
|
|
14
15
|
pdaltools/las_comparison.py
|
|
@@ -17,12 +18,14 @@ pdaltools/las_merge.py
|
|
|
17
18
|
pdaltools/las_remove_dimensions.py
|
|
18
19
|
pdaltools/las_rename_dimension.py
|
|
19
20
|
pdaltools/pcd_info.py
|
|
21
|
+
pdaltools/replace_area_in_pointcloud.py
|
|
20
22
|
pdaltools/replace_attribute_in_las.py
|
|
21
23
|
pdaltools/standardize_format.py
|
|
22
24
|
pdaltools/unlock_file.py
|
|
23
25
|
test/test_add_points_in_pointcloud.py
|
|
24
26
|
test/test_color.py
|
|
25
27
|
test/test_create_random_laz.py
|
|
28
|
+
test/test_download_image.py
|
|
26
29
|
test/test_las_add_buffer.py
|
|
27
30
|
test/test_las_clip.py
|
|
28
31
|
test/test_las_comparison.py
|
|
@@ -32,6 +35,7 @@ test/test_las_remove_dimensions.py
|
|
|
32
35
|
test/test_las_rename_dimension.py
|
|
33
36
|
test/test_pcd_info.py
|
|
34
37
|
test/test_pdal_custom.py
|
|
38
|
+
test/test_replace_area_in_pointcloud.py
|
|
35
39
|
test/test_replace_attribute_in_las.py
|
|
36
40
|
test/test_standardize_format.py
|
|
37
41
|
test/test_unlock.py
|
|
@@ -169,7 +169,7 @@ def add_points_to_las(
|
|
|
169
169
|
pipeline |= pdal.Reader.las(filename=input_las)
|
|
170
170
|
pipeline |= pdal.Reader.las(filename=tmp.name)
|
|
171
171
|
pipeline |= pdal.Filter.merge()
|
|
172
|
-
pipeline |= pdal.Writer.las(filename=output_las, forward="all", a_srs=a_srs)
|
|
172
|
+
pipeline |= pdal.Writer.las(filename=output_las, forward="all", extra_dims="all", a_srs=a_srs)
|
|
173
173
|
pipeline.execute()
|
|
174
174
|
|
|
175
175
|
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import tempfile
|
|
3
|
+
from math import ceil, floor
|
|
4
|
+
from typing import Tuple
|
|
5
|
+
|
|
6
|
+
import pdal
|
|
7
|
+
|
|
8
|
+
import pdaltools.las_info as las_info
|
|
9
|
+
from pdaltools.download_image import download_image
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def match_min_max_with_pixel_size(min_d: float, max_d: float, pixel_per_meter: float) -> Tuple[float, float]:
|
|
13
|
+
"""Round min/max values along one dimension to the closest multiple of 1 / pixel_per_meter
|
|
14
|
+
It should prevent having to interpolate during a request to the geoplateforme
|
|
15
|
+
in case we use a native resolution.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
min_d (float): minimum value along the dimension, in meters
|
|
19
|
+
max_d (float): maximum value along the dimension, in meters
|
|
20
|
+
pixel_per_meter (float): resolution (in number of pixels per meter)
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Tuple[float, float]: adapted min / max value
|
|
24
|
+
"""
|
|
25
|
+
# Use ceil - 1 instead of ceil to make sure that
|
|
26
|
+
# no point of the pointcloud is on the limit of the first pixel
|
|
27
|
+
min_d = (ceil(min_d * pixel_per_meter) - 1) / pixel_per_meter
|
|
28
|
+
# Use floor + 1 instead of ceil to make sure that no point of the pointcloud is on the limit of the last pixel
|
|
29
|
+
max_d = (floor(max_d * pixel_per_meter) + 1) / pixel_per_meter
|
|
30
|
+
|
|
31
|
+
return min_d, max_d
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def color(
|
|
35
|
+
input_file: str,
|
|
36
|
+
output_file: str,
|
|
37
|
+
proj="",
|
|
38
|
+
pixel_per_meter=5,
|
|
39
|
+
timeout_second=300,
|
|
40
|
+
color_rvb_enabled=True,
|
|
41
|
+
color_ir_enabled=True,
|
|
42
|
+
veget_index_file="",
|
|
43
|
+
vegetation_dim="Deviation",
|
|
44
|
+
check_images=False,
|
|
45
|
+
stream_RGB="ORTHOIMAGERY.ORTHOPHOTOS",
|
|
46
|
+
stream_IRC="ORTHOIMAGERY.ORTHOPHOTOS.IRC",
|
|
47
|
+
size_max_gpf=5000,
|
|
48
|
+
):
|
|
49
|
+
"""Colorize a las file with any of the following methods:
|
|
50
|
+
- R, G, B values from an image retrieved from ign geoplateform via the "stream_RGB" data feed name
|
|
51
|
+
- Infrared from another image retrieved from ign geoplateform via the "stream_IRC" data feed name
|
|
52
|
+
- any field "vegetation_dim" from another image stored locally at "veget_index_file"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
input_file (str): Path to the las file to colorize
|
|
57
|
+
output_file (str): Path to the output colorized file
|
|
58
|
+
proj (str, optional): EPSG value of the SRS to apply to the output file (if not provided, use the one from
|
|
59
|
+
the input file). Eg. "2154" to use "EPSG:2154". Defaults to "".
|
|
60
|
+
pixel_per_meter (int, optional): Stream image resolution (for RGB and IRC) in pixels per meter. Defaults to 5.
|
|
61
|
+
timeout_second (int, optional): Timeout for the geoplateform request. Defaults to 300.
|
|
62
|
+
color_rvb_enabled (bool, optional): If true, apply R, G, B dimensions colorization. Defaults to True.
|
|
63
|
+
color_ir_enabled (bool, optional): If true, apply Infrared dimension colorization. Defaults to True.
|
|
64
|
+
veget_index_file (str, optional): Path to the tiff tile to use for "vegetation_dim" colorization.
|
|
65
|
+
Defaults to "".
|
|
66
|
+
vegetation_dim (str, optional): Name of the dimension to use to store the values of "veget_index_file".
|
|
67
|
+
Defaults to "Deviation".
|
|
68
|
+
check_images (bool, optional): If true, check if images from the geoplateform data feed are white
|
|
69
|
+
(and raise and error in this case). Defaults to False.
|
|
70
|
+
stream_RGB (str, optional): WMS raster stream for RGB colorization:
|
|
71
|
+
Default stream (ORTHOIMAGERY.ORTHOPHOTOS) let the server choose the resolution
|
|
72
|
+
for 20cm resolution rasters, use HR.ORTHOIMAGERY.ORTHOPHOTOS
|
|
73
|
+
for 50 cm resolution rasters, use ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO
|
|
74
|
+
Defaults to ORTHOIMAGERY.ORTHOPHOTOS
|
|
75
|
+
stream_IRC (str, optional):WMS raster stream for IRC colorization.
|
|
76
|
+
Documentation about possible stream : https://geoservices.ign.fr/services-web-experts-ortho.
|
|
77
|
+
Defaults to "ORTHOIMAGERY.ORTHOPHOTOS.IRC".
|
|
78
|
+
size_max_gpf (int, optional): Maximum edge size (in pixels) of downloaded images. If input file needs more,
|
|
79
|
+
several images are downloaded and merged. Defaults to 5000.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Paths to the temporary files that store the streamed images (tmp_ortho, tmp_ortho_irc)
|
|
83
|
+
"""
|
|
84
|
+
metadata = las_info.las_info_metadata(input_file)
|
|
85
|
+
minx, maxx, miny, maxy = las_info.get_bounds_from_header_info(metadata)
|
|
86
|
+
|
|
87
|
+
minx, maxx = match_min_max_with_pixel_size(minx, maxx, pixel_per_meter)
|
|
88
|
+
miny, maxy = match_min_max_with_pixel_size(miny, maxy, pixel_per_meter)
|
|
89
|
+
|
|
90
|
+
if proj == "":
|
|
91
|
+
proj = las_info.get_epsg_from_header_info(metadata)
|
|
92
|
+
|
|
93
|
+
pipeline = pdal.Reader.las(filename=input_file)
|
|
94
|
+
|
|
95
|
+
writer_extra_dims = "all"
|
|
96
|
+
|
|
97
|
+
if veget_index_file and veget_index_file != "":
|
|
98
|
+
print(f"Remplissage du champ {vegetation_dim} à partir du fichier {veget_index_file}")
|
|
99
|
+
pipeline |= pdal.Filter.colorization(raster=veget_index_file, dimensions=f"{vegetation_dim}:1:256.0")
|
|
100
|
+
writer_extra_dims = [f"{vegetation_dim}=ushort"]
|
|
101
|
+
|
|
102
|
+
tmp_ortho = None
|
|
103
|
+
if color_rvb_enabled:
|
|
104
|
+
tmp_ortho = tempfile.NamedTemporaryFile(suffix="_rvb.tif")
|
|
105
|
+
download_image(
|
|
106
|
+
proj,
|
|
107
|
+
stream_RGB,
|
|
108
|
+
minx,
|
|
109
|
+
miny,
|
|
110
|
+
maxx,
|
|
111
|
+
maxy,
|
|
112
|
+
pixel_per_meter,
|
|
113
|
+
tmp_ortho.name,
|
|
114
|
+
timeout_second,
|
|
115
|
+
check_images,
|
|
116
|
+
size_max_gpf,
|
|
117
|
+
)
|
|
118
|
+
# Warning: the initial color is multiplied by 256 despite its initial 8-bits encoding
|
|
119
|
+
# which turns it to a 0 to 255*256 range.
|
|
120
|
+
# It is kept this way because of other dependencies that have been tuned to fit this range
|
|
121
|
+
pipeline |= pdal.Filter.colorization(
|
|
122
|
+
raster=tmp_ortho.name, dimensions="Red:1:256.0, Green:2:256.0, Blue:3:256.0"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
tmp_ortho_irc = None
|
|
126
|
+
if color_ir_enabled:
|
|
127
|
+
tmp_ortho_irc = tempfile.NamedTemporaryFile(suffix="_irc.tif")
|
|
128
|
+
download_image(
|
|
129
|
+
proj,
|
|
130
|
+
stream_IRC,
|
|
131
|
+
minx,
|
|
132
|
+
miny,
|
|
133
|
+
maxx,
|
|
134
|
+
maxy,
|
|
135
|
+
pixel_per_meter,
|
|
136
|
+
tmp_ortho_irc.name,
|
|
137
|
+
timeout_second,
|
|
138
|
+
check_images,
|
|
139
|
+
size_max_gpf,
|
|
140
|
+
)
|
|
141
|
+
# Warning: the initial color is multiplied by 256 despite its initial 8-bits encoding
|
|
142
|
+
# which turns it to a 0 to 255*256 range.
|
|
143
|
+
# It is kept this way because of other dependencies that have been tuned to fit this range
|
|
144
|
+
pipeline |= pdal.Filter.colorization(raster=tmp_ortho_irc.name, dimensions="Infrared:1:256.0")
|
|
145
|
+
|
|
146
|
+
pipeline |= pdal.Writer.las(
|
|
147
|
+
filename=output_file, extra_dims=writer_extra_dims, minor_version="4", dataformat_id="8", forward="all"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
print("Traitement du nuage de point")
|
|
151
|
+
pipeline.execute()
|
|
152
|
+
|
|
153
|
+
# The orthoimages files will be deleted only when their reference are lost.
|
|
154
|
+
# To keep them, make a copy (with e.g. shutil.copy(...))
|
|
155
|
+
# See: https://docs.python.org/2/library/tempfile.html#tempfile.TemporaryFile
|
|
156
|
+
return tmp_ortho, tmp_ortho_irc
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def parse_args():
|
|
160
|
+
parser = argparse.ArgumentParser("Colorize tool", formatter_class=argparse.RawTextHelpFormatter)
|
|
161
|
+
parser.add_argument("--input", "-i", type=str, required=True, help="Input file")
|
|
162
|
+
parser.add_argument("--output", "-o", type=str, default="", help="Output file")
|
|
163
|
+
parser.add_argument(
|
|
164
|
+
"--proj", "-p", type=str, default="", help="Projection, default will use projection from metadata input"
|
|
165
|
+
)
|
|
166
|
+
parser.add_argument("--resolution", "-r", type=float, default=5, help="Resolution, in pixel per meter")
|
|
167
|
+
parser.add_argument("--timeout", "-t", type=int, default=300, help="Timeout, in seconds")
|
|
168
|
+
parser.add_argument("--rvb", action="store_true", help="Colorize RVB")
|
|
169
|
+
parser.add_argument("--ir", action="store_true", help="Colorize IR")
|
|
170
|
+
parser.add_argument(
|
|
171
|
+
"--vegetation",
|
|
172
|
+
type=str,
|
|
173
|
+
default="",
|
|
174
|
+
help="Vegetation file (raster), value will be stored in 'vegetation_dim' field",
|
|
175
|
+
)
|
|
176
|
+
parser.add_argument(
|
|
177
|
+
"--vegetation_dim", type=str, default="Deviation", help="name of the extra_dim uses for the vegetation value"
|
|
178
|
+
)
|
|
179
|
+
parser.add_argument("--check-images", "-c", action="store_true", help="Check that downloaded image is not white")
|
|
180
|
+
parser.add_argument(
|
|
181
|
+
"--stream-RGB",
|
|
182
|
+
type=str,
|
|
183
|
+
default="ORTHOIMAGERY.ORTHOPHOTOS",
|
|
184
|
+
help="""WMS raster stream for RGB colorization:
|
|
185
|
+
default stream (ORTHOIMAGERY.ORTHOPHOTOS) let the server choose the resolution
|
|
186
|
+
for 20cm resolution rasters, use HR.ORTHOIMAGERY.ORTHOPHOTOS
|
|
187
|
+
for 50 cm resolution rasters, use ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO""",
|
|
188
|
+
)
|
|
189
|
+
parser.add_argument(
|
|
190
|
+
"--stream-IRC",
|
|
191
|
+
type=str,
|
|
192
|
+
default="ORTHOIMAGERY.ORTHOPHOTOS.IRC",
|
|
193
|
+
help="""WMS raster stream for IRC colorization. Default to ORTHOIMAGERY.ORTHOPHOTOS.IRC
|
|
194
|
+
Documentation about possible stream : https://geoservices.ign.fr/services-web-experts-ortho""",
|
|
195
|
+
)
|
|
196
|
+
parser.add_argument(
|
|
197
|
+
"--size-max-GPF",
|
|
198
|
+
type=int,
|
|
199
|
+
default=5000,
|
|
200
|
+
help="Maximum edge size (in pixels) of downloaded images."
|
|
201
|
+
" If input file needs more, several images are downloaded and merged.",
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
return parser.parse_args()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
if __name__ == "__main__":
|
|
208
|
+
args = parse_args()
|
|
209
|
+
color(
|
|
210
|
+
input_file=args.input,
|
|
211
|
+
output_file=args.output,
|
|
212
|
+
proj=args.proj,
|
|
213
|
+
pixel_per_meter=args.resolution,
|
|
214
|
+
timeout_second=args.timeout,
|
|
215
|
+
color_rvb_enabled=args.rvb,
|
|
216
|
+
color_ir_enabled=args.ir,
|
|
217
|
+
veget_index_file=args.vegetation,
|
|
218
|
+
vegetation_dim=args.vegetation_dim,
|
|
219
|
+
check_images=args.check_images,
|
|
220
|
+
stream_RGB=args.stream_RGB,
|
|
221
|
+
stream_IRC=args.stream_IRC,
|
|
222
|
+
size_max_gpf=args.size_max_GPF,
|
|
223
|
+
)
|
|
@@ -8,11 +8,12 @@ from typing import List, Tuple
|
|
|
8
8
|
|
|
9
9
|
def create_random_laz(
|
|
10
10
|
output_file: str,
|
|
11
|
-
point_format: int =
|
|
11
|
+
point_format: int = 6,
|
|
12
12
|
num_points: int = 100,
|
|
13
13
|
crs: int = 2154,
|
|
14
14
|
center: Tuple[float, float] = (650000, 6810000),
|
|
15
15
|
extra_dims: List[Tuple[str, str]] = [],
|
|
16
|
+
classifications: List[int] = None,
|
|
16
17
|
):
|
|
17
18
|
"""
|
|
18
19
|
Create a test LAZ file with EPSG code and additional dimensions.
|
|
@@ -26,6 +27,7 @@ def create_random_laz(
|
|
|
26
27
|
(default: (650000, 6810000) ; around Paris)
|
|
27
28
|
extra_dims: List of tuples (dimension_name, dimension_type) where type can be:
|
|
28
29
|
'float32', 'float64', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'
|
|
30
|
+
classifications: Optional list of classification values.
|
|
29
31
|
"""
|
|
30
32
|
|
|
31
33
|
# Create a new point cloud
|
|
@@ -52,7 +54,7 @@ def create_random_laz(
|
|
|
52
54
|
numpy_type = type_mapping[dim_type]
|
|
53
55
|
header.add_extra_dim(laspy.ExtraBytesParams(name=dim_name, type=numpy_type))
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
# Create point cloud
|
|
56
58
|
las = laspy.LasData(header)
|
|
57
59
|
las.header.add_crs(CRS.from_string(f"epsg:{crs}"))
|
|
58
60
|
|
|
@@ -64,14 +66,19 @@ def create_random_laz(
|
|
|
64
66
|
# Generate random intensity values
|
|
65
67
|
las.intensity = np.random.randint(0, 255, num_points)
|
|
66
68
|
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
num_classifications = 66
|
|
69
|
+
# Set classification values
|
|
70
|
+
if classifications:
|
|
71
|
+
# Randomly select from the provided classification values
|
|
72
|
+
las.classification = np.random.choice(classifications, size=num_points, replace=True).astype(np.uint8)
|
|
72
73
|
else:
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
# Generate random classification values if not provided
|
|
75
|
+
# 66 is the max value for classification of IGN LidarHD
|
|
76
|
+
# cf. https://geoservices.ign.fr/sites/default/files/2022-05/DT_LiDAR_HD_1-0.pdf
|
|
77
|
+
if point_format >= 6:
|
|
78
|
+
num_classifications = 66
|
|
79
|
+
else:
|
|
80
|
+
num_classifications = 10
|
|
81
|
+
las.classification = np.random.randint(0, num_classifications, num_points, dtype=np.uint8)
|
|
75
82
|
|
|
76
83
|
# Generate random values for each extra dimension
|
|
77
84
|
for dim_name, dim_type in extra_dims:
|
|
@@ -112,20 +119,24 @@ def parse_args():
|
|
|
112
119
|
# Parse arguments (assuming argparse is used)
|
|
113
120
|
parser = argparse.ArgumentParser(description="Create a random LAZ file.")
|
|
114
121
|
parser.add_argument("--output_file", type=str, help="Path to save the LAZ file")
|
|
115
|
-
parser.add_argument("--point_format", type=int, default=
|
|
122
|
+
parser.add_argument("--point_format", type=int, default=6, help="Point format of the LAZ file")
|
|
116
123
|
parser.add_argument("--num_points", type=int, default=100, help="Number of points to generate")
|
|
117
124
|
parser.add_argument(
|
|
118
125
|
"--extra_dims", type=str, nargs="*", default=[], help="Extra dimensions in the format name:type"
|
|
119
126
|
)
|
|
120
127
|
parser.add_argument("--crs", type=int, default=2154, help="Projection code")
|
|
121
128
|
parser.add_argument(
|
|
122
|
-
"--center", type=
|
|
129
|
+
"--center", type=float, nargs=2, default=[650000.0, 6810000.0],
|
|
130
|
+
help="Center coordinates (x y) of the area to generate points in (space-separated)"
|
|
131
|
+
)
|
|
132
|
+
parser.add_argument(
|
|
133
|
+
"--classifications", type=int, nargs='+',
|
|
134
|
+
help="List of classification values (space-separated)"
|
|
123
135
|
)
|
|
124
136
|
return parser.parse_args()
|
|
125
137
|
|
|
126
138
|
|
|
127
139
|
def main():
|
|
128
|
-
|
|
129
140
|
# Parse arguments
|
|
130
141
|
args = parse_args()
|
|
131
142
|
|
|
@@ -133,10 +144,21 @@ def main():
|
|
|
133
144
|
extra_dims = [tuple(dim.split(":")) for dim in args.extra_dims]
|
|
134
145
|
|
|
135
146
|
# Parse center
|
|
136
|
-
center = tuple(
|
|
147
|
+
center = tuple(args.center[:2]) # Only take first 2 values if more are provided
|
|
148
|
+
|
|
149
|
+
# Parse classifications if provided
|
|
150
|
+
classifications = args.classifications
|
|
137
151
|
|
|
138
152
|
# Call create_random_laz
|
|
139
|
-
result = create_random_laz(
|
|
153
|
+
result = create_random_laz(
|
|
154
|
+
args.output_file,
|
|
155
|
+
args.point_format,
|
|
156
|
+
args.num_points,
|
|
157
|
+
args.crs,
|
|
158
|
+
center,
|
|
159
|
+
extra_dims,
|
|
160
|
+
classifications
|
|
161
|
+
)
|
|
140
162
|
|
|
141
163
|
# Test output file
|
|
142
164
|
test_output_file(result, args.output_file)
|