-
Notifications
You must be signed in to change notification settings - Fork 1
/
standardize_format.py
119 lines (102 loc) · 3.88 KB
/
standardize_format.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""Re-write las file with expected format:
- laz version
- [TODO] nomenclature ???
- record format
- global encoding
- projection
- precision
- no extra-dims
"""
import argparse
import os
import platform
import subprocess as sp
import tempfile
from typing import Dict, List
import pdal
from pdaltools.unlock_file import copy_and_hack_decorator
# Standard parameters to pass to the pdal writer
STANDARD_PARAMETERS = dict(
major_version="1",
minor_version="4", # Laz format version (pdal always write in 1.x format)
global_encoding=17, # store WKT projection in file
compression="true", # Save to compressed laz format
extra_dims=[], # Save no extra_dims
scale_x=0.01, # Precision of the stored data
scale_y=0.01,
scale_z=0.01,
offset_x=0, # No offset
offset_y=0,
offset_z=0,
dataformat_id=6, # No color by default
a_srs="EPSG:2154",
)
def parse_args():
parser = argparse.ArgumentParser("Rewrite laz file with standard format.")
parser.add_argument("--input_file", type=str, help="Laz input file.")
parser.add_argument("--output_file", type=str, help="Laz output file")
parser.add_argument(
"--record_format", choices=[6, 8], type=int, help="Record format: 6 (no color) or 8 (4 color channels)"
)
parser.add_argument("--projection", default="EPSG:2154", type=str, help="Projection, eg. EPSG:2154")
parser.add_argument(
"--class_points_removed",
default=[],
nargs="*",
type=str,
help="List of classes number. Points of this classes will be removed from the file",
)
parser.add_argument(
"--extra_dims",
default=[],
nargs="*",
type=str,
help="List of extra dims to keep in the output (default=[], use 'all' to keep all extra dims), "
"extra_dims must be specified with their type (see pdal.writers.las documentation, eg 'dim1=double')",
)
return parser.parse_args()
def get_writer_parameters(new_parameters: Dict) -> Dict:
"""
Get writer parameters from a set of standard parameters + a new set of parameters that can
override the standard ones
"""
params = STANDARD_PARAMETERS | new_parameters
return params
def rewrite_with_pdal(
input_file: str, output_file: str, params_from_parser: Dict, classes_to_remove: List = []
) -> None:
params = get_writer_parameters(params_from_parser)
pipeline = pdal.Pipeline()
pipeline |= pdal.Reader.las(input_file)
if classes_to_remove:
expression = "&&".join([f"Classification != {c}" for c in classes_to_remove])
pipeline |= pdal.Filter.expression(expression=expression)
pipeline |= pdal.Writer(filename=output_file, forward="all", **params)
pipeline.execute()
def exec_las2las(input_file: str, output_file: str):
if platform.processor() == "arm" and platform.architecture()[0] == "64bit":
las2las = "las2las64"
else:
las2las = "las2las"
r = sp.run([las2las, "-i", input_file, "-o", output_file], stderr=sp.PIPE, stdout=sp.PIPE)
if r.returncode == 1:
msg = r.stderr.decode()
print(msg)
raise RuntimeError(msg)
output = r.stdout.decode()
for line in output.splitlines():
print(line)
@copy_and_hack_decorator
def standardize(input_file: str, output_file: str, params_from_parser: Dict, class_points_removed: []) -> None:
filename = os.path.basename(output_file)
with tempfile.NamedTemporaryFile(suffix=filename) as tmp:
rewrite_with_pdal(input_file, tmp.name, params_from_parser, class_points_removed)
exec_las2las(tmp.name, output_file)
if __name__ == "__main__":
args = parse_args()
params_from_parser = dict(
dataformat_id=args.record_format,
a_srs=args.projection,
extra_dims=args.extra_dims,
)
standardize(args.input_file, args.output_file, params_from_parser, args.class_points_removed)