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.

Files changed (200) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +37 -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 +104 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -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 +655 -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 +1460 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-312-i386-linux-gnu.so +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  31. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  32. cars/applications/dense_matching/cpp/meson.build +9 -0
  33. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  34. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  35. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  36. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  37. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  38. cars/applications/dense_matching/disparity_grid_algo.py +588 -0
  39. cars/applications/dense_matching/loaders/__init__.py +23 -0
  40. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  46. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  47. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  48. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  49. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  50. cars/applications/dsm_filling/__init__.py +32 -0
  51. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  52. cars/applications/dsm_filling/border_interpolation_app.py +270 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
  56. cars/applications/grid_generation/__init__.py +30 -0
  57. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  58. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  59. cars/applications/grid_generation/grid_correction_app.py +496 -0
  60. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  61. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  62. cars/applications/grid_generation/transform_grid.py +88 -0
  63. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  64. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  65. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  66. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  67. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  68. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  69. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  70. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  71. cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
  72. cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
  73. cars/applications/rasterization/__init__.py +30 -0
  74. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  75. cars/applications/rasterization/rasterization_algo.py +534 -0
  76. cars/applications/rasterization/rasterization_constants.py +38 -0
  77. cars/applications/rasterization/rasterization_wrappers.py +634 -0
  78. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  79. cars/applications/resampling/__init__.py +28 -0
  80. cars/applications/resampling/abstract_resampling_app.py +187 -0
  81. cars/applications/resampling/bicubic_resampling_app.py +762 -0
  82. cars/applications/resampling/resampling_algo.py +614 -0
  83. cars/applications/resampling/resampling_constants.py +36 -0
  84. cars/applications/resampling/resampling_wrappers.py +309 -0
  85. cars/applications/sparse_matching/__init__.py +30 -0
  86. cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
  87. cars/applications/sparse_matching/sift_app.py +735 -0
  88. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  89. cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
  90. cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
  91. cars/applications/triangulation/__init__.py +32 -0
  92. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  93. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  94. cars/applications/triangulation/pc_transform.py +552 -0
  95. cars/applications/triangulation/triangulation_algo.py +371 -0
  96. cars/applications/triangulation/triangulation_constants.py +38 -0
  97. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  98. cars/bundleadjustment.py +757 -0
  99. cars/cars.py +177 -0
  100. cars/conf/__init__.py +23 -0
  101. cars/conf/geoid/egm96.grd +0 -0
  102. cars/conf/geoid/egm96.grd.hdr +15 -0
  103. cars/conf/input_parameters.py +156 -0
  104. cars/conf/mask_cst.py +35 -0
  105. cars/core/__init__.py +23 -0
  106. cars/core/cars_logging.py +402 -0
  107. cars/core/constants.py +191 -0
  108. cars/core/constants_disparity.py +50 -0
  109. cars/core/datasets.py +140 -0
  110. cars/core/geometry/__init__.py +27 -0
  111. cars/core/geometry/abstract_geometry.py +1119 -0
  112. cars/core/geometry/shareloc_geometry.py +598 -0
  113. cars/core/inputs.py +568 -0
  114. cars/core/outputs.py +176 -0
  115. cars/core/preprocessing.py +722 -0
  116. cars/core/projection.py +843 -0
  117. cars/core/roi_tools.py +215 -0
  118. cars/core/tiling.py +774 -0
  119. cars/core/utils.py +164 -0
  120. cars/data_structures/__init__.py +23 -0
  121. cars/data_structures/cars_dataset.py +1541 -0
  122. cars/data_structures/cars_dict.py +74 -0
  123. cars/data_structures/corresponding_tiles_tools.py +186 -0
  124. cars/data_structures/dataframe_converter.py +185 -0
  125. cars/data_structures/format_transformation.py +297 -0
  126. cars/devibrate.py +689 -0
  127. cars/extractroi.py +264 -0
  128. cars/orchestrator/__init__.py +23 -0
  129. cars/orchestrator/achievement_tracker.py +125 -0
  130. cars/orchestrator/cluster/__init__.py +37 -0
  131. cars/orchestrator/cluster/abstract_cluster.py +244 -0
  132. cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
  133. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  134. cars/orchestrator/cluster/dask_config/README.md +94 -0
  135. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  136. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  137. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  138. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  139. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  140. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  141. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  142. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  143. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  144. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  145. cars/orchestrator/cluster/log_wrapper.py +1075 -0
  146. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  147. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  148. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  149. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  150. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  151. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
  152. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  153. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  154. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  155. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  156. cars/orchestrator/orchestrator.py +905 -0
  157. cars/orchestrator/orchestrator_constants.py +29 -0
  158. cars/orchestrator/registry/__init__.py +23 -0
  159. cars/orchestrator/registry/abstract_registry.py +143 -0
  160. cars/orchestrator/registry/compute_registry.py +106 -0
  161. cars/orchestrator/registry/id_generator.py +116 -0
  162. cars/orchestrator/registry/replacer_registry.py +213 -0
  163. cars/orchestrator/registry/saver_registry.py +363 -0
  164. cars/orchestrator/registry/unseen_registry.py +118 -0
  165. cars/orchestrator/tiles_profiler.py +279 -0
  166. cars/pipelines/__init__.py +26 -0
  167. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  168. cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
  169. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  170. cars/pipelines/default/__init__.py +26 -0
  171. cars/pipelines/default/default_pipeline.py +786 -0
  172. cars/pipelines/parameters/__init__.py +0 -0
  173. cars/pipelines/parameters/advanced_parameters.py +417 -0
  174. cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
  175. cars/pipelines/parameters/application_parameters.py +71 -0
  176. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  177. cars/pipelines/parameters/dsm_inputs.py +918 -0
  178. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  179. cars/pipelines/parameters/output_constants.py +52 -0
  180. cars/pipelines/parameters/output_parameters.py +454 -0
  181. cars/pipelines/parameters/sensor_inputs.py +842 -0
  182. cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
  183. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  184. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  185. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  186. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  187. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  188. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  189. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  190. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  191. cars/pipelines/pipeline.py +119 -0
  192. cars/pipelines/pipeline_constants.py +31 -0
  193. cars/pipelines/pipeline_template.py +139 -0
  194. cars/pipelines/unit/__init__.py +26 -0
  195. cars/pipelines/unit/unit_pipeline.py +2850 -0
  196. cars/starter.py +167 -0
  197. cars-1.0.0rc1.dist-info/METADATA +292 -0
  198. cars-1.0.0rc1.dist-info/RECORD +200 -0
  199. cars-1.0.0rc1.dist-info/WHEEL +6 -0
  200. cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,630 @@
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
+ import logging
26
+ import os
27
+ import shutil
28
+
29
+ import numpy as np
30
+ import rasterio as rio
31
+ import xarray as xr
32
+ from json_checker import Checker
33
+ from pyproj import CRS
34
+ from rasterio.enums import Resampling
35
+ from rasterio.warp import reproject
36
+ from shapely.geometry import Polygon
37
+
38
+ import cars.orchestrator.orchestrator as ocht
39
+ from cars.applications.auxiliary_filling import (
40
+ auxiliary_filling_algo,
41
+ auxiliary_filling_wrappers,
42
+ )
43
+
44
+ # CARS imports
45
+ from cars.applications.auxiliary_filling.abstract_auxiliary_filling_app import (
46
+ AuxiliaryFilling,
47
+ )
48
+ from cars.core import constants as cst
49
+ from cars.core import inputs, projection, tiling
50
+ from cars.data_structures import cars_dataset
51
+
52
+
53
+ class AuxiliaryFillingFromSensors(
54
+ AuxiliaryFilling, short_name="auxiliary_filling_from_sensors"
55
+ ):
56
+ """
57
+ AuxiliaryFillingFromSensors Application
58
+ """
59
+
60
+ def __init__(self, conf=None):
61
+ """
62
+ Init function of AuxiliaryFillingFromSensors
63
+
64
+ :param conf: configuration for AuxiliaryFillingFromSensors
65
+ :return: an application_to_use object
66
+ """
67
+
68
+ self.orchestrator = None
69
+
70
+ super().__init__(conf=conf)
71
+
72
+ def check_conf(self, conf):
73
+ """
74
+ Check configuration
75
+
76
+ :param conf: configuration to check
77
+ :type conf: dict
78
+
79
+ :return: overloaded configuration
80
+ :rtype: dict
81
+
82
+ """
83
+
84
+ # init conf
85
+ if conf is not None:
86
+ overloaded_conf = conf.copy()
87
+ else:
88
+ conf = {}
89
+ overloaded_conf = {}
90
+
91
+ # Overload conf
92
+ overloaded_conf["method"] = conf.get(
93
+ "method", "auxiliary_filling_from_sensors"
94
+ )
95
+
96
+ overloaded_conf["mode"] = conf.get("mode", "fill_nan")
97
+
98
+ if overloaded_conf["mode"] not in ["fill_nan", "full"]:
99
+ # pylint: disable=inconsistent-quotes
100
+ raise RuntimeError(
101
+ f"Invalid mode {overloaded_conf['mode']} for "
102
+ f"AuxiliaryFilling, supported modes are fill_nan "
103
+ f"and full"
104
+ )
105
+
106
+ overloaded_conf["texture_interpolator"] = conf.get(
107
+ "texture_interpolator", "linear"
108
+ )
109
+ overloaded_conf["activated"] = conf.get("activated", False)
110
+ overloaded_conf["use_mask"] = conf.get("use_mask", True)
111
+
112
+ # Saving files
113
+ overloaded_conf["save_intermediate_data"] = conf.get(
114
+ "save_intermediate_data", False
115
+ )
116
+
117
+ auxiliary_filling_schema = {
118
+ "method": str,
119
+ "activated": bool,
120
+ "mode": str,
121
+ "use_mask": bool,
122
+ "texture_interpolator": str,
123
+ "save_intermediate_data": bool,
124
+ }
125
+
126
+ # Check conf
127
+ checker = Checker(auxiliary_filling_schema)
128
+ checker.validate(overloaded_conf)
129
+
130
+ return overloaded_conf
131
+
132
+ # pylint: disable=too-many-positional-arguments
133
+ def run( # noqa: C901
134
+ self,
135
+ dsm_file,
136
+ color_file,
137
+ classif_file,
138
+ dump_dir,
139
+ sensor_inputs,
140
+ pairing,
141
+ geom_plugin,
142
+ texture_bands,
143
+ output_geoid,
144
+ orchestrator=None,
145
+ ):
146
+ """
147
+ run AuxiliaryFillingFromSensors
148
+
149
+ :param dsm_file: path to the filled dsm file
150
+ :type dsm_file: str
151
+ :param color_file: path to the color file
152
+ :type color_file: str
153
+ :param classification_file: path to the classification file
154
+ :type classification_file: str
155
+ :param dump_dir: output dump directory
156
+ :type dump_dir: str
157
+ :param sensor_inputs: dictionary containing paths to input images and
158
+ models
159
+ :type sensor_inputs: dict
160
+ :param pairing: pairing between input images
161
+ :type pairing: list
162
+ :param geom_plugin: geometry plugin used for inverse locations
163
+ :type geom_plugin: AbstractGeometry
164
+ :param texture_bands: list of band names used for output texture
165
+ :type texture_bands: list
166
+ :param output_geoid: output geoid filename as vertical reference for the
167
+ input DSM. If a boolean is provided instead of a filename True means
168
+ defined relative to cars internal geoid, and false on ellipsoid
169
+ :type output_geoid: OR(bool, str)
170
+ :param orchestrator: orchestrator used
171
+ :type orchestrator: Orchestrator
172
+ """
173
+
174
+ if not self.used_config["activated"]:
175
+ return None
176
+ if sensor_inputs is None:
177
+ logging.error(
178
+ "No sensor inputs were provided, "
179
+ "auxiliary_filling will not run."
180
+ )
181
+ return None
182
+
183
+ # Default orchestrator
184
+ if orchestrator is None:
185
+ # Create default sequential orchestrator for current application
186
+ # be aware, no out_json will be shared between orchestrators
187
+ # No files saved
188
+ self.orchestrator = ocht.Orchestrator(
189
+ orchestrator_conf={"mode": "sequential"}
190
+ )
191
+ else:
192
+ self.orchestrator = orchestrator
193
+
194
+ dump_dir = os.path.join(dump_dir, "auxiliary_filling")
195
+
196
+ if not os.path.exists(dump_dir):
197
+ os.makedirs(dump_dir)
198
+
199
+ color_not_filled_file = os.path.join(dump_dir, "texture_not_filled.tif")
200
+ if color_file is not None and os.path.exists(color_file):
201
+ shutil.move(color_file, color_not_filled_file)
202
+
203
+ classification_not_filled_file = None
204
+ # classif_file could be defined without data attached
205
+ if classif_file is not None and not os.path.exists(classif_file):
206
+ classif_file = None
207
+
208
+ if classif_file is not None:
209
+ classification_not_filled_file = os.path.join(
210
+ dump_dir, "classification_not_filled.tif"
211
+ )
212
+ shutil.move(classif_file, classification_not_filled_file)
213
+
214
+ # Clean dump_dir at the end of processing if required
215
+ if not self.used_config["save_intermediate_data"]:
216
+ self.orchestrator.add_to_clean(dump_dir)
217
+
218
+ # Create output CarsDataset
219
+ aux_filled_image = cars_dataset.CarsDataset(
220
+ "arrays", name="aux_filled_image"
221
+ )
222
+
223
+ # Create tiling grid
224
+ ground_image_width, ground_image_height = inputs.rasterio_get_size(
225
+ dsm_file
226
+ )
227
+
228
+ region_grid = tiling.generate_tiling_grid(
229
+ 0,
230
+ 0,
231
+ ground_image_height,
232
+ ground_image_width,
233
+ 1000,
234
+ 1000,
235
+ )
236
+
237
+ aux_filled_image.tiling_grid = region_grid
238
+
239
+ # Initialize no data value
240
+ classification_no_data_value = 0
241
+ texture_no_data_value = 0
242
+ color_dtype = np.float32
243
+ classif_dtype = np.uint8
244
+
245
+ if color_file is not None:
246
+ if os.path.exists(color_not_filled_file):
247
+ with rio.open(color_not_filled_file, "r") as descriptor:
248
+ texture_no_data_value = descriptor.nodata
249
+ color_dtype = descriptor.profile.get("dtype", np.float32)
250
+
251
+ self.orchestrator.add_to_save_lists(
252
+ os.path.join(dump_dir, color_file),
253
+ cst.RASTER_COLOR_IMG,
254
+ aux_filled_image,
255
+ nodata=texture_no_data_value,
256
+ dtype=color_dtype,
257
+ cars_ds_name="filled_texture",
258
+ )
259
+
260
+ if classif_file is not None:
261
+ if os.path.exists(classification_not_filled_file):
262
+ with rio.open(
263
+ classification_not_filled_file, "r"
264
+ ) as descriptor:
265
+ classification_no_data_value = descriptor.nodata
266
+ classif_dtype = descriptor.profile.get("dtype", np.uint8)
267
+
268
+ self.orchestrator.add_to_save_lists(
269
+ os.path.join(dump_dir, classif_file),
270
+ cst.RASTER_CLASSIF,
271
+ aux_filled_image,
272
+ dtype=classif_dtype,
273
+ nodata=classification_no_data_value,
274
+ cars_ds_name="filled_classification",
275
+ )
276
+
277
+ # Get saving infos in order to save tiles when they are computed
278
+ [saving_info] = self.orchestrator.get_saving_infos([aux_filled_image])
279
+
280
+ reference_transform = inputs.rasterio_get_transform(dsm_file)
281
+ reference_crs = inputs.rasterio_get_crs(dsm_file)
282
+
283
+ # Pre-compute sensor bounds of all sensors to filter sensors that do
284
+ # not intersect with tile in tasks
285
+ sensor_bounds = auxiliary_filling_wrappers.compute_sensor_bounds(
286
+ sensor_inputs, geom_plugin, reference_crs
287
+ )
288
+
289
+ for row in range(aux_filled_image.shape[0]):
290
+ for col in range(aux_filled_image.shape[1]):
291
+
292
+ # Get window
293
+ window = cars_dataset.window_array_to_dict(
294
+ aux_filled_image.tiling_grid[row, col]
295
+ )
296
+
297
+ full_saving_info = ocht.update_saving_infos(
298
+ saving_info, row=row, col=col
299
+ )
300
+ aux_filled_image[
301
+ row, col
302
+ ] = self.orchestrator.cluster.create_task(
303
+ filling_from_sensor_wrapper, nout=1
304
+ )(
305
+ dsm_file,
306
+ color_not_filled_file,
307
+ classification_not_filled_file,
308
+ sensor_inputs,
309
+ sensor_bounds,
310
+ pairing,
311
+ window,
312
+ reference_transform,
313
+ reference_crs,
314
+ full_saving_info,
315
+ geom_plugin,
316
+ texture_bands,
317
+ output_geoid,
318
+ mode=self.used_config["mode"],
319
+ texture_interpolator=self.used_config[
320
+ "texture_interpolator"
321
+ ],
322
+ use_mask=self.used_config["use_mask"],
323
+ )
324
+
325
+ # Run tasks if an internal orchestrator is used, in order to save output
326
+ # files
327
+ if orchestrator is None:
328
+ self.orchestrator.breakpoint()
329
+
330
+ return aux_filled_image
331
+
332
+
333
+ # pylint: disable=too-many-positional-arguments
334
+ def filling_from_sensor_wrapper(
335
+ dsm_file,
336
+ color_file,
337
+ classification_file,
338
+ sensor_inputs,
339
+ sensor_bounds,
340
+ pairing,
341
+ window,
342
+ transform,
343
+ crs,
344
+ saving_info,
345
+ geom_plugin,
346
+ texture_bands,
347
+ output_geoid,
348
+ mode,
349
+ texture_interpolator,
350
+ use_mask,
351
+ ):
352
+ """
353
+ Fill color and classification from sensor information for a terrain tile
354
+
355
+ :param dsm_file: path to the filled dsm file
356
+ :type dsm_file: str
357
+ :param color_file: path to the color file
358
+ :type color_file: str
359
+ :param classification_file: path to the classification file
360
+ :type classification_file: str
361
+ :param sensor_inputs: dictionary containing paths to input images and models
362
+ :type sensor_inputs: dict
363
+ :param sensor_bounds: dictionary containing bounds of input sensors
364
+ :type sensor_bounds: dict
365
+ :param pairing: pairing between input images
366
+ :type pairing: list
367
+ :param window: window of the current tile
368
+ :type window: dict
369
+ :param transform: input geo transform
370
+ :type transform: tuple
371
+ :param crs: input crs
372
+ :type crs: CRS
373
+ :param saving_info: saving info for cars orchestrator
374
+ :type saving_info: dict
375
+ :param geom_plugin: geometry plugin used for inverse locations
376
+ :type geom_plugin: AbstractGeometry
377
+ :param texture_bands: list of band names used for output texture
378
+ :type texture_bands: list
379
+ :param output_geoid: output geoid filename as vertical reference for the
380
+ input DSM. If a boolean is provided instead of a filename True means
381
+ defined relative to cars internal geoid, and false on ellipsoid
382
+ :type output_geoid: OR(bool, str)
383
+ :param mode: geometry plugin used for inverse locations
384
+ :type mode: str
385
+ :param texture_interpolator: scipy interpolator use to interpolate color
386
+ values
387
+ :type texture_interpolator: str
388
+ :param use_mask: use mask information from sensors in color computation
389
+ :type use_mask: bool
390
+ """
391
+
392
+ col_min = window["col_min"]
393
+ col_max = window["col_max"]
394
+ row_min = window["row_min"]
395
+ row_max = window["row_max"]
396
+
397
+ col_min_ground = col_min * transform[0] + transform[2]
398
+ col_max_ground = col_max * transform[0] + transform[2]
399
+ row_min_ground = row_min * transform[4] + transform[5]
400
+ row_max_ground = row_max * transform[4] + transform[5]
401
+
402
+ ground_polygon = Polygon(
403
+ [
404
+ (col_min_ground, row_min_ground),
405
+ (col_min_ground, row_max_ground),
406
+ (col_max_ground, row_max_ground),
407
+ (col_max_ground, row_min_ground),
408
+ (col_min_ground, row_min_ground),
409
+ ]
410
+ )
411
+
412
+ cols = (
413
+ np.linspace(col_min, col_max, col_max - col_min) * transform[0]
414
+ + transform[2]
415
+ )
416
+ rows = (
417
+ np.linspace(row_min, row_max, row_max - row_min) * transform[4]
418
+ + transform[5]
419
+ )
420
+
421
+ cols_values_2d, rows_values_2d = np.meshgrid(cols, rows)
422
+
423
+ stacked_values = np.vstack([cols_values_2d.ravel(), rows_values_2d.ravel()])
424
+
425
+ lon_lat = projection.point_cloud_conversion_crs(
426
+ stacked_values.transpose(), crs, CRS(4326)
427
+ )
428
+
429
+ rio_window = rio.windows.Window.from_slices(
430
+ (
431
+ row_min,
432
+ row_max,
433
+ ),
434
+ (
435
+ col_min,
436
+ col_max,
437
+ ),
438
+ )
439
+
440
+ # From input DSM read altitudes for localisation and no-data mask.
441
+ # if fill_nan mode is chosed, all values valid in dsm and invalid in color
442
+ # will be filled
443
+ # if not, all values valid in dsm will be filled
444
+ # Note that the same pixels are filled for color and classification
445
+ with rio.open(dsm_file) as dsm_image:
446
+ alt_values = dsm_image.read(1, window=rio_window)
447
+ target_mask = dsm_image.read_masks(1, window=rio_window)
448
+ dsm_profile = dsm_image.profile
449
+
450
+ if output_geoid:
451
+ if output_geoid is True:
452
+ geoid_file = geom_plugin.geoid
453
+ else:
454
+ geoid_file = output_geoid
455
+ with rio.open(geoid_file) as in_geoid:
456
+ # Reproject the geoid data to match the DSM
457
+ output_geoid_data = np.empty(
458
+ alt_values.shape, dtype=in_geoid.dtypes[0]
459
+ )
460
+
461
+ reproject(
462
+ source=rio.band(in_geoid, 1),
463
+ destination=output_geoid_data,
464
+ src_transform=in_geoid.transform,
465
+ src_crs=in_geoid.crs,
466
+ dst_transform=transform,
467
+ dst_crs=crs,
468
+ resampling=Resampling.bilinear,
469
+ )
470
+ alt_values += output_geoid_data
471
+
472
+ nodata_color = None
473
+ nodata_classif = None
474
+
475
+ if os.path.exists(color_file):
476
+ with rio.open(color_file) as color_image:
477
+ profile = color_image.profile
478
+ nodata_color = color_image.nodata
479
+
480
+ number_of_color_bands = color_image.count
481
+ color_band_names = list(color_image.descriptions)
482
+
483
+ color_values = color_image.read(window=rio_window)
484
+
485
+ if mode == "fill_nan":
486
+ target_mask = target_mask & ~color_image.read_masks(
487
+ 1, window=rio_window
488
+ )
489
+ else:
490
+ profile = dsm_profile
491
+ number_of_color_bands = inputs.rasterio_get_nb_bands(
492
+ sensor_inputs[list(sensor_inputs.keys())[0]].get("texture", None)
493
+ )
494
+ color_values = np.full(
495
+ (number_of_color_bands, *target_mask.shape), np.nan
496
+ )
497
+ color_band_names = inputs.get_descriptions_bands(
498
+ sensor_inputs[list(sensor_inputs.keys())[0]].get("texture", None)
499
+ )
500
+ # update profile
501
+ profile.update(count=number_of_color_bands)
502
+
503
+ number_of_classification_bands = 0
504
+ classification_values = None
505
+ classification_band_names = None
506
+
507
+ if classification_file is not None:
508
+ if os.path.exists(classification_file):
509
+ with rio.open(classification_file) as classification_image:
510
+ nodata_classif = None
511
+
512
+ number_of_classification_bands = classification_image.count
513
+
514
+ classification_values = classification_image.read(
515
+ window=rio_window
516
+ )
517
+ classification_band_names = list(
518
+ classification_image.descriptions
519
+ )
520
+ else:
521
+ profile = dsm_profile
522
+ classif_sample = sensor_inputs[list(sensor_inputs.keys())[0]].get(
523
+ "classification", None
524
+ )
525
+ if classif_sample is None:
526
+ raise RuntimeError(
527
+ "No classification file found for auxiliary filling"
528
+ )
529
+ number_of_classification_bands = len(classif_sample["values"])
530
+ classification_values = np.full(
531
+ (number_of_classification_bands, *target_mask.shape), np.nan
532
+ )
533
+ classification_band_names = inputs.get_descriptions_bands(
534
+ classif_sample
535
+ )
536
+ # update profile
537
+ profile.update(count=number_of_classification_bands)
538
+
539
+ # 1D index list from target mask
540
+ index_1d = target_mask.flatten().nonzero()[0]
541
+
542
+ # Remove sensor that don't intesects with current tile
543
+ filtered_sensor_inputs = auxiliary_filling_wrappers.filter_sensor_inputs(
544
+ sensor_inputs, sensor_bounds, ground_polygon
545
+ )
546
+
547
+ if len(index_1d) > 0:
548
+ # Fill required pixels
549
+ color_values_filled, classification_values_filled = (
550
+ auxiliary_filling_algo.fill_auxiliary(
551
+ filtered_sensor_inputs,
552
+ pairing,
553
+ lon_lat[index_1d, 0],
554
+ lon_lat[index_1d, 1],
555
+ alt_values.ravel()[index_1d],
556
+ geom_plugin,
557
+ number_of_color_bands,
558
+ number_of_classification_bands,
559
+ texture_bands,
560
+ texture_interpolator=texture_interpolator,
561
+ use_mask=use_mask,
562
+ )
563
+ )
564
+
565
+ # Change nan to nodata
566
+ if nodata_color is not None:
567
+ color_values_filled[np.isnan(color_values_filled)] = nodata_color
568
+ if nodata_classif is not None:
569
+ classification_values_filled[
570
+ np.isnan(classification_values_filled)
571
+ ] = nodata_classif
572
+
573
+ # forward filled values in the output buffer
574
+ for band_index in range(number_of_color_bands):
575
+ np.put(
576
+ color_values[band_index, :, :],
577
+ index_1d,
578
+ color_values_filled[band_index, :],
579
+ )
580
+
581
+ for band_index in range(number_of_classification_bands):
582
+ np.put(
583
+ classification_values[band_index, :, :],
584
+ index_1d,
585
+ classification_values_filled[band_index, :],
586
+ )
587
+
588
+ row_arr = np.array(range(row_min, row_max))
589
+ col_arr = np.array(range(col_min, col_max))
590
+
591
+ values = {}
592
+ coords = {cst.ROW: row_arr, cst.COL: col_arr}
593
+
594
+ if len(color_band_names) == 0 or None in color_band_names:
595
+ color_band_names = [
596
+ str(current_band) for current_band in range(number_of_color_bands)
597
+ ]
598
+
599
+ values[cst.RASTER_COLOR_IMG] = (
600
+ [cst.BAND_IM, cst.ROW, cst.COL],
601
+ color_values,
602
+ )
603
+ coords[cst.BAND_IM] = list(color_band_names)
604
+
605
+ if classification_values is not None:
606
+ values[cst.RASTER_CLASSIF] = (
607
+ [cst.BAND_CLASSIF, cst.ROW, cst.COL],
608
+ classification_values,
609
+ )
610
+ coords[cst.BAND_CLASSIF] = list(classification_band_names)
611
+
612
+ attributes = {}
613
+
614
+ dataset = xr.Dataset(
615
+ values,
616
+ coords=coords,
617
+ )
618
+
619
+ profile.update(crs=crs.to_wkt())
620
+
621
+ cars_dataset.fill_dataset(
622
+ dataset,
623
+ saving_info=saving_info,
624
+ window=window,
625
+ profile=profile,
626
+ attributes=attributes,
627
+ overlaps=None,
628
+ )
629
+
630
+ return dataset