cars 1.0.0rc2__cp312-cp312-win_amd64.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.
- cars/__init__.py +86 -0
- cars/applications/__init__.py +40 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +597 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +278 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
- cars/applications/dsm_merging/__init__.py +28 -0
- cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
- cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
- cars/applications/grid_correction/__init__.py +30 -0
- cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
- cars/applications/grid_correction/grid_correction_app.py +557 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +639 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +760 -0
- cars/applications/resampling/resampling_algo.py +590 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sensors_subsampling/__init__.py +32 -0
- cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
- cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
- cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
- cars/applications/sparse_matching/sift_app.py +724 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +750 -0
- cars/cars.py +179 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +1119 -0
- cars/core/geometry/shareloc_geometry.py +598 -0
- cars/core/inputs.py +568 -0
- cars/core/outputs.py +176 -0
- cars/core/preprocessing.py +722 -0
- cars/core/projection.py +843 -0
- cars/core/roi_tools.py +215 -0
- cars/core/tiling.py +774 -0
- cars/core/utils.py +164 -0
- cars/data_structures/__init__.py +23 -0
- cars/data_structures/cars_dataset.py +1544 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +250 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +728 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/memory_tools.py +47 -0
- cars/orchestrator/orchestrator.py +755 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +1088 -0
- cars/pipelines/filling/__init__.py +26 -0
- cars/pipelines/filling/filling.py +981 -0
- cars/pipelines/formatting/__init__.py +26 -0
- cars/pipelines/formatting/formatting.py +186 -0
- cars/pipelines/merging/__init__.py +26 -0
- cars/pipelines/merging/merging.py +439 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +256 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
- cars/pipelines/parameters/application_parameters.py +72 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +349 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +438 -0
- cars/pipelines/parameters/sensor_inputs.py +859 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +38 -0
- cars/pipelines/pipeline_template.py +135 -0
- cars/pipelines/subsampling/__init__.py +26 -0
- cars/pipelines/subsampling/subsampling.py +358 -0
- cars/pipelines/surface_modeling/__init__.py +26 -0
- cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
- cars/pipelines/tie_points/__init__.py +26 -0
- cars/pipelines/tie_points/tie_points.py +536 -0
- cars/starter.py +167 -0
- cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
- cars-1.0.0rc2.dist-info/METADATA +289 -0
- cars-1.0.0rc2.dist-info/RECORD +225 -0
- cars-1.0.0rc2.dist-info/WHEEL +4 -0
- cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
- cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
- cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
- cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -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"
|