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