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.
Files changed (43) hide show
  1. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/PKG-INFO +2 -1
  2. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/README.md +1 -0
  3. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/PKG-INFO +2 -1
  4. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/SOURCES.txt +4 -0
  5. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/_version.py +1 -1
  6. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/add_points_in_pointcloud.py +1 -1
  7. ign_pdal_tools-1.14.0/pdaltools/color.py +223 -0
  8. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/create_random_laz.py +36 -14
  9. ign_pdal_tools-1.12.3/pdaltools/color.py → ign_pdal_tools-1.14.0/pdaltools/download_image.py +55 -227
  10. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_rename_dimension.py +8 -0
  11. ign_pdal_tools-1.14.0/pdaltools/replace_area_in_pointcloud.py +79 -0
  12. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_add_points_in_pointcloud.py +11 -0
  13. ign_pdal_tools-1.14.0/test/test_color.py +198 -0
  14. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_create_random_laz.py +43 -2
  15. ign_pdal_tools-1.12.3/test/test_color.py → ign_pdal_tools-1.14.0/test/test_download_image.py +37 -119
  16. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_add_buffer.py +1 -1
  17. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_rename_dimension.py +34 -16
  18. ign_pdal_tools-1.14.0/test/test_replace_area_in_pointcloud.py +118 -0
  19. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/LICENSE.md +0 -0
  20. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/dependency_links.txt +0 -0
  21. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/ign_pdal_tools.egg-info/top_level.txt +0 -0
  22. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_add_buffer.py +0 -0
  23. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_clip.py +0 -0
  24. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_comparison.py +0 -0
  25. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_info.py +0 -0
  26. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_merge.py +0 -0
  27. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/las_remove_dimensions.py +0 -0
  28. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/pcd_info.py +0 -0
  29. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/replace_attribute_in_las.py +0 -0
  30. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/standardize_format.py +0 -0
  31. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pdaltools/unlock_file.py +0 -0
  32. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/pyproject.toml +0 -0
  33. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/setup.cfg +0 -0
  34. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_clip.py +0 -0
  35. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_comparison.py +0 -0
  36. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_info.py +0 -0
  37. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_merge.py +0 -0
  38. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_las_remove_dimensions.py +0 -0
  39. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_pcd_info.py +0 -0
  40. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_pdal_custom.py +0 -0
  41. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_replace_attribute_in_las.py +0 -0
  42. {ign_pdal_tools-1.12.3 → ign_pdal_tools-1.14.0}/test/test_standardize_format.py +0 -0
  43. {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.12.3
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.12.3
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
@@ -1,4 +1,4 @@
1
- __version__ = "1.12.3"
1
+ __version__ = "1.14.0"
2
2
 
3
3
 
4
4
  if __name__ == "__main__":
@@ -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 = 3,
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
- # Create point cloud
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
- # Generate random classification values
68
- # 66 is the max value for classification of IGN LidarHD
69
- # cf. https://geoservices.ign.fr/sites/default/files/2022-05/DT_LiDAR_HD_1-0.pdf
70
- if point_format > 3:
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
- num_classifications = 10
74
- las.classification = np.random.randint(0, num_classifications, num_points)
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=3, help="Point format of the LAZ file")
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=str, default="650000,6810000", help="Center of the area to generate points in"
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(map(float, args.center.split(",")))
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(args.output_file, args.point_format, args.num_points, args.crs, center, extra_dims)
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)