cars 1.0.0rc2__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cars might be problematic. Click here for more details.
- cars/__init__.py +86 -0
- cars/applications/__init__.py +40 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +597 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +278 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
- cars/applications/dsm_merging/__init__.py +28 -0
- cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
- cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
- cars/applications/grid_correction/__init__.py +30 -0
- cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
- cars/applications/grid_correction/grid_correction_app.py +557 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +639 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +760 -0
- cars/applications/resampling/resampling_algo.py +590 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sensors_subsampling/__init__.py +32 -0
- cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
- cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
- cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
- cars/applications/sparse_matching/sift_app.py +724 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +750 -0
- cars/cars.py +179 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +1119 -0
- cars/core/geometry/shareloc_geometry.py +598 -0
- cars/core/inputs.py +568 -0
- cars/core/outputs.py +176 -0
- cars/core/preprocessing.py +722 -0
- cars/core/projection.py +843 -0
- cars/core/roi_tools.py +215 -0
- cars/core/tiling.py +774 -0
- cars/core/utils.py +164 -0
- cars/data_structures/__init__.py +23 -0
- cars/data_structures/cars_dataset.py +1544 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +250 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +728 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/memory_tools.py +47 -0
- cars/orchestrator/orchestrator.py +755 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +1088 -0
- cars/pipelines/filling/__init__.py +26 -0
- cars/pipelines/filling/filling.py +981 -0
- cars/pipelines/formatting/__init__.py +26 -0
- cars/pipelines/formatting/formatting.py +186 -0
- cars/pipelines/merging/__init__.py +26 -0
- cars/pipelines/merging/merging.py +439 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +256 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
- cars/pipelines/parameters/application_parameters.py +72 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +349 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +438 -0
- cars/pipelines/parameters/sensor_inputs.py +859 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +38 -0
- cars/pipelines/pipeline_template.py +135 -0
- cars/pipelines/subsampling/__init__.py +26 -0
- cars/pipelines/subsampling/subsampling.py +358 -0
- cars/pipelines/surface_modeling/__init__.py +26 -0
- cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
- cars/pipelines/tie_points/__init__.py +26 -0
- cars/pipelines/tie_points/tie_points.py +536 -0
- cars/starter.py +167 -0
- cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
- cars-1.0.0rc2.dist-info/METADATA +289 -0
- cars-1.0.0rc2.dist-info/RECORD +225 -0
- cars-1.0.0rc2.dist-info/WHEEL +4 -0
- cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
- cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
- cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
- cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2024 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 AuxiliaryFillingFromSensors application class.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
import rasterio as rio
|
|
28
|
+
from scipy import interpolate
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def fill_auxiliary( # pylint: disable=too-many-positional-arguments
|
|
32
|
+
sensor_inputs,
|
|
33
|
+
pairing,
|
|
34
|
+
longitudes,
|
|
35
|
+
latitudes,
|
|
36
|
+
altitudes,
|
|
37
|
+
geom_plugin,
|
|
38
|
+
number_of_color_bands,
|
|
39
|
+
number_of_classification_bands,
|
|
40
|
+
texture_bands,
|
|
41
|
+
texture_interpolator,
|
|
42
|
+
use_mask=False,
|
|
43
|
+
):
|
|
44
|
+
"""
|
|
45
|
+
Compute color and classification for a list of points (lon, lat, alt) using
|
|
46
|
+
information from sensor images
|
|
47
|
+
|
|
48
|
+
:param sensor_inputs: dictionary containing paths to input images and models
|
|
49
|
+
:type sensor_inputs: dict
|
|
50
|
+
:param pairing: pairing between input images
|
|
51
|
+
:type pairing: list
|
|
52
|
+
:param longitudes: list containing longitudes coordinates
|
|
53
|
+
:type longitudes: list
|
|
54
|
+
:param latitudes: list containing latitudes coordinates
|
|
55
|
+
:type latitudes: list
|
|
56
|
+
:param altitudes: list containing altitudes coordinates
|
|
57
|
+
:type altitudes: list
|
|
58
|
+
:param geom_plugin: geometry plugin used for inverse locations
|
|
59
|
+
:type geom_plugin: AbstractGeometry
|
|
60
|
+
:param number_of_color_bands: number of bands in the color image
|
|
61
|
+
:type number_of_color_bands: int
|
|
62
|
+
:param number_of_classification_bands: number of bands in the color image
|
|
63
|
+
:type number_of_classification_bands: int
|
|
64
|
+
:param texture_bands: list of band names used for output texture
|
|
65
|
+
:type texture_bands: list
|
|
66
|
+
:param texture_interpolator: scipy interpolator use to interpolate color
|
|
67
|
+
values
|
|
68
|
+
:type texture_interpolator: str
|
|
69
|
+
:param use_mask: use mask information from sensors in color computation
|
|
70
|
+
:type use_mask: bool
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
filled_color = np.zeros((number_of_color_bands, len(altitudes)))
|
|
75
|
+
|
|
76
|
+
filled_classif = None
|
|
77
|
+
if number_of_classification_bands:
|
|
78
|
+
filled_classif = np.zeros(
|
|
79
|
+
(number_of_classification_bands, len(altitudes)), dtype=bool
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
weights = np.zeros(len(altitudes))
|
|
83
|
+
full_weights = np.zeros(len(altitudes))
|
|
84
|
+
|
|
85
|
+
all_values = np.zeros((number_of_color_bands, len(altitudes)))
|
|
86
|
+
|
|
87
|
+
for pair in pairing:
|
|
88
|
+
|
|
89
|
+
first_sensor = sensor_inputs.get(pair[0])
|
|
90
|
+
second_sensor = sensor_inputs.get(pair[1])
|
|
91
|
+
|
|
92
|
+
# if first sensor has been filtered, use the second sensor instead
|
|
93
|
+
if first_sensor is None:
|
|
94
|
+
first_sensor = second_sensor
|
|
95
|
+
second_sensor = None
|
|
96
|
+
|
|
97
|
+
# process first sensor
|
|
98
|
+
if first_sensor is not None:
|
|
99
|
+
not_interpolated_mask, all_values_sensor = fill_from_one_sensor(
|
|
100
|
+
first_sensor,
|
|
101
|
+
filled_color,
|
|
102
|
+
filled_classif,
|
|
103
|
+
weights,
|
|
104
|
+
longitudes,
|
|
105
|
+
latitudes,
|
|
106
|
+
altitudes,
|
|
107
|
+
geom_plugin,
|
|
108
|
+
number_of_color_bands,
|
|
109
|
+
number_of_classification_bands,
|
|
110
|
+
texture_bands,
|
|
111
|
+
texture_interpolator,
|
|
112
|
+
not_interpolated_mask=None,
|
|
113
|
+
use_mask=use_mask,
|
|
114
|
+
return_all_points=True,
|
|
115
|
+
)
|
|
116
|
+
if all_values_sensor is not None:
|
|
117
|
+
all_values_sensor_mask = ~np.isnan(all_values_sensor)
|
|
118
|
+
all_values[all_values_sensor_mask] += all_values_sensor[
|
|
119
|
+
all_values_sensor_mask
|
|
120
|
+
]
|
|
121
|
+
full_weights[np.any(all_values_sensor_mask[0, :], axis=0)] += 1
|
|
122
|
+
|
|
123
|
+
# process second sensor
|
|
124
|
+
if second_sensor is not None:
|
|
125
|
+
fill_from_one_sensor(
|
|
126
|
+
second_sensor,
|
|
127
|
+
filled_color,
|
|
128
|
+
filled_classif,
|
|
129
|
+
weights,
|
|
130
|
+
longitudes,
|
|
131
|
+
latitudes,
|
|
132
|
+
altitudes,
|
|
133
|
+
geom_plugin,
|
|
134
|
+
number_of_color_bands,
|
|
135
|
+
number_of_classification_bands,
|
|
136
|
+
texture_bands,
|
|
137
|
+
texture_interpolator,
|
|
138
|
+
not_interpolated_mask,
|
|
139
|
+
use_mask=use_mask,
|
|
140
|
+
return_all_points=False,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
interpolated_pixels = np.any(filled_color != 0, axis=0)
|
|
144
|
+
|
|
145
|
+
filled_color[:, interpolated_pixels] /= weights[interpolated_pixels]
|
|
146
|
+
|
|
147
|
+
if use_mask is True:
|
|
148
|
+
full_interpolated_pixels = ~np.logical_or(
|
|
149
|
+
np.any(np.isnan(all_values), axis=0), interpolated_pixels
|
|
150
|
+
)
|
|
151
|
+
filled_color[:, full_interpolated_pixels] = (
|
|
152
|
+
all_values[:, full_interpolated_pixels]
|
|
153
|
+
/ full_weights[full_interpolated_pixels]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return filled_color, filled_classif
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def fill_from_one_sensor( # pylint: disable=too-many-positional-arguments # noqa C901
|
|
160
|
+
sensor,
|
|
161
|
+
filled_color,
|
|
162
|
+
filled_classif,
|
|
163
|
+
weights,
|
|
164
|
+
longitudes,
|
|
165
|
+
latitudes,
|
|
166
|
+
altitudes,
|
|
167
|
+
geom_plugin,
|
|
168
|
+
number_of_color_bands,
|
|
169
|
+
number_of_classification_bands,
|
|
170
|
+
texture_bands,
|
|
171
|
+
texture_interpolator,
|
|
172
|
+
not_interpolated_mask=None,
|
|
173
|
+
use_mask=False,
|
|
174
|
+
return_all_points=False,
|
|
175
|
+
):
|
|
176
|
+
"""
|
|
177
|
+
Compute color and classification contribution for a list of points
|
|
178
|
+
(lon, lat, alt) using information from a sensor image
|
|
179
|
+
|
|
180
|
+
:param sensor: dictionary containing paths to input images and model
|
|
181
|
+
:type sensor: dict
|
|
182
|
+
:param filled_color: array containing (non normalized) color information
|
|
183
|
+
:type filled_color: numpy.ndarray
|
|
184
|
+
:param filled_classif: array containing classification information
|
|
185
|
+
:type filled_classif: numpy.array
|
|
186
|
+
:param weights: array containing weight for normalization
|
|
187
|
+
:type weights: numpy.array
|
|
188
|
+
:param longitudes: list containing longitudes coordinates
|
|
189
|
+
:type longitudes: list
|
|
190
|
+
:param latitudes: list containing latitudes coordinates
|
|
191
|
+
:type latitudes: list
|
|
192
|
+
:param altitudes: list containing altitudes coordinates
|
|
193
|
+
:type altitudes: list
|
|
194
|
+
:param geom_plugin: geometry plugin used for inverse locations
|
|
195
|
+
:type geom_plugin: AbstractGeometry
|
|
196
|
+
:param number_of_color_bands: number of bands in the color image
|
|
197
|
+
:type number_of_color_bands: int
|
|
198
|
+
:param number_of_classification_bands: number of bands in the color image
|
|
199
|
+
:type number_of_classification_bands: int
|
|
200
|
+
:param texture_bands: list of band names used for output texture
|
|
201
|
+
:type texture_bands: list
|
|
202
|
+
:param texture_interpolator: scipy interpolator use to interpolate color
|
|
203
|
+
values
|
|
204
|
+
:type texture_interpolator: str
|
|
205
|
+
:param not_interpolated_mask: use mask information in color computation
|
|
206
|
+
:type not_interpolated_mask: numpy.array
|
|
207
|
+
:param use_mask: use mask information in color computation
|
|
208
|
+
:type use_mask: bool
|
|
209
|
+
:param return_all_points: compute interpolated values for all points
|
|
210
|
+
:type return_all_points: bool
|
|
211
|
+
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
# Check if the sensor has color or classification
|
|
215
|
+
reference_sensor_image = sensor["image"]["bands"]["b0"]["path"]
|
|
216
|
+
|
|
217
|
+
output_not_interpolated_mask = np.ones(len(altitudes), dtype=bool)
|
|
218
|
+
all_values = np.zeros((number_of_color_bands, len(altitudes)))
|
|
219
|
+
|
|
220
|
+
# No filling information for this sensor, return
|
|
221
|
+
if reference_sensor_image is None:
|
|
222
|
+
return output_not_interpolated_mask, all_values
|
|
223
|
+
# read metadata
|
|
224
|
+
with rio.open(reference_sensor_image) as reference_image:
|
|
225
|
+
sensor_height = reference_image.height
|
|
226
|
+
sensor_width = reference_image.width
|
|
227
|
+
|
|
228
|
+
# sensors physical positions
|
|
229
|
+
(
|
|
230
|
+
ind_cols_sensor,
|
|
231
|
+
ind_rows_sensor,
|
|
232
|
+
_,
|
|
233
|
+
) = geom_plugin.inverse_loc(
|
|
234
|
+
reference_sensor_image,
|
|
235
|
+
sensor["geomodel"],
|
|
236
|
+
latitudes,
|
|
237
|
+
longitudes,
|
|
238
|
+
altitudes,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Compute col and row bounds
|
|
242
|
+
min_rows = np.min(ind_rows_sensor)
|
|
243
|
+
max_rows = np.max(ind_rows_sensor)
|
|
244
|
+
|
|
245
|
+
min_cols = np.min(ind_cols_sensor)
|
|
246
|
+
max_cols = np.max(ind_cols_sensor)
|
|
247
|
+
|
|
248
|
+
# Check for out of bound coordinates
|
|
249
|
+
if (
|
|
250
|
+
min_rows > sensor_height
|
|
251
|
+
or max_rows < 0
|
|
252
|
+
or min_cols > sensor_width
|
|
253
|
+
or max_cols < 0
|
|
254
|
+
):
|
|
255
|
+
return output_not_interpolated_mask, all_values
|
|
256
|
+
|
|
257
|
+
if texture_interpolator in ("linear", "nearest"):
|
|
258
|
+
texture_interpolator_margin = 1
|
|
259
|
+
elif texture_interpolator == "cubic":
|
|
260
|
+
texture_interpolator_margin = 3
|
|
261
|
+
else:
|
|
262
|
+
raise RuntimeError(f"Invalid interpolator {texture_interpolator}")
|
|
263
|
+
|
|
264
|
+
# Classification interpolator is always nearest
|
|
265
|
+
classif_interpolator = "nearest"
|
|
266
|
+
classif_interpolator_margin = 1
|
|
267
|
+
|
|
268
|
+
validity_mask = not_interpolated_mask
|
|
269
|
+
if use_mask and sensor.get("mask"):
|
|
270
|
+
with rio.open(sensor["mask"]) as sensor_mask_image:
|
|
271
|
+
first_row = np.floor(max(min_rows - classif_interpolator_margin, 0))
|
|
272
|
+
last_row = np.ceil(
|
|
273
|
+
min(
|
|
274
|
+
max_rows + classif_interpolator_margin,
|
|
275
|
+
sensor_mask_image.height,
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
first_col = np.floor(max(min_cols - classif_interpolator_margin, 0))
|
|
279
|
+
last_col = np.ceil(
|
|
280
|
+
min(
|
|
281
|
+
max_cols + classif_interpolator_margin,
|
|
282
|
+
sensor_mask_image.width,
|
|
283
|
+
)
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
rio_window = rio.windows.Window.from_slices(
|
|
287
|
+
(first_row, last_row),
|
|
288
|
+
(first_col, last_col),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
sensor_points = (
|
|
292
|
+
np.arange(first_row, last_row),
|
|
293
|
+
np.arange(first_col, last_col),
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
sensor_data = sensor_mask_image.read(1, window=rio_window)
|
|
297
|
+
|
|
298
|
+
validity_mask = np.logical_not(
|
|
299
|
+
interpolate.interpn(
|
|
300
|
+
sensor_points,
|
|
301
|
+
sensor_data,
|
|
302
|
+
(ind_rows_sensor, ind_cols_sensor),
|
|
303
|
+
bounds_error=False,
|
|
304
|
+
fill_value=1,
|
|
305
|
+
method=classif_interpolator,
|
|
306
|
+
)
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
if not_interpolated_mask is not None:
|
|
310
|
+
validity_mask = np.logical_and(
|
|
311
|
+
validity_mask, not_interpolated_mask
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
if sensor.get("image"):
|
|
315
|
+
# Only fill color if all texture bands are present
|
|
316
|
+
if all(
|
|
317
|
+
band_name in sensor["image"]["bands"] for band_name in texture_bands
|
|
318
|
+
):
|
|
319
|
+
with rio.open(
|
|
320
|
+
sensor["image"]["bands"]["b0"]["path"]
|
|
321
|
+
) as sensor_color_image:
|
|
322
|
+
first_row = np.floor(
|
|
323
|
+
max(
|
|
324
|
+
np.min(ind_rows_sensor) - texture_interpolator_margin, 0
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
last_row = np.ceil(
|
|
328
|
+
min(
|
|
329
|
+
np.max(ind_rows_sensor) + texture_interpolator_margin,
|
|
330
|
+
sensor_color_image.height,
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
first_col = np.floor(
|
|
334
|
+
max(
|
|
335
|
+
np.min(ind_cols_sensor) - texture_interpolator_margin, 0
|
|
336
|
+
)
|
|
337
|
+
)
|
|
338
|
+
last_col = np.ceil(
|
|
339
|
+
min(
|
|
340
|
+
np.max(ind_cols_sensor) + texture_interpolator_margin,
|
|
341
|
+
sensor_color_image.width,
|
|
342
|
+
)
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
rio_window = rio.windows.Window.from_slices(
|
|
346
|
+
(first_row, last_row),
|
|
347
|
+
(first_col, last_col),
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
sensor_points = (
|
|
351
|
+
np.arange(first_row, last_row),
|
|
352
|
+
np.arange(first_col, last_col),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if validity_mask is not None:
|
|
356
|
+
interpolated_mask = validity_mask
|
|
357
|
+
else:
|
|
358
|
+
interpolated_mask = np.ones(len(altitudes), dtype=bool)
|
|
359
|
+
|
|
360
|
+
for output_band, band_name in enumerate(texture_bands):
|
|
361
|
+
# rio band convention
|
|
362
|
+
sensor_file = rio.open(
|
|
363
|
+
sensor["image"]["bands"][band_name]["path"]
|
|
364
|
+
)
|
|
365
|
+
input_band = sensor["image"]["bands"][band_name]["band"]
|
|
366
|
+
sensor_data = sensor_file.read(
|
|
367
|
+
input_band + 1, window=rio_window
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
if validity_mask is not None:
|
|
371
|
+
if return_all_points is True:
|
|
372
|
+
all_values[output_band, :] = interpolate.interpn(
|
|
373
|
+
sensor_points,
|
|
374
|
+
sensor_data,
|
|
375
|
+
(ind_rows_sensor, ind_cols_sensor),
|
|
376
|
+
bounds_error=False,
|
|
377
|
+
method=texture_interpolator,
|
|
378
|
+
)
|
|
379
|
+
band_values = all_values[output_band, validity_mask]
|
|
380
|
+
# No need to interpolate on every points
|
|
381
|
+
else:
|
|
382
|
+
band_values = interpolate.interpn(
|
|
383
|
+
sensor_points,
|
|
384
|
+
sensor_data,
|
|
385
|
+
(
|
|
386
|
+
ind_rows_sensor[validity_mask],
|
|
387
|
+
ind_cols_sensor[validity_mask],
|
|
388
|
+
),
|
|
389
|
+
bounds_error=False,
|
|
390
|
+
method=texture_interpolator,
|
|
391
|
+
)
|
|
392
|
+
nan_values = np.isnan(band_values)
|
|
393
|
+
interpolated_mask[validity_mask] = np.logical_or(
|
|
394
|
+
interpolated_mask[validity_mask], ~nan_values
|
|
395
|
+
)
|
|
396
|
+
filled_color[output_band, interpolated_mask] += band_values
|
|
397
|
+
|
|
398
|
+
else:
|
|
399
|
+
band_values = interpolate.interpn(
|
|
400
|
+
sensor_points,
|
|
401
|
+
sensor_data,
|
|
402
|
+
(ind_rows_sensor, ind_cols_sensor),
|
|
403
|
+
bounds_error=False,
|
|
404
|
+
method=texture_interpolator,
|
|
405
|
+
)
|
|
406
|
+
interpolated_mask = np.logical_or(
|
|
407
|
+
interpolated_mask, ~np.isnan(band_values)
|
|
408
|
+
)
|
|
409
|
+
filled_color[output_band, interpolated_mask] += band_values
|
|
410
|
+
output_not_interpolated_mask = ~interpolated_mask
|
|
411
|
+
|
|
412
|
+
weights[interpolated_mask] += 1
|
|
413
|
+
|
|
414
|
+
if filled_classif is not None and sensor.get("classification"):
|
|
415
|
+
if number_of_classification_bands == len(
|
|
416
|
+
sensor["classification"]["values"]
|
|
417
|
+
):
|
|
418
|
+
with rio.open(
|
|
419
|
+
sensor["classification"]["path"]
|
|
420
|
+
) as sensor_classif_image:
|
|
421
|
+
|
|
422
|
+
first_row = np.floor(
|
|
423
|
+
max(
|
|
424
|
+
np.min(ind_rows_sensor) - classif_interpolator_margin, 0
|
|
425
|
+
)
|
|
426
|
+
)
|
|
427
|
+
last_row = np.ceil(
|
|
428
|
+
min(
|
|
429
|
+
np.max(ind_rows_sensor) + classif_interpolator_margin,
|
|
430
|
+
sensor_classif_image.height,
|
|
431
|
+
)
|
|
432
|
+
)
|
|
433
|
+
first_col = np.floor(
|
|
434
|
+
max(
|
|
435
|
+
np.min(ind_cols_sensor) - classif_interpolator_margin, 0
|
|
436
|
+
)
|
|
437
|
+
)
|
|
438
|
+
last_col = np.ceil(
|
|
439
|
+
min(
|
|
440
|
+
np.max(ind_cols_sensor) + classif_interpolator_margin,
|
|
441
|
+
sensor_classif_image.width,
|
|
442
|
+
)
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
rio_window = rio.windows.Window.from_slices(
|
|
446
|
+
(first_row, last_row),
|
|
447
|
+
(first_col, last_col),
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
sensor_points = (
|
|
451
|
+
np.arange(first_row, last_row),
|
|
452
|
+
np.arange(first_col, last_col),
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
classif_data = rio.open(sensor["classification"]["path"]).read(
|
|
456
|
+
1, window=rio_window
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
for output_band, value in enumerate(
|
|
460
|
+
sensor["classification"]["values"]
|
|
461
|
+
):
|
|
462
|
+
binary_band_data = classif_data == value
|
|
463
|
+
|
|
464
|
+
filled_classif[output_band, :] = np.logical_or(
|
|
465
|
+
filled_classif[output_band, :],
|
|
466
|
+
interpolate.interpn(
|
|
467
|
+
sensor_points,
|
|
468
|
+
binary_band_data,
|
|
469
|
+
(ind_rows_sensor, ind_cols_sensor),
|
|
470
|
+
bounds_error=False,
|
|
471
|
+
method=classif_interpolator,
|
|
472
|
+
),
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
return output_not_interpolated_mask, all_values
|