-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
218 lines (165 loc) · 6.31 KB
/
main.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# %% [markdown]
# ## Main for automatic tree cadastre
# ### by Sabine Zagst
# %% [markdown]
"""
Automatic Tree Cadastre
This program automatically creates a tree cadastre from a point cloud.
Copyright (c) 2022-2023 Sabine Zagst ([email protected])
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
# %% [markdown]
# #### Import
# %%
import numpy as np
import open3d as o3d
import laspy
import ground as gr
import cylinder_approach as ca
import imageProcessing_approach as ipa
import run_FME_Workspace as runFME
# %%
# TODO: Before using this program you have to set some parameters and define all necessary paths in the next section:
visualize = False
preprocessing_las = False
save_images = True
ground_rastersize = 1.0
pxlsize_binary_img = np.float64(0.025) # Arcisstrasse [m]
# pxlsize_binary_img = np.float64(0.040) # Pasinger Klostergarten [m]
# num_peaks influences correctnes and completeness
num_peaks = 10 # Arcisstrasse Sued
# num_peaks = 16 # Arcisstrasse Nord
# num_peaks = 45 # Pasinger Klostergarten
# %% [markdown]
# #### Define file paths
# %%
# Filepath and filename of point cloud
# filepath = "C:/Users/Sabine/Desktop/Masterarbeit_Code/Data/Arcisstrasse/"
# filename = "pp_arcisNorthThirdRound.pcd"
# filename = "pp_arcisSouthFirstRound.pcd"
filepath = (
"C:/Users/Sabine/Desktop/Masterarbeit_Code/Data/Arcisstrasse/georeferenziert/"
)
filename = "pp_arcisSouthFirstRound_geo.las"
# filename = "pp_arcisNorthFirstRound_geo.las"
# TODO: Turn off preprocessing!
# filepath = "C:/Users/Sabine/Desktop/Masterarbeit_Code/Data/Pasing_Klostergarten/Rucksack_Daten/georefed/"
# filename = "2022-10-25-12-06-51_MLS_garden_reg.las"
# TODO: Turn on preprocessing!
# filepath = "C:/Users/Sabine/Desktop/Masterarbeit_Code/Data/p seminar pktwolke/"
# filename = "P-Seminar_PW_bereinigt - CloudSegment.las"
# %% [markdown]
# ### Read and Preprocessing
# %%
print("Read point cloud: " + filename)
if any(ext in filename for ext in [".pcd", ".xyz", ".xyzn", ".xyzrgb", ".pts", ".ply"]):
cloud_o3d = o3d.io.read_point_cloud(filepath + filename, remove_nan_points=True)
# supported file types: http://www.open3d.org/docs/latest/tutorial/Basic/file_io.html
cloud_array = np.asarray(
cloud_o3d.points
) # necessary to access x, y, z - values; output array of float64 with size (numberOfPoints, 3)
# output for user
if len(cloud_array) > 0:
print("Read successful.")
print(cloud_o3d)
else:
print("Point cloud empty.")
elif any(ext in filename for ext in [".las", ".laz"]):
cloud = laspy.read(filepath + filename)
points = cloud.points
if len(cloud) > 0:
print("Read successful. File header: ")
print(cloud.header)
print("Number of points: ")
print(cloud.header.point_count)
else:
print("Point cloud empty.")
if preprocessing_las:
cloud_array_i = np.vstack(
(cloud.x, cloud.y, cloud.z, cloud.intensity)
).transpose()
# Filter intensity 0 and 255
cloud_array_i = cloud_array_i[cloud_array_i[:, 3] < 255]
cloud_array_i = cloud_array_i[cloud_array_i[:, 3] > 0]
cloud_array = cloud_array_i[:, 0:3]
print(f"Number of points after filtering with intensity: {len(cloud_array)}")
else:
cloud_array = np.vstack((cloud.x, cloud.y, cloud.z)).transpose()
# o3d cloud object
cloud_o3d = o3d.geometry.PointCloud()
cloud_o3d.points = o3d.utility.Vector3dVector(cloud_array)
if preprocessing_las:
# http://www.open3d.org/docs/release/python_api/open3d.geometry.PointCloud.html
# Remove duplicated points
cloud_o3d = cloud_o3d.remove_duplicated_points() # identical coordinates
print(
f"Number of points after removing duplicated points: {len(cloud_o3d.points)}"
)
# Remove all points from pcd that have a nan entry or infinite entries
cloud_o3d = cloud_o3d.remove_non_finite_points()
print(
f"Number of points after removing non-finite points: {len(cloud_o3d.points)}"
)
# Statistical outlier removal filter
# http://www.open3d.org/docs/latest/tutorial/Advanced/pointcloud_outlier_removal.html
# http://www.open3d.org/docs/0.6.0/python_api/open3d.geometry.statistical_outlier_removal.html
cloud_o3d, ind = cloud_o3d.remove_statistical_outlier(
nb_neighbors=10, std_ratio=2.0
)
cloud_array = np.asarray(cloud_o3d.points)
print(f"Number of points after SOR filtering: {len(cloud_array)}")
else:
print("Unsupported file type.")
print(cloud_array)
# %% [markdown]
# #### Visualize input point cloud
# %%
# Press the H key to print out a complete list of keyboard instructions for the GUI
if visualize:
o3d.visualization.draw_geometries([cloud_o3d])
# %% [markdown]
# #### Write point cloud to file
# %%
# o3d.io.write_point_cloud("copy_of_pcd.pcd", cloud_o3d, write_ascii=False)
# outFile = laspy.LasData(cloud.header)
# # extract ground points, and save it to a las file.
# outFile.points = points[ground_array]
# outFile.write("csf_pcd/ground.las")
# %% [markdown]
# #### Ground
# %%
ground_array, nonGround_array, ground_grid = gr.process_ground(
cloud_array, "ground_grid", ground_rastersize, visualize, save_images
)
# %% [markdown]
# #### Tree Parameters
# %%
# nonGround_o3d = o3d.geometry.PointCloud()
# nonGround_o3d.points = o3d.utility.Vector3dVector(nonGround_array)
# dbh = ca.cylinder_approach(nonGround_o3d, visualize=True)
# print(dbh)
# %%
ipa.imageProcessing_approach(
nonGround_array,
ground_grid,
pxlsize_binary_img,
np.float64(0.10),
num_peaks,
save_images,
visualize,
ground_rastersize,
)
# for results see output folder
# %% [markdown]
# #### Run FME Workflow
# %%
runFME.run_FME_Workspace()