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,371 @@
|
|
|
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
|
+
Preprocessing module:
|
|
23
|
+
contains functions used for triangulation
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# Standard imports
|
|
27
|
+
from typing import Dict
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
import pandas
|
|
31
|
+
import xarray as xr
|
|
32
|
+
|
|
33
|
+
from cars.applications.triangulation import (
|
|
34
|
+
triangulation_wrappers as triang_wrap,
|
|
35
|
+
)
|
|
36
|
+
from cars.core import constants as cst
|
|
37
|
+
from cars.core import constants_disparity as cst_disp
|
|
38
|
+
from cars.core import projection
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def triangulate( # pylint: disable=too-many-positional-arguments
|
|
42
|
+
geometry_plugin,
|
|
43
|
+
sensor1,
|
|
44
|
+
sensor2,
|
|
45
|
+
geomodel1,
|
|
46
|
+
geomodel2,
|
|
47
|
+
grid1,
|
|
48
|
+
grid2,
|
|
49
|
+
disp_ref: xr.Dataset,
|
|
50
|
+
disp_key: str = cst_disp.MAP,
|
|
51
|
+
) -> Dict[str, xr.Dataset]:
|
|
52
|
+
"""
|
|
53
|
+
This function will perform triangulation from a disparity map
|
|
54
|
+
|
|
55
|
+
:param geometry_plugin: geometry plugin to use
|
|
56
|
+
:type geometry_plugin: AbstractGeometry
|
|
57
|
+
:param sensor1: path to left sensor image
|
|
58
|
+
:type sensor1: str
|
|
59
|
+
:param sensor2: path to right sensor image
|
|
60
|
+
:type sensor2: str
|
|
61
|
+
:param geomodel1: path and attributes for left geomodel
|
|
62
|
+
:type geomodel1: dict
|
|
63
|
+
:param geomodel2: path and attributes for right geomodel
|
|
64
|
+
:type geomodel2: dict
|
|
65
|
+
:param grid1: dataset of the reference image grid file
|
|
66
|
+
:type grid1: CarsDataset
|
|
67
|
+
:param grid2: dataset of the secondary image grid file
|
|
68
|
+
:type grid2: CarsDataset
|
|
69
|
+
:param disp_ref: left to right disparity map dataset
|
|
70
|
+
:param im_ref_msk_ds: reference image dataset (image and
|
|
71
|
+
mask (if indicated by the user) in epipolar geometry)
|
|
72
|
+
:param disp_key: disparity key in the dataset\
|
|
73
|
+
usually set to cst_disp.MAP, but can be a disparity interval bound
|
|
74
|
+
:returns: point_cloud as a dictionary of dataset containing:
|
|
75
|
+
|
|
76
|
+
- Array with shape (roi_size_x,roi_size_y,3), with last dimension \
|
|
77
|
+
corresponding to longitude, latitude and elevation
|
|
78
|
+
- Array with shape (roi_size_x,roi_size_y) with output mask
|
|
79
|
+
- Array for color (optional): only if color1 is not None
|
|
80
|
+
|
|
81
|
+
The dictionary keys are :
|
|
82
|
+
|
|
83
|
+
- 'ref' to retrieve the dataset built from the left to \
|
|
84
|
+
right disparity map
|
|
85
|
+
- 'sec' to retrieve the dataset built from the right to \
|
|
86
|
+
left disparity map (if provided in input)
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if disp_key != cst_disp.MAP:
|
|
90
|
+
# Switching the variable names so the desired disparity is named 'disp'
|
|
91
|
+
# It does not modifies the dataset outside of this function
|
|
92
|
+
disp_ref = disp_ref.rename_vars(
|
|
93
|
+
{disp_key: cst_disp.MAP, cst_disp.MAP: disp_key}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
point_clouds = {}
|
|
97
|
+
point_clouds[cst.STEREO_REF] = compute_point_cloud(
|
|
98
|
+
geometry_plugin,
|
|
99
|
+
sensor1,
|
|
100
|
+
sensor2,
|
|
101
|
+
geomodel1,
|
|
102
|
+
geomodel2,
|
|
103
|
+
grid1,
|
|
104
|
+
grid2,
|
|
105
|
+
disp_ref,
|
|
106
|
+
roi_key=cst.ROI_WITH_MARGINS,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return point_clouds
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def triangulate_matches( # pylint: disable=too-many-positional-arguments
|
|
113
|
+
geometry_plugin,
|
|
114
|
+
sensor1,
|
|
115
|
+
sensor2,
|
|
116
|
+
geomodel1,
|
|
117
|
+
geomodel2,
|
|
118
|
+
grid1,
|
|
119
|
+
grid2,
|
|
120
|
+
matches,
|
|
121
|
+
interpolation_method=None,
|
|
122
|
+
):
|
|
123
|
+
"""
|
|
124
|
+
This function will perform triangulation from sift matches
|
|
125
|
+
|
|
126
|
+
:param geometry_plugin: geometry plugin to use
|
|
127
|
+
:type geometry_plugin: AbstractGeometry
|
|
128
|
+
:param sensor1: path to left sensor image
|
|
129
|
+
:type sensor1: str
|
|
130
|
+
:param sensor2: path to right sensor image
|
|
131
|
+
:type sensor2: str
|
|
132
|
+
:param geomodel1: path and attributes for left geomodel
|
|
133
|
+
:type geomodel1: dict
|
|
134
|
+
:param geomodel2: path and attributes for right geomodel
|
|
135
|
+
:type geomodel2: dict
|
|
136
|
+
:param grid1: dataset of the reference image grid file
|
|
137
|
+
:type grid1: CarsDataset
|
|
138
|
+
:param grid2: dataset of the secondary image grid file
|
|
139
|
+
:type grid2: CarsDataset
|
|
140
|
+
:param matches: numpy.array of matches of shape (nb_matches, 4)
|
|
141
|
+
:type data: numpy.ndarray
|
|
142
|
+
:returns: point_cloud as a panda DataFrame containing:
|
|
143
|
+
|
|
144
|
+
- Array with shape (nb_matches,1,3), with last dimension \
|
|
145
|
+
corresponding to longitude, latitude and elevation
|
|
146
|
+
- Array with shape (nb_matches,1) with output mask
|
|
147
|
+
- cst.X
|
|
148
|
+
- cst.Y
|
|
149
|
+
- cst.Z
|
|
150
|
+
- corr_mask
|
|
151
|
+
- lon
|
|
152
|
+
- lat
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
:rtype: pandas.DataFrame
|
|
156
|
+
"""
|
|
157
|
+
llh = geometry_plugin.triangulate(
|
|
158
|
+
sensor1,
|
|
159
|
+
sensor2,
|
|
160
|
+
geomodel1,
|
|
161
|
+
geomodel2,
|
|
162
|
+
cst.MATCHES_MODE,
|
|
163
|
+
matches,
|
|
164
|
+
grid1,
|
|
165
|
+
grid2,
|
|
166
|
+
interpolation_method=interpolation_method,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
disparity = np.array([matches[:, 2] - matches[:, 0]])
|
|
170
|
+
disparity = np.transpose(disparity)
|
|
171
|
+
|
|
172
|
+
msk = np.full(llh.shape[0:2], 255, dtype=np.uint8)
|
|
173
|
+
|
|
174
|
+
point_cloud_index = [
|
|
175
|
+
cst.X,
|
|
176
|
+
cst.Y,
|
|
177
|
+
cst.Z,
|
|
178
|
+
cst.DISPARITY,
|
|
179
|
+
cst.POINT_CLOUD_CORR_MSK,
|
|
180
|
+
]
|
|
181
|
+
point_cloud_array = np.zeros(
|
|
182
|
+
(np.ravel(llh[:, :, 0]).size, len(point_cloud_index)), dtype=np.float64
|
|
183
|
+
)
|
|
184
|
+
point_cloud_array[:, 0] = np.ravel(llh[:, :, 0])
|
|
185
|
+
point_cloud_array[:, 1] = np.ravel(llh[:, :, 1])
|
|
186
|
+
point_cloud_array[:, 2] = np.ravel(llh[:, :, 2])
|
|
187
|
+
point_cloud_array[:, 3] = np.ravel(disparity)
|
|
188
|
+
point_cloud_array[:, 4] = np.ravel(msk)
|
|
189
|
+
point_cloud = pandas.DataFrame(point_cloud_array, columns=point_cloud_index)
|
|
190
|
+
point_cloud.attrs[cst.EPSG] = int(cst.EPSG_WSG84)
|
|
191
|
+
return point_cloud
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def triangulate_sparse_matches( # pylint: disable=too-many-positional-arguments
|
|
195
|
+
sensor1,
|
|
196
|
+
sensor2,
|
|
197
|
+
geomodel1,
|
|
198
|
+
geomodel2,
|
|
199
|
+
interpolated_grid_left,
|
|
200
|
+
interpolated_grid_right,
|
|
201
|
+
matches,
|
|
202
|
+
geometry_plugin,
|
|
203
|
+
epsg,
|
|
204
|
+
):
|
|
205
|
+
"""
|
|
206
|
+
Triangulate matches in a metric system
|
|
207
|
+
|
|
208
|
+
:param sensor_image_right: sensor image right
|
|
209
|
+
:type sensor_image_right: CarsDataset
|
|
210
|
+
:param sensor_image_left: sensor image left
|
|
211
|
+
:type sensor_image_left: CarsDataset
|
|
212
|
+
:param grid_left: grid left
|
|
213
|
+
:type grid_left: CarsDataset CarsDataset
|
|
214
|
+
:param grid_right: corrected grid right
|
|
215
|
+
:type grid_right: CarsDataset
|
|
216
|
+
:param interpolated_grid_left: rectification grid left
|
|
217
|
+
:type interpolated_grid_left: shareloc.rectificationGrid
|
|
218
|
+
:param interpolated_grid_right: rectification grid right
|
|
219
|
+
:type interpolated_grid_right: shareloc.rectificationGrid
|
|
220
|
+
:param matches: matches
|
|
221
|
+
:type matches: np.ndarray
|
|
222
|
+
:param geometry_plugin: geometry plugin to use
|
|
223
|
+
:type geometry_plugin: AbstractGeometry
|
|
224
|
+
:param srtm_dir: srtm directory
|
|
225
|
+
:type srtm_dir: str
|
|
226
|
+
:param default_alt: default altitude
|
|
227
|
+
:type default_alt: float
|
|
228
|
+
:param pair_folder: folder used for current pair
|
|
229
|
+
:type pair_folder: str
|
|
230
|
+
:param epsg: ground epsg
|
|
231
|
+
:type epsg: int
|
|
232
|
+
|
|
233
|
+
:return: disp min and disp max
|
|
234
|
+
:rtype: float, float
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
point_cloud = triangulate_matches(
|
|
238
|
+
geometry_plugin,
|
|
239
|
+
sensor1,
|
|
240
|
+
sensor2,
|
|
241
|
+
geomodel1,
|
|
242
|
+
geomodel2,
|
|
243
|
+
interpolated_grid_left,
|
|
244
|
+
interpolated_grid_right,
|
|
245
|
+
np.ascontiguousarray(matches),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Project point cloud to UTM
|
|
249
|
+
projection.point_cloud_conversion_dataset(point_cloud, epsg)
|
|
250
|
+
|
|
251
|
+
# Convert point cloud to pandas format to allow statistical filtering
|
|
252
|
+
labels = [cst.X, cst.Y, cst.Z, cst.DISPARITY, cst.POINT_CLOUD_CORR_MSK]
|
|
253
|
+
cloud_array = []
|
|
254
|
+
cloud_array.append(point_cloud[cst.X].values)
|
|
255
|
+
cloud_array.append(point_cloud[cst.Y].values)
|
|
256
|
+
cloud_array.append(point_cloud[cst.Z].values)
|
|
257
|
+
cloud_array.append(point_cloud[cst.DISPARITY].values)
|
|
258
|
+
cloud_array.append(point_cloud[cst.POINT_CLOUD_CORR_MSK].values)
|
|
259
|
+
pd_cloud = pandas.DataFrame(
|
|
260
|
+
np.transpose(np.array(cloud_array)), columns=labels
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
pd_cloud.attrs["epsg"] = epsg
|
|
264
|
+
|
|
265
|
+
return pd_cloud
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def compute_point_cloud( # pylint: disable=too-many-positional-arguments
|
|
269
|
+
geometry_plugin,
|
|
270
|
+
sensor1,
|
|
271
|
+
sensor2,
|
|
272
|
+
geomodel1,
|
|
273
|
+
geomodel2,
|
|
274
|
+
grid1,
|
|
275
|
+
grid2,
|
|
276
|
+
data: xr.Dataset,
|
|
277
|
+
roi_key: str,
|
|
278
|
+
) -> xr.Dataset:
|
|
279
|
+
# TODO detail a bit more what this method do
|
|
280
|
+
"""
|
|
281
|
+
Compute point cloud
|
|
282
|
+
|
|
283
|
+
:param geometry_plugin: geometry plugin to use
|
|
284
|
+
:param sensor1: path to left sensor image
|
|
285
|
+
:param sensor2: path to right sensor image
|
|
286
|
+
:param geomodel1: path and attributes for left geomodel
|
|
287
|
+
:param geomodel2: path and attributes for right geomodel
|
|
288
|
+
:param grid1: dataset of the reference image grid file
|
|
289
|
+
:param grid2: dataset of the secondary image grid file
|
|
290
|
+
:param data: The reference to disparity map dataset
|
|
291
|
+
:param roi_key: roi of the disparity map key
|
|
292
|
+
('roi' if cropped while calling create_disp_dataset,
|
|
293
|
+
otherwise 'roi_with_margins')
|
|
294
|
+
:return: the point cloud dataset
|
|
295
|
+
"""
|
|
296
|
+
# Extract input paths from configuration
|
|
297
|
+
llh = geometry_plugin.triangulate(
|
|
298
|
+
sensor1,
|
|
299
|
+
sensor2,
|
|
300
|
+
geomodel1,
|
|
301
|
+
geomodel2,
|
|
302
|
+
cst.DISP_MODE,
|
|
303
|
+
data,
|
|
304
|
+
grid1,
|
|
305
|
+
grid2,
|
|
306
|
+
roi_key,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
row = np.array(range(data.attrs[roi_key][1], data.attrs[roi_key][3]))
|
|
310
|
+
col = np.array(range(data.attrs[roi_key][0], data.attrs[roi_key][2]))
|
|
311
|
+
|
|
312
|
+
# apply no_data to X,Y and Z point cloud
|
|
313
|
+
nodata_index = np.where(data[cst_disp.VALID].values == 0)
|
|
314
|
+
llh[:, :, 0][nodata_index] = np.nan
|
|
315
|
+
llh[:, :, 1][nodata_index] = np.nan
|
|
316
|
+
llh[:, :, 2][nodata_index] = np.nan
|
|
317
|
+
|
|
318
|
+
values = {
|
|
319
|
+
cst.X: ([cst.ROW, cst.COL], llh[:, :, 0]), # longitudes
|
|
320
|
+
cst.Y: ([cst.ROW, cst.COL], llh[:, :, 1]), # latitudes
|
|
321
|
+
cst.Z: ([cst.ROW, cst.COL], llh[:, :, 2]),
|
|
322
|
+
cst.POINT_CLOUD_CORR_MSK: (
|
|
323
|
+
[cst.ROW, cst.COL],
|
|
324
|
+
data[cst_disp.VALID].values,
|
|
325
|
+
),
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
# Copy all 2D attributes from disparity dataset to point cloud
|
|
329
|
+
# except color and pandora validity mask (already copied in corr_msk)
|
|
330
|
+
for key, val in data.items():
|
|
331
|
+
if len(val.values.shape) == 2:
|
|
332
|
+
if key not in (cst.EPI_TEXTURE, cst_disp.VALID):
|
|
333
|
+
values[key] = ([cst.ROW, cst.COL], val.values)
|
|
334
|
+
|
|
335
|
+
point_cloud = xr.Dataset(values, coords={cst.ROW: row, cst.COL: col})
|
|
336
|
+
|
|
337
|
+
# add color and data type of image
|
|
338
|
+
color_type = None
|
|
339
|
+
if cst.EPI_TEXTURE in data:
|
|
340
|
+
triang_wrap.add_layer(data, cst.EPI_TEXTURE, cst.BAND_IM, point_cloud)
|
|
341
|
+
color_type = data[cst.EPI_TEXTURE].attrs["color_type"]
|
|
342
|
+
elif cst.EPI_IMAGE in data:
|
|
343
|
+
color_type = data[cst.EPI_IMAGE].attrs["color_type"]
|
|
344
|
+
if color_type:
|
|
345
|
+
point_cloud.attrs["color_type"] = color_type
|
|
346
|
+
|
|
347
|
+
# add classif
|
|
348
|
+
if cst.EPI_CLASSIFICATION in data:
|
|
349
|
+
triang_wrap.add_layer(
|
|
350
|
+
data,
|
|
351
|
+
cst.EPI_CLASSIFICATION,
|
|
352
|
+
cst.BAND_CLASSIF,
|
|
353
|
+
point_cloud,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# add filling in data:
|
|
357
|
+
if cst.EPI_FILLING in data:
|
|
358
|
+
triang_wrap.add_layer(
|
|
359
|
+
data,
|
|
360
|
+
cst.EPI_FILLING,
|
|
361
|
+
cst.BAND_FILLING,
|
|
362
|
+
point_cloud,
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
point_cloud.attrs[cst.ROI] = data.attrs[cst.ROI]
|
|
366
|
+
point_cloud.attrs[cst.ROI_WITH_MARGINS] = data.attrs[cst.ROI_WITH_MARGINS]
|
|
367
|
+
point_cloud.attrs[cst.EPI_MARGINS] = data.attrs[cst.EPI_MARGINS]
|
|
368
|
+
point_cloud.attrs[cst.EPI_FULL_SIZE] = data.attrs[cst.EPI_FULL_SIZE]
|
|
369
|
+
point_cloud.attrs[cst.EPSG] = int(4326)
|
|
370
|
+
|
|
371
|
+
return point_cloud
|
|
@@ -0,0 +1,38 @@
|
|
|
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 constants of triangulation.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# USED VARIABLES
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
TRIANGULATION_RUN_TAG = "triangulation"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# PARAMS
|
|
33
|
+
METHOD = "method"
|
|
34
|
+
SNAP_TO_IMG1 = "snap_to_img1"
|
|
35
|
+
GEOMETRY_PLUGIN = "geometry_plugin"
|
|
36
|
+
|
|
37
|
+
# INFOS
|
|
38
|
+
ALT_REFERENCE_TAG = "alt_reference"
|
|
@@ -0,0 +1,259 @@
|
|
|
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
|
+
Preprocessing module:
|
|
23
|
+
contains functions used for triangulation
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import copy
|
|
27
|
+
|
|
28
|
+
# Third party imports
|
|
29
|
+
import logging
|
|
30
|
+
import os
|
|
31
|
+
|
|
32
|
+
import numpy as np
|
|
33
|
+
import pandas
|
|
34
|
+
import xarray as xr
|
|
35
|
+
from scipy import interpolate
|
|
36
|
+
from shareloc.image import Image
|
|
37
|
+
from shareloc.proj_utils import transform_physical_point_to_index
|
|
38
|
+
|
|
39
|
+
from cars.core import constants as cst
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def add_layer(dataset, layer_name, layer_coords, point_cloud):
|
|
43
|
+
"""
|
|
44
|
+
Add layer point cloud to point cloud dataset
|
|
45
|
+
|
|
46
|
+
:param dataset: input disparity map dataset
|
|
47
|
+
:param layer_name: layer key in disparity dataset
|
|
48
|
+
:param layer_coords: layer axis name in disparity dataset
|
|
49
|
+
:param point_cloud: output point cloud dataset
|
|
50
|
+
"""
|
|
51
|
+
layers = dataset[layer_name].values
|
|
52
|
+
band_layer = dataset.coords[layer_coords]
|
|
53
|
+
|
|
54
|
+
if layer_coords not in point_cloud.dims:
|
|
55
|
+
point_cloud.coords[layer_coords] = band_layer
|
|
56
|
+
|
|
57
|
+
point_cloud[layer_name] = xr.DataArray(
|
|
58
|
+
layers,
|
|
59
|
+
dims=[layer_coords, cst.ROW, cst.COL],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def interpolate_geoid_height(
|
|
64
|
+
geoid_filename, positions, interpolation_method="linear"
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
terrain to index conversion
|
|
68
|
+
retrieve geoid height above ellispoid
|
|
69
|
+
This is a modified version of the Shareloc interpolate_geoid_height
|
|
70
|
+
function that supports Nan positions (return Nan)
|
|
71
|
+
|
|
72
|
+
:param geoid_filename: geoid_filename
|
|
73
|
+
:type geoid_filename: str
|
|
74
|
+
:param positions: geodetic coordinates
|
|
75
|
+
:type positions: 2D numpy array: (number of points,[long coord, lat coord])
|
|
76
|
+
:param interpolation_method: default is 'linear' (interpn parameter)
|
|
77
|
+
:type interpolation_method: str
|
|
78
|
+
:return: geoid height
|
|
79
|
+
:rtype: 1 numpy array (number of points)
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
geoid_image = Image(geoid_filename, read_data=True)
|
|
83
|
+
|
|
84
|
+
# Check longitude overlap is not present, rounding to handle egm2008 with
|
|
85
|
+
# rounded pixel size
|
|
86
|
+
if geoid_image.nb_columns * geoid_image.pixel_size_col - 360 < 10**-8:
|
|
87
|
+
logging.debug("add one pixel overlap on longitudes")
|
|
88
|
+
geoid_image.nb_columns += 1
|
|
89
|
+
# Check if we can add a column
|
|
90
|
+
geoid_image.data = np.column_stack(
|
|
91
|
+
(geoid_image.data[:, :], geoid_image.data[:, 0])
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Prepare grid for interpolation
|
|
95
|
+
row_indexes = np.arange(0, geoid_image.nb_rows, 1)
|
|
96
|
+
col_indexes = np.arange(0, geoid_image.nb_columns, 1)
|
|
97
|
+
points = (row_indexes, col_indexes)
|
|
98
|
+
|
|
99
|
+
# add modulo lon/lat
|
|
100
|
+
min_lon = geoid_image.origin_col + geoid_image.pixel_size_col / 2
|
|
101
|
+
max_lon = (
|
|
102
|
+
geoid_image.origin_col
|
|
103
|
+
+ geoid_image.nb_columns * geoid_image.pixel_size_col
|
|
104
|
+
- geoid_image.pixel_size_col / 2
|
|
105
|
+
)
|
|
106
|
+
positions[:, 0] += ((positions[:, 0] + min_lon) < 0) * 360.0
|
|
107
|
+
positions[:, 0] -= ((positions[:, 0] - max_lon) > 0) * 360.0
|
|
108
|
+
if np.any(np.abs(positions[:, 1]) > 90.0):
|
|
109
|
+
raise RuntimeError("Geoid cannot handle latitudes greater than 90 deg.")
|
|
110
|
+
indexes_geoid = transform_physical_point_to_index(
|
|
111
|
+
geoid_image.trans_inv, positions[:, 1], positions[:, 0]
|
|
112
|
+
)
|
|
113
|
+
return interpolate.interpn(
|
|
114
|
+
points,
|
|
115
|
+
geoid_image.data[:, :],
|
|
116
|
+
indexes_geoid,
|
|
117
|
+
bounds_error=False,
|
|
118
|
+
method=interpolation_method,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def geoid_offset(points, geoid_path):
|
|
123
|
+
"""
|
|
124
|
+
Compute the point cloud height offset from geoid.
|
|
125
|
+
|
|
126
|
+
:param points: point cloud data in lat/lon/alt WGS84 (EPSG 4326)
|
|
127
|
+
coordinates.
|
|
128
|
+
:type points: xarray.Dataset or pandas.DataFrame
|
|
129
|
+
:param geoid_path: path to input geoid file on disk
|
|
130
|
+
:type geoid_path: string
|
|
131
|
+
:return: the same point cloud but using geoid as altimetric reference.
|
|
132
|
+
:rtype: xarray.Dataset or pandas.DataFrame
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
# deep copy the given point cloud that will be used as output
|
|
136
|
+
out_pc = points.copy(deep=True)
|
|
137
|
+
|
|
138
|
+
# interpolate data
|
|
139
|
+
if isinstance(out_pc, xr.Dataset):
|
|
140
|
+
# Convert the dataset to a np array as expected by Shareloc
|
|
141
|
+
pc_array = (
|
|
142
|
+
out_pc[[cst.X, cst.Y]]
|
|
143
|
+
.to_array()
|
|
144
|
+
.to_numpy()
|
|
145
|
+
.transpose((1, 2, 0))
|
|
146
|
+
.reshape((out_pc.sizes["row"] * out_pc.sizes["col"], 2))
|
|
147
|
+
)
|
|
148
|
+
geoid_height_array = interpolate_geoid_height(
|
|
149
|
+
geoid_path, pc_array
|
|
150
|
+
).reshape((out_pc.sizes["row"], out_pc.sizes["col"]))
|
|
151
|
+
elif isinstance(out_pc, pandas.DataFrame):
|
|
152
|
+
geoid_height_array = interpolate_geoid_height(
|
|
153
|
+
geoid_path, out_pc[[cst.X, cst.Y]].to_numpy()
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
raise RuntimeError("Invalid point cloud type")
|
|
157
|
+
|
|
158
|
+
# offset using geoid height
|
|
159
|
+
out_pc[cst.Z] -= geoid_height_array
|
|
160
|
+
|
|
161
|
+
return out_pc
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# pylint: disable=too-many-positional-arguments
|
|
165
|
+
def generate_point_cloud_file_names(
|
|
166
|
+
csv_dir: str,
|
|
167
|
+
laz_dir: str,
|
|
168
|
+
row: int,
|
|
169
|
+
col: int,
|
|
170
|
+
index: dict = None,
|
|
171
|
+
pair_key: str = "PAIR_0",
|
|
172
|
+
):
|
|
173
|
+
"""
|
|
174
|
+
generate the point cloud CSV and LAZ filenames of a given tile from its
|
|
175
|
+
corresponding row and col. Optionally update the index, if provided.
|
|
176
|
+
|
|
177
|
+
:param csv_dir: target directory for csv files, If None no csv filenames
|
|
178
|
+
will be generated
|
|
179
|
+
:type csv_dir: str
|
|
180
|
+
:param laz_dir: target directory for laz files, If None no laz filenames
|
|
181
|
+
will be generated
|
|
182
|
+
:type laz_dir: str
|
|
183
|
+
:param row: row index of the tile
|
|
184
|
+
:type row: int
|
|
185
|
+
:param col: col index of the tile
|
|
186
|
+
:type col: int
|
|
187
|
+
:param index: product index to update with the filename
|
|
188
|
+
:type index: dict
|
|
189
|
+
:param pair_key: current product key (used in index), if a list is given
|
|
190
|
+
a filename will be added to the index for each element of the list
|
|
191
|
+
:type pair_key: str
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
file_name_root = str(col) + "_" + str(row)
|
|
195
|
+
csv_pc_file_name = None
|
|
196
|
+
if csv_dir is not None:
|
|
197
|
+
csv_pc_file_name = os.path.join(csv_dir, file_name_root + ".csv")
|
|
198
|
+
|
|
199
|
+
laz_pc_file_name = None
|
|
200
|
+
if laz_dir is not None:
|
|
201
|
+
laz_name = file_name_root + ".laz"
|
|
202
|
+
laz_pc_file_name = os.path.join(laz_dir, laz_name)
|
|
203
|
+
# add to index if the laz is saved to output product
|
|
204
|
+
if index is not None:
|
|
205
|
+
# index initialization, if it has not been done yet
|
|
206
|
+
if "point_cloud" not in index:
|
|
207
|
+
index["point_cloud"] = {}
|
|
208
|
+
# case where merging=True and save_by_pair=False
|
|
209
|
+
if pair_key is None:
|
|
210
|
+
index["point_cloud"][file_name_root] = laz_name
|
|
211
|
+
else:
|
|
212
|
+
if isinstance(pair_key, str):
|
|
213
|
+
pair_key = [pair_key]
|
|
214
|
+
for elem in pair_key:
|
|
215
|
+
if elem not in index["point_cloud"]:
|
|
216
|
+
index["point_cloud"][elem] = {}
|
|
217
|
+
index["point_cloud"][elem][file_name_root] = os.path.join(
|
|
218
|
+
elem, laz_name
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
return csv_pc_file_name, laz_pc_file_name
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def compute_performance_map(
|
|
225
|
+
alti_ref, z_inf, z_sup, ambiguity_map=None, perf_ambiguity_threshold=None
|
|
226
|
+
):
|
|
227
|
+
"""
|
|
228
|
+
Compute performance map
|
|
229
|
+
|
|
230
|
+
:param alti_ref: z
|
|
231
|
+
:type alti_ref: xarray Dataarray
|
|
232
|
+
:param z_inf: z inf map
|
|
233
|
+
:type z_inf: xarray Dataarray
|
|
234
|
+
:param z_sup: z sup map
|
|
235
|
+
:type z_sup: xarray Dataarray
|
|
236
|
+
:param ambiguity_map: None or ambiguity map
|
|
237
|
+
:type ambiguity_map: xarray Dataarray
|
|
238
|
+
:param perf_ambiguity_threshold: ambiguity threshold to use
|
|
239
|
+
:type perf_ambiguity_threshold: None or float
|
|
240
|
+
|
|
241
|
+
"""
|
|
242
|
+
performance_map = copy.copy(alti_ref)
|
|
243
|
+
|
|
244
|
+
performance_map_values = np.maximum(
|
|
245
|
+
np.abs(alti_ref.values - z_inf.values),
|
|
246
|
+
np.abs(z_sup.values - alti_ref.values),
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if ambiguity_map is not None:
|
|
250
|
+
# ambiguity is already ambiguity, not confidence from ambiguity
|
|
251
|
+
ambiguity_map = ambiguity_map.values
|
|
252
|
+
mask_ambi = ambiguity_map > perf_ambiguity_threshold
|
|
253
|
+
w_ambi = ambiguity_map / perf_ambiguity_threshold
|
|
254
|
+
w_ambi[mask_ambi] = 1
|
|
255
|
+
performance_map_values *= w_ambi
|
|
256
|
+
|
|
257
|
+
performance_map.values = performance_map_values
|
|
258
|
+
|
|
259
|
+
return performance_map
|