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.
- cars/__init__.py +74 -0
- cars/applications/__init__.py +37 -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 +104 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -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 +655 -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 +1460 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-312-i386-linux-gnu.so +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 +588 -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 +270 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +333 -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_correction_app.py +496 -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 +527 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -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 +634 -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 +762 -0
- cars/applications/resampling/resampling_algo.py +614 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
- cars/applications/sparse_matching/sift_app.py +735 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -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 +757 -0
- cars/cars.py +177 -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 +1541 -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 +244 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +375 -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 +1075 -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 +873 -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/orchestrator.py +905 -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 +2 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +786 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +417 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
- cars/pipelines/parameters/application_parameters.py +71 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +918 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +454 -0
- cars/pipelines/parameters/sensor_inputs.py +842 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +49 -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 +31 -0
- cars/pipelines/pipeline_template.py +139 -0
- cars/pipelines/unit/__init__.py +26 -0
- cars/pipelines/unit/unit_pipeline.py +2850 -0
- cars/starter.py +167 -0
- cars-1.0.0rc1.dist-info/METADATA +292 -0
- cars-1.0.0rc1.dist-info/RECORD +200 -0
- cars-1.0.0rc1.dist-info/WHEEL +6 -0
- cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
|
@@ -0,0 +1,527 @@
|
|
|
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 the small_components point removal application class.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
import copy
|
|
27
|
+
|
|
28
|
+
# Standard imports
|
|
29
|
+
import logging
|
|
30
|
+
import os
|
|
31
|
+
|
|
32
|
+
# Third party imports
|
|
33
|
+
import numpy as np
|
|
34
|
+
from json_checker import And, Checker, Or
|
|
35
|
+
from pyproj import CRS
|
|
36
|
+
|
|
37
|
+
# CARS imports
|
|
38
|
+
import cars.orchestrator.orchestrator as ocht
|
|
39
|
+
from cars.applications import application_constants
|
|
40
|
+
from cars.applications.point_cloud_outlier_removal import (
|
|
41
|
+
abstract_outlier_removal_app as pc_removal,
|
|
42
|
+
)
|
|
43
|
+
from cars.applications.point_cloud_outlier_removal import (
|
|
44
|
+
outlier_removal_algo,
|
|
45
|
+
)
|
|
46
|
+
from cars.applications.triangulation import pc_transform
|
|
47
|
+
from cars.applications.triangulation.triangulation_wrappers import (
|
|
48
|
+
generate_point_cloud_file_names,
|
|
49
|
+
)
|
|
50
|
+
from cars.core import constants as cst
|
|
51
|
+
from cars.core import projection
|
|
52
|
+
from cars.data_structures import cars_dataset
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class SmallComponents(
|
|
56
|
+
pc_removal.PointCloudOutlierRemoval, short_name="small_components"
|
|
57
|
+
): # pylint: disable=R0903
|
|
58
|
+
"""
|
|
59
|
+
SmallComponents
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
# pylint: disable=too-many-instance-attributes
|
|
63
|
+
|
|
64
|
+
def __init__(self, scaling_coeff, conf=None):
|
|
65
|
+
"""
|
|
66
|
+
Init function of SmallComponents
|
|
67
|
+
|
|
68
|
+
:param scaling_coeff: scaling factor for resolution
|
|
69
|
+
:type scaling_coeff: float
|
|
70
|
+
:param conf: configuration for points outlier removal
|
|
71
|
+
:return: an application_to_use object
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
super().__init__(scaling_coeff, conf=conf)
|
|
75
|
+
|
|
76
|
+
self.used_method = self.used_config["method"]
|
|
77
|
+
|
|
78
|
+
# small components
|
|
79
|
+
self.on_ground_margin = self.used_config["on_ground_margin"]
|
|
80
|
+
self.connection_distance = self.used_config["connection_distance"]
|
|
81
|
+
self.nb_points_threshold = self.used_config["nb_points_threshold"]
|
|
82
|
+
self.clusters_distance_threshold = self.used_config[
|
|
83
|
+
"clusters_distance_threshold"
|
|
84
|
+
]
|
|
85
|
+
self.half_epipolar_size = self.used_config["half_epipolar_size"]
|
|
86
|
+
|
|
87
|
+
# Saving files
|
|
88
|
+
self.save_by_pair = self.used_config.get("save_by_pair", False)
|
|
89
|
+
|
|
90
|
+
# Init orchestrator
|
|
91
|
+
self.orchestrator = None
|
|
92
|
+
|
|
93
|
+
def check_conf(self, conf):
|
|
94
|
+
"""
|
|
95
|
+
Check configuration
|
|
96
|
+
|
|
97
|
+
:param conf: configuration to check
|
|
98
|
+
:type conf: dict
|
|
99
|
+
|
|
100
|
+
:return: overloaded configuration
|
|
101
|
+
:rtype: dict
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
# init conf
|
|
106
|
+
if conf is not None:
|
|
107
|
+
overloaded_conf = conf.copy()
|
|
108
|
+
else:
|
|
109
|
+
conf = {}
|
|
110
|
+
overloaded_conf = {}
|
|
111
|
+
|
|
112
|
+
# Overload conf
|
|
113
|
+
overloaded_conf["method"] = conf.get("method", "small_components")
|
|
114
|
+
overloaded_conf[application_constants.SAVE_INTERMEDIATE_DATA] = (
|
|
115
|
+
conf.get(application_constants.SAVE_INTERMEDIATE_DATA, False)
|
|
116
|
+
)
|
|
117
|
+
overloaded_conf["save_by_pair"] = conf.get("save_by_pair", False)
|
|
118
|
+
|
|
119
|
+
# small components
|
|
120
|
+
# on_ground_margin:
|
|
121
|
+
# margin added to the on ground region to not filter
|
|
122
|
+
# points clusters
|
|
123
|
+
# that were incomplete because they were on the edges
|
|
124
|
+
overloaded_conf["on_ground_margin"] = conf.get("on_ground_margin", 11)
|
|
125
|
+
# pts_connection_dist:
|
|
126
|
+
# distance to use to consider that two points are connected
|
|
127
|
+
overloaded_conf["connection_distance"] = conf.get(
|
|
128
|
+
"connection_distance", self.scaling_coeff * 3.0
|
|
129
|
+
)
|
|
130
|
+
# nb_pts_threshold:
|
|
131
|
+
# points clusters that have less than this number of points
|
|
132
|
+
# will be filtered
|
|
133
|
+
overloaded_conf["nb_points_threshold"] = conf.get(
|
|
134
|
+
"nb_points_threshold", 50
|
|
135
|
+
)
|
|
136
|
+
# dist_between_clusters:
|
|
137
|
+
# distance to use to consider that two points clusters
|
|
138
|
+
# are far from each other or not.
|
|
139
|
+
# If a small points cluster is near to another one, it won't
|
|
140
|
+
# be filtered.
|
|
141
|
+
# (None = deactivated)
|
|
142
|
+
overloaded_conf["clusters_distance_threshold"] = conf.get(
|
|
143
|
+
"clusters_distance_threshold", None
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# half_epipolar_size:
|
|
147
|
+
# Half size of the epipolar window used for neighobr search (depth map
|
|
148
|
+
# input only)
|
|
149
|
+
overloaded_conf["half_epipolar_size"] = conf.get(
|
|
150
|
+
"half_epipolar_size", 5
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
point_cloud_fusion_schema = {
|
|
154
|
+
"method": str,
|
|
155
|
+
"save_by_pair": bool,
|
|
156
|
+
"on_ground_margin": int,
|
|
157
|
+
"connection_distance": And(float, lambda x: x > 0),
|
|
158
|
+
"nb_points_threshold": And(int, lambda x: x > 0),
|
|
159
|
+
"clusters_distance_threshold": Or(None, float),
|
|
160
|
+
"half_epipolar_size": int,
|
|
161
|
+
application_constants.SAVE_INTERMEDIATE_DATA: bool,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# Check conf
|
|
165
|
+
checker = Checker(point_cloud_fusion_schema)
|
|
166
|
+
checker.validate(overloaded_conf)
|
|
167
|
+
|
|
168
|
+
return overloaded_conf
|
|
169
|
+
|
|
170
|
+
def get_optimal_tile_size(
|
|
171
|
+
self,
|
|
172
|
+
max_ram_per_worker,
|
|
173
|
+
superposing_point_clouds=1,
|
|
174
|
+
point_cloud_resolution=0.5,
|
|
175
|
+
):
|
|
176
|
+
"""
|
|
177
|
+
Get the optimal tile size to use, depending on memory available
|
|
178
|
+
|
|
179
|
+
:param max_ram_per_worker: maximum ram available
|
|
180
|
+
:type max_ram_per_worker: int
|
|
181
|
+
:param superposing_point_clouds: number of point clouds superposing
|
|
182
|
+
:type superposing_point_clouds: int
|
|
183
|
+
:param point_cloud_resolution: resolution of point cloud
|
|
184
|
+
:type point_cloud_resolution: float
|
|
185
|
+
|
|
186
|
+
:return: optimal tile size in meter
|
|
187
|
+
:rtype: float
|
|
188
|
+
|
|
189
|
+
"""
|
|
190
|
+
tot = 10000 * superposing_point_clouds / point_cloud_resolution
|
|
191
|
+
|
|
192
|
+
import_ = 200 # MiB
|
|
193
|
+
tile_size = int(
|
|
194
|
+
np.sqrt(float(((max_ram_per_worker - import_) * 2**23)) / tot)
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
logging.info(
|
|
198
|
+
"Estimated optimal tile size for small"
|
|
199
|
+
"component removal: {} meters".format(tile_size)
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
return tile_size
|
|
203
|
+
|
|
204
|
+
def get_method(self):
|
|
205
|
+
"""
|
|
206
|
+
Get margins to use during point clouds fusion
|
|
207
|
+
|
|
208
|
+
:return: algorithm method
|
|
209
|
+
:rtype: string
|
|
210
|
+
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
return self.used_method
|
|
214
|
+
|
|
215
|
+
def get_epipolar_margin(self):
|
|
216
|
+
"""
|
|
217
|
+
Get epipolar margin to use
|
|
218
|
+
|
|
219
|
+
:return: margin
|
|
220
|
+
:rtype: int
|
|
221
|
+
"""
|
|
222
|
+
margin = self.half_epipolar_size
|
|
223
|
+
|
|
224
|
+
return margin
|
|
225
|
+
|
|
226
|
+
def get_on_ground_margin(self, resolution=0.5):
|
|
227
|
+
"""
|
|
228
|
+
Get margins to use during point clouds fusion
|
|
229
|
+
|
|
230
|
+
:return: margin
|
|
231
|
+
:rtype: float
|
|
232
|
+
|
|
233
|
+
"""
|
|
234
|
+
on_ground_margin = self.on_ground_margin * resolution
|
|
235
|
+
|
|
236
|
+
return on_ground_margin
|
|
237
|
+
|
|
238
|
+
def run( # pylint: disable=too-many-positional-arguments
|
|
239
|
+
self,
|
|
240
|
+
merged_point_cloud,
|
|
241
|
+
orchestrator=None,
|
|
242
|
+
depth_map_dir=None,
|
|
243
|
+
point_cloud_dir=None,
|
|
244
|
+
dump_dir=None,
|
|
245
|
+
epsg=None,
|
|
246
|
+
):
|
|
247
|
+
"""
|
|
248
|
+
Run PointCloudOutlierRemoval application.
|
|
249
|
+
|
|
250
|
+
Creates a CarsDataset filled with new point cloud tiles.
|
|
251
|
+
|
|
252
|
+
:param merged_point_cloud: merged point cloud. CarsDataset contains:
|
|
253
|
+
|
|
254
|
+
- Z x W Delayed tiles. \
|
|
255
|
+
Each tile will be a future pandas DataFrame containing:
|
|
256
|
+
|
|
257
|
+
- data : with keys : "x", "y", "z", "corr_msk"\
|
|
258
|
+
optional: "clr", "msk", "data_valid","coord_epi_geom_i",\
|
|
259
|
+
"coord_epi_geom_j","idx_im_epi" \
|
|
260
|
+
- attrs with keys: "epsg"
|
|
261
|
+
- attributes containing "bounds", "ysize", "xsize", "epsg"
|
|
262
|
+
|
|
263
|
+
:type merged_point_cloud: CarsDataset filled with pandas.DataFrame
|
|
264
|
+
:param orchestrator: orchestrator used
|
|
265
|
+
:param depth_map_dir: output depth map directory. If None output will
|
|
266
|
+
be written in dump_dir if intermediate data is requested
|
|
267
|
+
:type depth_map_dir: str
|
|
268
|
+
:param point_cloud_dir: output depth map directory. If None output will
|
|
269
|
+
be written in dump_dir if intermediate data is requested
|
|
270
|
+
:type point_cloud_dir: str
|
|
271
|
+
:type output_dir: str
|
|
272
|
+
:param dump_dir: dump dir for output (except depth map) if intermediate
|
|
273
|
+
data is requested
|
|
274
|
+
:type dump_dir: str
|
|
275
|
+
:param epsg: cartographic reference for the point cloud (array input)
|
|
276
|
+
:type epsg: int
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
:return: filtered merged point cloud. CarsDataset contains:
|
|
280
|
+
|
|
281
|
+
- Z x W Delayed tiles.\
|
|
282
|
+
Each tile will be a future pandas DataFrame containing:
|
|
283
|
+
|
|
284
|
+
- data : with keys : "x", "y", "z", "corr_msk"\
|
|
285
|
+
optional: "clr", "msk", "data_valid","coord_epi_geom_i",\
|
|
286
|
+
"coord_epi_geom_j","idx_im_epi"
|
|
287
|
+
- attrs with keys: "epsg"
|
|
288
|
+
- attributes containing "bounds", "ysize", "xsize", "epsg"
|
|
289
|
+
|
|
290
|
+
:rtype: CarsDataset filled with xr.Dataset
|
|
291
|
+
"""
|
|
292
|
+
# Default orchestrator
|
|
293
|
+
if orchestrator is None:
|
|
294
|
+
# Create default sequential orchestrator for current application
|
|
295
|
+
# be awere, no out_json will be shared between orchestrators
|
|
296
|
+
# No files saved
|
|
297
|
+
self.orchestrator = ocht.Orchestrator(
|
|
298
|
+
orchestrator_conf={"mode": "sequential"}
|
|
299
|
+
)
|
|
300
|
+
else:
|
|
301
|
+
self.orchestrator = orchestrator
|
|
302
|
+
|
|
303
|
+
if dump_dir is None:
|
|
304
|
+
dump_dir = self.generate_unknown_dump_dir(self.orchestrator)
|
|
305
|
+
|
|
306
|
+
if merged_point_cloud.dataset_type != "arrays":
|
|
307
|
+
raise RuntimeError(
|
|
308
|
+
"Only arrays is supported in small components removal"
|
|
309
|
+
)
|
|
310
|
+
prefix = os.path.basename(dump_dir)
|
|
311
|
+
# Save as depth map
|
|
312
|
+
filtered_point_cloud, saving_info_epipolar = (
|
|
313
|
+
self.__register_epipolar_dataset__(
|
|
314
|
+
merged_point_cloud,
|
|
315
|
+
depth_map_dir,
|
|
316
|
+
dump_dir,
|
|
317
|
+
app_name="small_components",
|
|
318
|
+
pair_key=prefix,
|
|
319
|
+
)
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# Save as point cloud
|
|
323
|
+
(
|
|
324
|
+
flatten_filtered_point_cloud,
|
|
325
|
+
laz_pc_dir_name,
|
|
326
|
+
csv_pc_dir_name,
|
|
327
|
+
saving_info_flatten,
|
|
328
|
+
) = self.__register_pc_dataset__(
|
|
329
|
+
merged_point_cloud,
|
|
330
|
+
point_cloud_dir,
|
|
331
|
+
dump_dir,
|
|
332
|
+
app_name="small_components",
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# initialize empty index file for point cloud product if official
|
|
336
|
+
# product is requested
|
|
337
|
+
pc_index = None
|
|
338
|
+
if point_cloud_dir:
|
|
339
|
+
pc_index = {}
|
|
340
|
+
|
|
341
|
+
# Generate rasters
|
|
342
|
+
for col in range(filtered_point_cloud.shape[1]):
|
|
343
|
+
for row in range(filtered_point_cloud.shape[0]):
|
|
344
|
+
|
|
345
|
+
# update saving infos for potential replacement
|
|
346
|
+
full_saving_info_epipolar = ocht.update_saving_infos(
|
|
347
|
+
saving_info_epipolar, row=row, col=col
|
|
348
|
+
)
|
|
349
|
+
full_saving_info_flatten = None
|
|
350
|
+
if saving_info_flatten is not None:
|
|
351
|
+
full_saving_info_flatten = ocht.update_saving_infos(
|
|
352
|
+
saving_info_flatten, row=row, col=col
|
|
353
|
+
)
|
|
354
|
+
if merged_point_cloud[row][col] is not None:
|
|
355
|
+
csv_pc_file_name, laz_pc_file_name = (
|
|
356
|
+
generate_point_cloud_file_names(
|
|
357
|
+
csv_pc_dir_name,
|
|
358
|
+
laz_pc_dir_name,
|
|
359
|
+
row,
|
|
360
|
+
col,
|
|
361
|
+
pc_index,
|
|
362
|
+
pair_key=prefix,
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
window = merged_point_cloud.tiling_grid[row, col]
|
|
366
|
+
overlap = filtered_point_cloud.overlaps[row, col]
|
|
367
|
+
# Delayed call to cloud filtering
|
|
368
|
+
(
|
|
369
|
+
filtered_point_cloud[row, col],
|
|
370
|
+
flatten_filtered_point_cloud[row, col],
|
|
371
|
+
) = self.orchestrator.cluster.create_task(
|
|
372
|
+
epipolar_small_component_removal_wrapper, nout=2
|
|
373
|
+
)(
|
|
374
|
+
merged_point_cloud[row, col],
|
|
375
|
+
self.connection_distance,
|
|
376
|
+
self.nb_points_threshold,
|
|
377
|
+
self.clusters_distance_threshold,
|
|
378
|
+
self.half_epipolar_size,
|
|
379
|
+
window,
|
|
380
|
+
overlap,
|
|
381
|
+
epsg=epsg,
|
|
382
|
+
point_cloud_csv_file_name=csv_pc_file_name,
|
|
383
|
+
point_cloud_laz_file_name=laz_pc_file_name,
|
|
384
|
+
saving_info_epipolar=full_saving_info_epipolar,
|
|
385
|
+
saving_info_flatten=full_saving_info_flatten,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# update point cloud index
|
|
389
|
+
if point_cloud_dir:
|
|
390
|
+
self.orchestrator.update_index(pc_index)
|
|
391
|
+
|
|
392
|
+
return filtered_point_cloud
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# pylint: disable=too-many-positional-arguments
|
|
396
|
+
def epipolar_small_component_removal_wrapper(
|
|
397
|
+
cloud,
|
|
398
|
+
connection_distance,
|
|
399
|
+
nb_points_threshold,
|
|
400
|
+
clusters_distance_threshold,
|
|
401
|
+
half_epipolar_size,
|
|
402
|
+
window,
|
|
403
|
+
overlap,
|
|
404
|
+
epsg=None,
|
|
405
|
+
point_cloud_csv_file_name=None,
|
|
406
|
+
point_cloud_laz_file_name=None,
|
|
407
|
+
saving_info_epipolar=None,
|
|
408
|
+
saving_info_flatten=None,
|
|
409
|
+
):
|
|
410
|
+
"""
|
|
411
|
+
Small component outlier removal in epipolar geometry
|
|
412
|
+
|
|
413
|
+
:param epipolar_ds: epipolar dataset to filter
|
|
414
|
+
:type epipolar_ds: xr.Dataset
|
|
415
|
+
:param connection_distance: minimum distance of two connected points
|
|
416
|
+
:type connection_distance: float
|
|
417
|
+
:param nb_points_threshold: minimum valid cluster size
|
|
418
|
+
:type nb_points_threshold: int
|
|
419
|
+
:param clusters_distance_threshold: max distance between an outlier cluster
|
|
420
|
+
and other points
|
|
421
|
+
:type clusters_distance_threshold: float
|
|
422
|
+
:param half_epipolar_size: half size of the window used to search neighbors
|
|
423
|
+
:type half_epipolar_size: int
|
|
424
|
+
:param window: window of base tile [row min, row max, col min col max]
|
|
425
|
+
:type window: list
|
|
426
|
+
:param overlap: overlap [row min, row max, col min col max]
|
|
427
|
+
:type overlap: list
|
|
428
|
+
|
|
429
|
+
:return: filtered dataset
|
|
430
|
+
:rtype: xr.Dataset
|
|
431
|
+
|
|
432
|
+
"""
|
|
433
|
+
|
|
434
|
+
# Copy input cloud
|
|
435
|
+
filtered_cloud = copy.copy(cloud)
|
|
436
|
+
|
|
437
|
+
# Get current epsg
|
|
438
|
+
cloud_epsg = filtered_cloud.attrs["epsg"]
|
|
439
|
+
current_epsg = cloud_epsg
|
|
440
|
+
|
|
441
|
+
# Check if can be used to filter
|
|
442
|
+
spatial_ref = CRS.from_epsg(cloud_epsg)
|
|
443
|
+
if spatial_ref.is_geographic:
|
|
444
|
+
logging.debug(
|
|
445
|
+
"The points cloud to filter is not in a cartographic system. "
|
|
446
|
+
"The filter's default parameters might not be adapted "
|
|
447
|
+
"to this referential. Please, convert the points "
|
|
448
|
+
"cloud to ECEF to ensure a proper point_cloud."
|
|
449
|
+
)
|
|
450
|
+
# Convert to epsg = 4978
|
|
451
|
+
cartographic_epsg = 4978
|
|
452
|
+
|
|
453
|
+
projection.point_cloud_conversion_dataset(
|
|
454
|
+
filtered_cloud, cartographic_epsg
|
|
455
|
+
)
|
|
456
|
+
current_epsg = cartographic_epsg
|
|
457
|
+
|
|
458
|
+
outlier_removal_algo.epipolar_small_components(
|
|
459
|
+
filtered_cloud,
|
|
460
|
+
min_cluster_size=nb_points_threshold,
|
|
461
|
+
radius=connection_distance,
|
|
462
|
+
half_window_size=half_epipolar_size,
|
|
463
|
+
clusters_distance_threshold=clusters_distance_threshold,
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
# Fill with attributes
|
|
467
|
+
cars_dataset.fill_dataset(
|
|
468
|
+
filtered_cloud,
|
|
469
|
+
saving_info=saving_info_epipolar,
|
|
470
|
+
window=cars_dataset.window_array_to_dict(window),
|
|
471
|
+
profile=None,
|
|
472
|
+
attributes=None,
|
|
473
|
+
overlaps=cars_dataset.overlap_array_to_dict(overlap),
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
# Flatten point cloud to save it as LAZ
|
|
477
|
+
flatten_filtered_cloud = None
|
|
478
|
+
if point_cloud_csv_file_name or point_cloud_laz_file_name:
|
|
479
|
+
# Convert epipolar array into point cloud
|
|
480
|
+
flatten_filtered_cloud, cloud_epsg = (
|
|
481
|
+
pc_transform.depth_map_dataset_to_dataframe(
|
|
482
|
+
filtered_cloud, current_epsg
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
# Convert to UTM
|
|
486
|
+
if epsg is not None and cloud_epsg != epsg:
|
|
487
|
+
projection.point_cloud_conversion_dataframe(
|
|
488
|
+
flatten_filtered_cloud, cloud_epsg, epsg
|
|
489
|
+
)
|
|
490
|
+
cloud_epsg = epsg
|
|
491
|
+
|
|
492
|
+
# Fill attributes for LAZ saving
|
|
493
|
+
color_type = pc_transform.get_color_type([filtered_cloud])
|
|
494
|
+
|
|
495
|
+
attributes = {
|
|
496
|
+
"epsg": cloud_epsg,
|
|
497
|
+
"color_type": color_type,
|
|
498
|
+
cst.CROPPED_DISPARITY_RANGE: ocht.get_disparity_range_cropped(
|
|
499
|
+
cloud
|
|
500
|
+
),
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
cars_dataset.fill_dataframe(
|
|
504
|
+
flatten_filtered_cloud,
|
|
505
|
+
saving_info=saving_info_flatten,
|
|
506
|
+
attributes=attributes,
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
# Save point cloud in worker
|
|
510
|
+
if point_cloud_csv_file_name:
|
|
511
|
+
cars_dataset.run_save_points(
|
|
512
|
+
flatten_filtered_cloud,
|
|
513
|
+
point_cloud_csv_file_name,
|
|
514
|
+
overwrite=True,
|
|
515
|
+
point_cloud_format="csv",
|
|
516
|
+
overwrite_file_name=False,
|
|
517
|
+
)
|
|
518
|
+
if point_cloud_laz_file_name:
|
|
519
|
+
cars_dataset.run_save_points(
|
|
520
|
+
flatten_filtered_cloud,
|
|
521
|
+
point_cloud_laz_file_name,
|
|
522
|
+
overwrite=True,
|
|
523
|
+
point_cloud_format="laz",
|
|
524
|
+
overwrite_file_name=False,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
return filtered_cloud, flatten_filtered_cloud
|