cars 1.0.0rc1__cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.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.

Potentially problematic release.


This version of cars might be problematic. Click here for more details.

Files changed (200) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +37 -0
  3. cars/applications/application.py +117 -0
  4. cars/applications/application_constants.py +29 -0
  5. cars/applications/application_template.py +146 -0
  6. cars/applications/auxiliary_filling/__init__.py +29 -0
  7. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +104 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -0
  10. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
  11. cars/applications/dem_generation/__init__.py +30 -0
  12. cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
  13. cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +655 -0
  15. cars/applications/dem_generation/bulldozer_memory.py +55 -0
  16. cars/applications/dem_generation/dem_generation_algo.py +107 -0
  17. cars/applications/dem_generation/dem_generation_constants.py +32 -0
  18. cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
  19. cars/applications/dense_match_filling/__init__.py +30 -0
  20. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
  21. cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
  22. cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
  23. cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
  24. cars/applications/dense_match_filling/zero_padding_app.py +302 -0
  25. cars/applications/dense_matching/__init__.py +30 -0
  26. cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
  27. cars/applications/dense_matching/census_mccnn_sgm_app.py +1460 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-312-i386-linux-gnu.so +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  31. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  32. cars/applications/dense_matching/cpp/meson.build +9 -0
  33. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  34. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  35. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  36. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  37. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  38. cars/applications/dense_matching/disparity_grid_algo.py +588 -0
  39. cars/applications/dense_matching/loaders/__init__.py +23 -0
  40. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  46. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  47. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  48. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  49. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  50. cars/applications/dsm_filling/__init__.py +32 -0
  51. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  52. cars/applications/dsm_filling/border_interpolation_app.py +270 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
  56. cars/applications/grid_generation/__init__.py +30 -0
  57. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  58. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  59. cars/applications/grid_generation/grid_correction_app.py +496 -0
  60. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  61. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  62. cars/applications/grid_generation/transform_grid.py +88 -0
  63. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  64. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  65. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  66. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  67. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  68. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  69. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  70. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  71. cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
  72. cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
  73. cars/applications/rasterization/__init__.py +30 -0
  74. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  75. cars/applications/rasterization/rasterization_algo.py +534 -0
  76. cars/applications/rasterization/rasterization_constants.py +38 -0
  77. cars/applications/rasterization/rasterization_wrappers.py +634 -0
  78. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  79. cars/applications/resampling/__init__.py +28 -0
  80. cars/applications/resampling/abstract_resampling_app.py +187 -0
  81. cars/applications/resampling/bicubic_resampling_app.py +762 -0
  82. cars/applications/resampling/resampling_algo.py +614 -0
  83. cars/applications/resampling/resampling_constants.py +36 -0
  84. cars/applications/resampling/resampling_wrappers.py +309 -0
  85. cars/applications/sparse_matching/__init__.py +30 -0
  86. cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
  87. cars/applications/sparse_matching/sift_app.py +735 -0
  88. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  89. cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
  90. cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
  91. cars/applications/triangulation/__init__.py +32 -0
  92. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  93. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  94. cars/applications/triangulation/pc_transform.py +552 -0
  95. cars/applications/triangulation/triangulation_algo.py +371 -0
  96. cars/applications/triangulation/triangulation_constants.py +38 -0
  97. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  98. cars/bundleadjustment.py +757 -0
  99. cars/cars.py +177 -0
  100. cars/conf/__init__.py +23 -0
  101. cars/conf/geoid/egm96.grd +0 -0
  102. cars/conf/geoid/egm96.grd.hdr +15 -0
  103. cars/conf/input_parameters.py +156 -0
  104. cars/conf/mask_cst.py +35 -0
  105. cars/core/__init__.py +23 -0
  106. cars/core/cars_logging.py +402 -0
  107. cars/core/constants.py +191 -0
  108. cars/core/constants_disparity.py +50 -0
  109. cars/core/datasets.py +140 -0
  110. cars/core/geometry/__init__.py +27 -0
  111. cars/core/geometry/abstract_geometry.py +1119 -0
  112. cars/core/geometry/shareloc_geometry.py +598 -0
  113. cars/core/inputs.py +568 -0
  114. cars/core/outputs.py +176 -0
  115. cars/core/preprocessing.py +722 -0
  116. cars/core/projection.py +843 -0
  117. cars/core/roi_tools.py +215 -0
  118. cars/core/tiling.py +774 -0
  119. cars/core/utils.py +164 -0
  120. cars/data_structures/__init__.py +23 -0
  121. cars/data_structures/cars_dataset.py +1541 -0
  122. cars/data_structures/cars_dict.py +74 -0
  123. cars/data_structures/corresponding_tiles_tools.py +186 -0
  124. cars/data_structures/dataframe_converter.py +185 -0
  125. cars/data_structures/format_transformation.py +297 -0
  126. cars/devibrate.py +689 -0
  127. cars/extractroi.py +264 -0
  128. cars/orchestrator/__init__.py +23 -0
  129. cars/orchestrator/achievement_tracker.py +125 -0
  130. cars/orchestrator/cluster/__init__.py +37 -0
  131. cars/orchestrator/cluster/abstract_cluster.py +244 -0
  132. cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
  133. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  134. cars/orchestrator/cluster/dask_config/README.md +94 -0
  135. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  136. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  137. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  138. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  139. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  140. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  141. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  142. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  143. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  144. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  145. cars/orchestrator/cluster/log_wrapper.py +1075 -0
  146. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  147. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  148. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  149. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  150. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  151. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
  152. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  153. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  154. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  155. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  156. cars/orchestrator/orchestrator.py +905 -0
  157. cars/orchestrator/orchestrator_constants.py +29 -0
  158. cars/orchestrator/registry/__init__.py +23 -0
  159. cars/orchestrator/registry/abstract_registry.py +143 -0
  160. cars/orchestrator/registry/compute_registry.py +106 -0
  161. cars/orchestrator/registry/id_generator.py +116 -0
  162. cars/orchestrator/registry/replacer_registry.py +213 -0
  163. cars/orchestrator/registry/saver_registry.py +363 -0
  164. cars/orchestrator/registry/unseen_registry.py +118 -0
  165. cars/orchestrator/tiles_profiler.py +279 -0
  166. cars/pipelines/__init__.py +26 -0
  167. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  168. cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
  169. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  170. cars/pipelines/default/__init__.py +26 -0
  171. cars/pipelines/default/default_pipeline.py +786 -0
  172. cars/pipelines/parameters/__init__.py +0 -0
  173. cars/pipelines/parameters/advanced_parameters.py +417 -0
  174. cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
  175. cars/pipelines/parameters/application_parameters.py +71 -0
  176. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  177. cars/pipelines/parameters/dsm_inputs.py +918 -0
  178. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  179. cars/pipelines/parameters/output_constants.py +52 -0
  180. cars/pipelines/parameters/output_parameters.py +454 -0
  181. cars/pipelines/parameters/sensor_inputs.py +842 -0
  182. cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
  183. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  184. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  185. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  186. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  187. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  188. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  189. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  190. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  191. cars/pipelines/pipeline.py +119 -0
  192. cars/pipelines/pipeline_constants.py +31 -0
  193. cars/pipelines/pipeline_template.py +139 -0
  194. cars/pipelines/unit/__init__.py +26 -0
  195. cars/pipelines/unit/unit_pipeline.py +2850 -0
  196. cars/starter.py +167 -0
  197. cars-1.0.0rc1.dist-info/METADATA +292 -0
  198. cars-1.0.0rc1.dist-info/RECORD +200 -0
  199. cars-1.0.0rc1.dist-info/WHEEL +6 -0
  200. cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,392 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ """
22
+ This module contains functions used in outlier removal
23
+ """
24
+
25
+ # Standard imports
26
+ from typing import List, Tuple, Union
27
+
28
+ # Third party imports
29
+ import numpy as np
30
+ import outlier_filter # pylint:disable=E0401
31
+ import pandas
32
+ from scipy.spatial import cKDTree # pylint: disable=no-name-in-module
33
+
34
+ from cars.applications.triangulation import pc_transform
35
+
36
+ # CARS imports
37
+ from cars.core import constants as cst
38
+ from cars.core import projection
39
+
40
+ # ##### Small component filtering ######
41
+
42
+
43
+ def small_component_filtering(
44
+ cloud: pandas.DataFrame,
45
+ connection_val: float,
46
+ nb_pts_threshold: int,
47
+ clusters_distance_threshold: float = None,
48
+ filtered_elt_pos: bool = False,
49
+ ) -> Tuple[pandas.DataFrame, Union[None, pandas.DataFrame]]:
50
+ """
51
+ Filter point cloud to remove small clusters of points
52
+ (see the detect_small_components function).
53
+
54
+ :param cloud: combined cloud
55
+ as returned by the create_combined_cloud function
56
+ :param connection_val: distance to use
57
+ to consider that two points are connected
58
+ :param nb_pts_threshold: number of points to use
59
+ to identify small clusters to filter
60
+ :param clusters_distance_threshold: distance to use
61
+ to consider if two points clusters are far from each other or not
62
+ (set to None to deactivate this level of filtering)
63
+ :param filtered_elt_pos: if filtered_elt_pos is set to True,
64
+ the removed points positions in their original
65
+ epipolar images are returned, otherwise it is set to None
66
+ :return: Tuple made of the filtered cloud and
67
+ the removed elements positions in their epipolar images
68
+ """
69
+
70
+ clusters_distance_threshold_float = (
71
+ np.nan
72
+ if clusters_distance_threshold is None
73
+ else clusters_distance_threshold
74
+ )
75
+
76
+ index_elt_to_remove = outlier_filter.pc_small_component_outlier_filtering(
77
+ cloud.loc[:, cst.X].values,
78
+ cloud.loc[:, cst.Y].values,
79
+ cloud.loc[:, cst.Z].values,
80
+ radius=connection_val,
81
+ min_cluster_size=nb_pts_threshold,
82
+ clusters_distance_threshold=clusters_distance_threshold_float,
83
+ )
84
+
85
+ return pc_transform.filter_cloud(
86
+ cloud, index_elt_to_remove, filtered_elt_pos
87
+ )
88
+
89
+
90
+ def detect_small_components(
91
+ cloud_xyz: np.ndarray,
92
+ connection_val: float,
93
+ nb_pts_threshold: int,
94
+ clusters_distance_threshold: float = None,
95
+ ) -> List[int]:
96
+ """
97
+ Determine the indexes of the points of cloud_xyz to filter.
98
+ The clusters are made of 'connected' points
99
+ (2 connected points have a distance smaller than connection_val)
100
+
101
+ The removed clusters are composed of less than nb_pts_threshold points and
102
+ are also far from other clusters
103
+ (points are further than clusters_distance_threshold).
104
+
105
+ If clusters_distance_threshold is set to None, all the clusters that are
106
+ composed of less than nb_pts_threshold points are filtered.
107
+
108
+ :param cloud_xyz: points kdTree
109
+ :param connection_val: distance to use
110
+ to consider that two points are connected
111
+ :param nb_pts_threshold: number of points to use
112
+ to identify small clusters to filter
113
+ :param clusters_distance_threshold: distance to use
114
+ to consider if two points clusters are far from each other or not
115
+ (set to None to deactivate this level of filtering)
116
+ :return: list of the points to filter indexes
117
+ """
118
+ cloud_tree = cKDTree(cloud_xyz)
119
+
120
+ # extract connected components
121
+ processed = [False] * len(cloud_xyz)
122
+ connected_components = []
123
+ for idx, xyz_point in enumerate(cloud_xyz):
124
+ # if point has already been added to a cluster
125
+ if processed[idx]:
126
+ continue
127
+
128
+ # get point neighbors
129
+ neighbors_list = cloud_tree.query_ball_point(xyz_point, connection_val)
130
+
131
+ # add them to the current cluster
132
+ seed = []
133
+ seed.extend(neighbors_list)
134
+ for neigh_idx in neighbors_list:
135
+ processed[neigh_idx] = True
136
+
137
+ # iteratively add all the neighbors of the points
138
+ # which were added to the current cluster (if there are some)
139
+ while len(neighbors_list) != 0:
140
+ all_neighbors = cloud_tree.query_ball_point(
141
+ cloud_xyz[neighbors_list], connection_val
142
+ )
143
+
144
+ # flatten neighbors
145
+ new_neighbors = []
146
+ for neighbor_item in all_neighbors:
147
+ new_neighbors.extend(neighbor_item)
148
+
149
+ # retrieve only new neighbors
150
+ neighbors_list = list(set(new_neighbors) - set(seed))
151
+
152
+ # add them to the current cluster
153
+ seed.extend(neighbors_list)
154
+ for neigh_idx in neighbors_list:
155
+ processed[neigh_idx] = True
156
+
157
+ connected_components.append(seed)
158
+
159
+ # determine clusters to remove
160
+ cluster_to_remove = []
161
+ for _, connected_components_item in enumerate(connected_components):
162
+ if len(connected_components_item) < nb_pts_threshold:
163
+ if clusters_distance_threshold is not None:
164
+ # search if the current cluster has any neighbors
165
+ # in the clusters_distance_threshold radius
166
+ all_neighbors = cloud_tree.query_ball_point(
167
+ cloud_xyz[connected_components_item],
168
+ clusters_distance_threshold,
169
+ )
170
+
171
+ # flatten neighbors
172
+ new_neighbors = []
173
+ for neighbor_item in all_neighbors:
174
+ new_neighbors.extend(neighbor_item)
175
+
176
+ # retrieve only new neighbors
177
+ neighbors_list = list(
178
+ set(new_neighbors) - set(connected_components_item)
179
+ )
180
+
181
+ # if there are no new neighbors, the cluster will be removed
182
+ if len(neighbors_list) == 0:
183
+ cluster_to_remove.extend(connected_components_item)
184
+ else:
185
+ cluster_to_remove.extend(connected_components_item)
186
+
187
+ return cluster_to_remove
188
+
189
+
190
+ # ##### statistical filtering ######
191
+
192
+
193
+ # pylint: disable=too-many-positional-arguments
194
+ def statistical_outlier_filtering(
195
+ cloud: pandas.DataFrame,
196
+ k: int,
197
+ filtering_constant: float,
198
+ mean_factor: float,
199
+ dev_factor: float,
200
+ use_median: bool = False,
201
+ filtered_elt_pos: bool = False,
202
+ ) -> Tuple[pandas.DataFrame, Union[None, pandas.DataFrame]]:
203
+ """
204
+ Filter point cloud to remove statistical outliers
205
+ (see the detect_statistical_outliers function).
206
+
207
+ :param cloud: combined cloud
208
+ as returned by the create_combined_cloud function
209
+ :param k: number of neighbors
210
+ :param filtering_constant: constant added to the distance threshold
211
+ :param mean_factor: multiplication factor of mean used
212
+ to compute the distance threshold
213
+ :param dev_factor: multiplication factor of deviation used
214
+ to compute the distance threshold
215
+ :param use_median: choice of statistical measure used to filter
216
+ :param filtered_elt_pos: if filtered_elt_pos is set to True,
217
+ the removed points positions in their original
218
+ epipolar images are returned, otherwise it is set to None
219
+ :return: Tuple made of the filtered cloud and
220
+ the removed elements positions in their epipolar images
221
+ """
222
+
223
+ index_elt_to_remove = outlier_filter.pc_statistical_outlier_filtering(
224
+ cloud.loc[:, cst.X].values,
225
+ cloud.loc[:, cst.Y].values,
226
+ cloud.loc[:, cst.Z].values,
227
+ filtering_constant=filtering_constant,
228
+ mean_factor=mean_factor,
229
+ dev_factor=dev_factor,
230
+ k=k,
231
+ use_median=use_median,
232
+ )
233
+
234
+ return pc_transform.filter_cloud(
235
+ cloud, index_elt_to_remove, filtered_elt_pos
236
+ )
237
+
238
+
239
+ def detect_statistical_outliers(
240
+ cloud_xyz: np.ndarray, k: int, dev_factor: float, use_median: bool
241
+ ) -> List[int]:
242
+ """
243
+ Determine the indexes of the points of cloud_xyz to filter.
244
+ The removed points have mean distances with their k nearest neighbors
245
+ that are greater than a distance threshold (dist_thresh).
246
+
247
+ This threshold is computed from the mean (or median) and
248
+ standard deviation (or interquartile range) of all the points mean
249
+ distances with their k nearest neighbors:
250
+
251
+ (1) dist_thresh = mean_distances + dev_factor * std_distances
252
+ or
253
+ (2) dist_thresh = median_distances + dev_factor * iqr_distances
254
+
255
+ :param cloud_xyz: points kdTree
256
+ :param k: number of neighbors
257
+ :param dev_factor: multiplication factor of deviation used
258
+ to compute the distance threshold
259
+ :param use_median: if True formula (2) is used for threshold, else
260
+ formula (1)
261
+ :return: list of the points to filter indexes
262
+ """
263
+ # compute for each points, all the distances to their k neighbors
264
+ cloud_tree = cKDTree(cloud_xyz)
265
+ neighbors_distances, _ = cloud_tree.query(cloud_xyz, k + 1)
266
+
267
+ # Compute the mean of those distances for each point
268
+ # Mean is not used directly as each line
269
+ # contained the distance value to the point itself
270
+ mean_neighbors_distances = np.sum(neighbors_distances, axis=1)
271
+ mean_neighbors_distances /= k
272
+
273
+ if use_median:
274
+ # compute median and interquartile range of those mean distances
275
+ # for the whole point cloud
276
+ median_distances = np.median(mean_neighbors_distances)
277
+ iqr_distances = np.percentile(
278
+ mean_neighbors_distances, 75
279
+ ) - np.percentile(mean_neighbors_distances, 25)
280
+
281
+ # compute distance threshold and
282
+ # apply it to determine which points will be removed
283
+ dist_thresh = median_distances + dev_factor * iqr_distances
284
+ else:
285
+ # compute median and interquartile range of those mean distances
286
+ # for the whole point cloud
287
+ mean_distances = np.mean(mean_neighbors_distances)
288
+ std_distances = np.std(mean_neighbors_distances)
289
+ # compute distance threshold and
290
+ # apply it to determine which points will be removed
291
+ dist_thresh = mean_distances + dev_factor * std_distances
292
+
293
+ points_to_remove = np.argwhere(mean_neighbors_distances > dist_thresh)
294
+
295
+ # flatten points_to_remove
296
+ detected_points = []
297
+ for removed_point in points_to_remove:
298
+ detected_points.extend(removed_point)
299
+
300
+ return detected_points
301
+
302
+
303
+ def epipolar_small_components(
304
+ cloud,
305
+ min_cluster_size=15,
306
+ radius=1.0,
307
+ half_window_size=5,
308
+ clusters_distance_threshold=np.nan,
309
+ ):
310
+ """
311
+ Filter outliers using the small components method in epipolar geometry
312
+
313
+ :param epipolar_ds: epipolar dataset to filter
314
+ :type epipolar_ds: xr.Dataset
315
+ :param statistical_k: k
316
+ :type statistical_k: int
317
+ :param std_dev_factor: std factor
318
+ :type std_dev_factor: float
319
+ :param half_window_size: use median and quartile instead of mean and std
320
+ :type half_window_size: int
321
+ :param use_median: use median and quartile instead of mean and std
322
+ :type use_median: bool
323
+
324
+ :return: filtered dataset
325
+ :rtype: xr.Dataset
326
+
327
+ """
328
+
329
+ if clusters_distance_threshold is None:
330
+ clusters_distance_threshold = np.nan
331
+
332
+ outlier_filter.epipolar_small_component_outlier_filtering(
333
+ cloud[cst.X],
334
+ cloud[cst.Y],
335
+ cloud[cst.Z],
336
+ min_cluster_size,
337
+ radius,
338
+ half_window_size,
339
+ clusters_distance_threshold,
340
+ )
341
+
342
+ projection.point_cloud_conversion_dataset(cloud, 4326)
343
+
344
+ return cloud
345
+
346
+
347
+ # pylint: disable=too-many-positional-arguments
348
+ def epipolar_statistical_filtering(
349
+ epipolar_ds,
350
+ k=15,
351
+ filtering_constant=0.0,
352
+ mean_factor=1.0,
353
+ dev_factor=1.0,
354
+ half_window_size=5,
355
+ use_median=False,
356
+ ):
357
+ """
358
+ Filter outliers using the statistical method in epipolar geometry
359
+
360
+ :param epipolar_ds: epipolar dataset to filter
361
+ :type epipolar_ds: xr.Dataset
362
+ :param statistical_k: k
363
+ :type statistical_k: int
364
+ :param std_dev_factor: std factor
365
+ :type std_dev_factor: float
366
+ :param half_window_size: use median and quartile instead of mean and std
367
+ :type half_window_size: int
368
+ :param use_median: use median and quartile instead of mean and std
369
+ :type use_median: bool
370
+
371
+ :return: filtered dataset
372
+ :rtype: xr.Dataset
373
+
374
+ """
375
+
376
+ if not np.all(np.isnan(epipolar_ds[cst.Z])):
377
+
378
+ outlier_filter.epipolar_statistical_outlier_filtering(
379
+ epipolar_ds[cst.X],
380
+ epipolar_ds[cst.Y],
381
+ epipolar_ds[cst.Z],
382
+ k,
383
+ half_window_size,
384
+ filtering_constant,
385
+ mean_factor,
386
+ dev_factor,
387
+ use_median,
388
+ )
389
+
390
+ projection.point_cloud_conversion_dataset(epipolar_ds, 4326)
391
+
392
+ return epipolar_ds
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ """
22
+ file contains all the constants used in cloud fusion module
23
+ """
24
+
25
+
26
+ CLOUD_OUTLIER_REMOVAL_RUN_TAG = "outlier_removal"
27
+
28
+ # Params
29
+ METHOD = "method"
30
+
31
+
32
+ # small components
33
+ SMALL_COMPONENT_FILTER = "small_components_filter_activated"
34
+ SC_ON_GROUND_MARGIN = "on_ground_margin"
35
+ SC_CONNECTION_DISTANCE = "connection_distance"
36
+ SC_NB_POINTS_THRESHOLD = "nb_points_threshold"
37
+ SC_CLUSTERS_DISTANCES_THRESHOLD = "clusters_distance_threshold"
38
+
39
+
40
+ # statistical outlier
41
+ STATISTICAL_OUTLIER = "statistical_outliers_filter_activated"
42
+ SO_K = "k"
43
+ SO_STD_DEV_FACTOR = "std_dev_factor"