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.

Files changed (225) hide show
  1. cars/__init__.py +86 -0
  2. cars/applications/__init__.py +40 -0
  3. cars/applications/application.py +117 -0
  4. cars/applications/application_constants.py +29 -0
  5. cars/applications/application_template.py +146 -0
  6. cars/applications/auxiliary_filling/__init__.py +29 -0
  7. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
  10. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
  11. cars/applications/dem_generation/__init__.py +30 -0
  12. cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
  13. cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
  15. cars/applications/dem_generation/bulldozer_memory.py +55 -0
  16. cars/applications/dem_generation/dem_generation_algo.py +107 -0
  17. cars/applications/dem_generation/dem_generation_constants.py +32 -0
  18. cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
  19. cars/applications/dense_match_filling/__init__.py +30 -0
  20. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
  21. cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
  22. cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
  23. cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
  24. cars/applications/dense_match_filling/zero_padding_app.py +302 -0
  25. cars/applications/dense_matching/__init__.py +30 -0
  26. cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
  27. cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.dll.a +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
  31. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  32. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  33. cars/applications/dense_matching/cpp/meson.build +9 -0
  34. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  35. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  36. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  37. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  38. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  39. cars/applications/dense_matching/disparity_grid_algo.py +597 -0
  40. cars/applications/dense_matching/loaders/__init__.py +23 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  46. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  47. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  48. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  49. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  50. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  51. cars/applications/dsm_filling/__init__.py +32 -0
  52. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  53. cars/applications/dsm_filling/border_interpolation_app.py +278 -0
  54. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  55. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  56. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  57. cars/applications/dsm_merging/__init__.py +28 -0
  58. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  59. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  60. cars/applications/grid_correction/__init__.py +30 -0
  61. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  62. cars/applications/grid_correction/grid_correction_app.py +557 -0
  63. cars/applications/grid_generation/__init__.py +30 -0
  64. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  65. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  66. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  67. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  68. cars/applications/grid_generation/transform_grid.py +88 -0
  69. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  70. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  71. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  72. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  73. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  74. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  76. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  77. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  78. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  79. cars/applications/rasterization/__init__.py +30 -0
  80. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  81. cars/applications/rasterization/rasterization_algo.py +534 -0
  82. cars/applications/rasterization/rasterization_constants.py +38 -0
  83. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  84. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  85. cars/applications/resampling/__init__.py +28 -0
  86. cars/applications/resampling/abstract_resampling_app.py +187 -0
  87. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  88. cars/applications/resampling/resampling_algo.py +590 -0
  89. cars/applications/resampling/resampling_constants.py +36 -0
  90. cars/applications/resampling/resampling_wrappers.py +309 -0
  91. cars/applications/sensors_subsampling/__init__.py +32 -0
  92. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  93. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  94. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  95. cars/applications/sparse_matching/__init__.py +30 -0
  96. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  97. cars/applications/sparse_matching/sift_app.py +724 -0
  98. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  99. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  100. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  101. cars/applications/triangulation/__init__.py +32 -0
  102. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  103. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  104. cars/applications/triangulation/pc_transform.py +552 -0
  105. cars/applications/triangulation/triangulation_algo.py +371 -0
  106. cars/applications/triangulation/triangulation_constants.py +38 -0
  107. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  108. cars/bundleadjustment.py +750 -0
  109. cars/cars.py +179 -0
  110. cars/conf/__init__.py +23 -0
  111. cars/conf/geoid/egm96.grd +0 -0
  112. cars/conf/geoid/egm96.grd.hdr +15 -0
  113. cars/conf/input_parameters.py +156 -0
  114. cars/conf/mask_cst.py +35 -0
  115. cars/core/__init__.py +23 -0
  116. cars/core/cars_logging.py +402 -0
  117. cars/core/constants.py +191 -0
  118. cars/core/constants_disparity.py +50 -0
  119. cars/core/datasets.py +140 -0
  120. cars/core/geometry/__init__.py +27 -0
  121. cars/core/geometry/abstract_geometry.py +1119 -0
  122. cars/core/geometry/shareloc_geometry.py +598 -0
  123. cars/core/inputs.py +568 -0
  124. cars/core/outputs.py +176 -0
  125. cars/core/preprocessing.py +722 -0
  126. cars/core/projection.py +843 -0
  127. cars/core/roi_tools.py +215 -0
  128. cars/core/tiling.py +774 -0
  129. cars/core/utils.py +164 -0
  130. cars/data_structures/__init__.py +23 -0
  131. cars/data_structures/cars_dataset.py +1544 -0
  132. cars/data_structures/cars_dict.py +74 -0
  133. cars/data_structures/corresponding_tiles_tools.py +186 -0
  134. cars/data_structures/dataframe_converter.py +185 -0
  135. cars/data_structures/format_transformation.py +297 -0
  136. cars/devibrate.py +689 -0
  137. cars/extractroi.py +264 -0
  138. cars/orchestrator/__init__.py +23 -0
  139. cars/orchestrator/achievement_tracker.py +125 -0
  140. cars/orchestrator/cluster/__init__.py +37 -0
  141. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  142. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  143. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  144. cars/orchestrator/cluster/dask_config/README.md +94 -0
  145. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  146. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  147. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  152. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  153. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  154. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  155. cars/orchestrator/cluster/log_wrapper.py +728 -0
  156. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  160. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  162. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  163. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  164. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  165. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  166. cars/orchestrator/memory_tools.py +47 -0
  167. cars/orchestrator/orchestrator.py +755 -0
  168. cars/orchestrator/orchestrator_constants.py +29 -0
  169. cars/orchestrator/registry/__init__.py +23 -0
  170. cars/orchestrator/registry/abstract_registry.py +143 -0
  171. cars/orchestrator/registry/compute_registry.py +106 -0
  172. cars/orchestrator/registry/id_generator.py +116 -0
  173. cars/orchestrator/registry/replacer_registry.py +213 -0
  174. cars/orchestrator/registry/saver_registry.py +363 -0
  175. cars/orchestrator/registry/unseen_registry.py +118 -0
  176. cars/orchestrator/tiles_profiler.py +279 -0
  177. cars/pipelines/__init__.py +26 -0
  178. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  179. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  180. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  181. cars/pipelines/default/__init__.py +26 -0
  182. cars/pipelines/default/default_pipeline.py +1088 -0
  183. cars/pipelines/filling/__init__.py +26 -0
  184. cars/pipelines/filling/filling.py +981 -0
  185. cars/pipelines/formatting/__init__.py +26 -0
  186. cars/pipelines/formatting/formatting.py +186 -0
  187. cars/pipelines/merging/__init__.py +26 -0
  188. cars/pipelines/merging/merging.py +439 -0
  189. cars/pipelines/parameters/__init__.py +0 -0
  190. cars/pipelines/parameters/advanced_parameters.py +256 -0
  191. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  192. cars/pipelines/parameters/application_parameters.py +72 -0
  193. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  194. cars/pipelines/parameters/dsm_inputs.py +349 -0
  195. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  196. cars/pipelines/parameters/output_constants.py +52 -0
  197. cars/pipelines/parameters/output_parameters.py +438 -0
  198. cars/pipelines/parameters/sensor_inputs.py +859 -0
  199. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  200. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  202. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  204. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  206. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  207. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  208. cars/pipelines/pipeline.py +119 -0
  209. cars/pipelines/pipeline_constants.py +38 -0
  210. cars/pipelines/pipeline_template.py +135 -0
  211. cars/pipelines/subsampling/__init__.py +26 -0
  212. cars/pipelines/subsampling/subsampling.py +358 -0
  213. cars/pipelines/surface_modeling/__init__.py +26 -0
  214. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  215. cars/pipelines/tie_points/__init__.py +26 -0
  216. cars/pipelines/tie_points/tie_points.py +536 -0
  217. cars/starter.py +167 -0
  218. cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
  219. cars-1.0.0rc2.dist-info/METADATA +289 -0
  220. cars-1.0.0rc2.dist-info/RECORD +225 -0
  221. cars-1.0.0rc2.dist-info/WHEEL +4 -0
  222. cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
  223. cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
  224. cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
  225. 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