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,632 @@
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
+ dsm_dir=None,
146
+ ):
147
+ """
148
+ run AuxiliaryFillingFromSensors
149
+
150
+ :param dsm_file: path to the filled dsm file
151
+ :type dsm_file: str
152
+ :param color_file: path to the color file
153
+ :type color_file: str
154
+ :param classification_file: path to the classification file
155
+ :type classification_file: str
156
+ :param dump_dir: output dump directory
157
+ :type dump_dir: str
158
+ :param sensor_inputs: dictionary containing paths to input images and
159
+ models
160
+ :type sensor_inputs: dict
161
+ :param pairing: pairing between input images
162
+ :type pairing: list
163
+ :param geom_plugin: geometry plugin used for inverse locations
164
+ :type geom_plugin: AbstractGeometry
165
+ :param texture_bands: list of band names used for output texture
166
+ :type texture_bands: list
167
+ :param output_geoid: output geoid filename as vertical reference for the
168
+ input DSM. If a boolean is provided instead of a filename True means
169
+ defined relative to cars internal geoid, and false on ellipsoid
170
+ :type output_geoid: OR(bool, str)
171
+ :param orchestrator: orchestrator used
172
+ :type orchestrator: Orchestrator
173
+ """
174
+
175
+ if dsm_dir is not None:
176
+ image_path_out = os.path.join(dsm_dir, "image.tif")
177
+ else:
178
+ image_path_out = color_file
179
+
180
+ if not self.used_config["activated"]:
181
+ return None
182
+ if sensor_inputs is None:
183
+ logging.error(
184
+ "No sensor inputs were provided, "
185
+ "auxiliary_filling will not run."
186
+ )
187
+ return None
188
+ # Default orchestrator
189
+ if orchestrator is None:
190
+ # Create default sequential orchestrator for current application
191
+ # be aware, no out_json will be shared between orchestrators
192
+ # No files saved
193
+ self.orchestrator = ocht.Orchestrator(
194
+ orchestrator_conf={"mode": "sequential"}
195
+ )
196
+ else:
197
+ self.orchestrator = orchestrator
198
+
199
+ dump_dir = os.path.join(dump_dir, "auxiliary_filling")
200
+
201
+ if not os.path.exists(dump_dir):
202
+ os.makedirs(dump_dir)
203
+
204
+ color_not_filled_file = color_file
205
+
206
+ classification_not_filled_file = None
207
+ # classif_file could be defined without data attached
208
+ if classif_file is not None and not os.path.exists(classif_file):
209
+ classif_file = None
210
+
211
+ if classif_file is not None:
212
+ classification_not_filled_file = os.path.join(
213
+ dump_dir, "classification_not_filled.tif"
214
+ )
215
+ shutil.move(classif_file, classification_not_filled_file)
216
+
217
+ # Clean dump_dir at the end of processing if required
218
+ if not self.used_config["save_intermediate_data"]:
219
+ self.orchestrator.add_to_clean(dump_dir)
220
+
221
+ # Create output CarsDataset
222
+ aux_filled_image = cars_dataset.CarsDataset(
223
+ "arrays", name="aux_filled_image"
224
+ )
225
+
226
+ # Create tiling grid
227
+ ground_image_width, ground_image_height = inputs.rasterio_get_size(
228
+ dsm_file
229
+ )
230
+
231
+ region_grid = tiling.generate_tiling_grid(
232
+ 0,
233
+ 0,
234
+ ground_image_height,
235
+ ground_image_width,
236
+ 1000,
237
+ 1000,
238
+ )
239
+
240
+ aux_filled_image.tiling_grid = region_grid
241
+
242
+ # Initialize no data value
243
+ classification_no_data_value = 0
244
+ texture_no_data_value = 0
245
+ color_dtype = np.float32
246
+ classif_dtype = np.uint8
247
+
248
+ if color_file is not None:
249
+ if os.path.exists(color_not_filled_file):
250
+ with rio.open(color_not_filled_file, "r") as descriptor:
251
+ texture_no_data_value = descriptor.nodata
252
+ color_dtype = descriptor.profile.get("dtype", np.float32)
253
+
254
+ self.orchestrator.add_to_save_lists(
255
+ os.path.join(dump_dir, image_path_out),
256
+ cst.RASTER_COLOR_IMG,
257
+ aux_filled_image,
258
+ nodata=texture_no_data_value,
259
+ dtype=color_dtype,
260
+ cars_ds_name="filled_texture",
261
+ )
262
+
263
+ if classif_file is not None:
264
+ if os.path.exists(classification_not_filled_file):
265
+ with rio.open(
266
+ classification_not_filled_file, "r"
267
+ ) as descriptor:
268
+ classification_no_data_value = descriptor.nodata
269
+ classif_dtype = descriptor.profile.get("dtype", np.uint8)
270
+
271
+ self.orchestrator.add_to_save_lists(
272
+ os.path.join(dump_dir, classif_file),
273
+ cst.RASTER_CLASSIF,
274
+ aux_filled_image,
275
+ dtype=classif_dtype,
276
+ nodata=classification_no_data_value,
277
+ cars_ds_name="filled_classification",
278
+ )
279
+
280
+ # Get saving infos in order to save tiles when they are computed
281
+ [saving_info] = self.orchestrator.get_saving_infos([aux_filled_image])
282
+
283
+ reference_transform = inputs.rasterio_get_transform(dsm_file)
284
+ reference_crs = inputs.rasterio_get_crs(dsm_file)
285
+
286
+ # Pre-compute sensor bounds of all sensors to filter sensors that do
287
+ # not intersect with tile in tasks
288
+ sensor_bounds = auxiliary_filling_wrappers.compute_sensor_bounds(
289
+ sensor_inputs, geom_plugin, reference_crs
290
+ )
291
+
292
+ for row in range(aux_filled_image.shape[0]):
293
+ for col in range(aux_filled_image.shape[1]):
294
+
295
+ # Get window
296
+ window = cars_dataset.window_array_to_dict(
297
+ aux_filled_image.tiling_grid[row, col]
298
+ )
299
+
300
+ full_saving_info = ocht.update_saving_infos(
301
+ saving_info, row=row, col=col
302
+ )
303
+ aux_filled_image[
304
+ row, col
305
+ ] = self.orchestrator.cluster.create_task(
306
+ filling_from_sensor_wrapper, nout=1
307
+ )(
308
+ dsm_file,
309
+ color_not_filled_file,
310
+ classification_not_filled_file,
311
+ sensor_inputs,
312
+ sensor_bounds,
313
+ pairing,
314
+ window,
315
+ reference_transform,
316
+ reference_crs,
317
+ full_saving_info,
318
+ geom_plugin,
319
+ texture_bands,
320
+ output_geoid,
321
+ mode=self.used_config["mode"],
322
+ texture_interpolator=self.used_config[
323
+ "texture_interpolator"
324
+ ],
325
+ use_mask=self.used_config["use_mask"],
326
+ )
327
+
328
+ # Run tasks if an internal orchestrator is used, in order to save output
329
+ # files
330
+ if orchestrator is None:
331
+ self.orchestrator.breakpoint()
332
+
333
+ return aux_filled_image
334
+
335
+
336
+ # pylint: disable=too-many-positional-arguments
337
+ def filling_from_sensor_wrapper(
338
+ dsm_file,
339
+ color_file,
340
+ classification_file,
341
+ sensor_inputs,
342
+ sensor_bounds,
343
+ pairing,
344
+ window,
345
+ transform,
346
+ crs,
347
+ saving_info,
348
+ geom_plugin,
349
+ texture_bands,
350
+ output_geoid,
351
+ mode,
352
+ texture_interpolator,
353
+ use_mask,
354
+ ):
355
+ """
356
+ Fill color and classification from sensor information for a terrain tile
357
+
358
+ :param dsm_file: path to the filled dsm file
359
+ :type dsm_file: str
360
+ :param color_file: path to the color file
361
+ :type color_file: str
362
+ :param classification_file: path to the classification file
363
+ :type classification_file: str
364
+ :param sensor_inputs: dictionary containing paths to input images and models
365
+ :type sensor_inputs: dict
366
+ :param sensor_bounds: dictionary containing bounds of input sensors
367
+ :type sensor_bounds: dict
368
+ :param pairing: pairing between input images
369
+ :type pairing: list
370
+ :param window: window of the current tile
371
+ :type window: dict
372
+ :param transform: input geo transform
373
+ :type transform: tuple
374
+ :param crs: input crs
375
+ :type crs: CRS
376
+ :param saving_info: saving info for cars orchestrator
377
+ :type saving_info: dict
378
+ :param geom_plugin: geometry plugin used for inverse locations
379
+ :type geom_plugin: AbstractGeometry
380
+ :param texture_bands: list of band names used for output texture
381
+ :type texture_bands: list
382
+ :param output_geoid: output geoid filename as vertical reference for the
383
+ input DSM. If a boolean is provided instead of a filename True means
384
+ defined relative to cars internal geoid, and false on ellipsoid
385
+ :type output_geoid: OR(bool, str)
386
+ :param mode: geometry plugin used for inverse locations
387
+ :type mode: str
388
+ :param texture_interpolator: scipy interpolator use to interpolate color
389
+ values
390
+ :type texture_interpolator: str
391
+ :param use_mask: use mask information from sensors in color computation
392
+ :type use_mask: bool
393
+ """
394
+ col_min = window["col_min"]
395
+ col_max = window["col_max"]
396
+ row_min = window["row_min"]
397
+ row_max = window["row_max"]
398
+
399
+ col_min_ground = col_min * transform[0] + transform[2]
400
+ col_max_ground = col_max * transform[0] + transform[2]
401
+ row_min_ground = row_min * transform[4] + transform[5]
402
+ row_max_ground = row_max * transform[4] + transform[5]
403
+
404
+ ground_polygon = Polygon(
405
+ [
406
+ (col_min_ground, row_min_ground),
407
+ (col_min_ground, row_max_ground),
408
+ (col_max_ground, row_max_ground),
409
+ (col_max_ground, row_min_ground),
410
+ (col_min_ground, row_min_ground),
411
+ ]
412
+ )
413
+
414
+ cols = (
415
+ np.linspace(col_min, col_max, col_max - col_min) * transform[0]
416
+ + transform[2]
417
+ )
418
+ rows = (
419
+ np.linspace(row_min, row_max, row_max - row_min) * transform[4]
420
+ + transform[5]
421
+ )
422
+
423
+ cols_values_2d, rows_values_2d = np.meshgrid(cols, rows)
424
+
425
+ stacked_values = np.vstack([cols_values_2d.ravel(), rows_values_2d.ravel()])
426
+
427
+ lon_lat = projection.point_cloud_conversion_crs(
428
+ stacked_values.transpose(), crs, CRS(4326)
429
+ )
430
+
431
+ rio_window = rio.windows.Window.from_slices(
432
+ (
433
+ row_min,
434
+ row_max,
435
+ ),
436
+ (
437
+ col_min,
438
+ col_max,
439
+ ),
440
+ )
441
+
442
+ # From input DSM read altitudes for localisation and no-data mask.
443
+ # if fill_nan mode is chosed, all values valid in dsm and invalid in color
444
+ # will be filled
445
+ # if not, all values valid in dsm will be filled
446
+ # Note that the same pixels are filled for color and classification
447
+ with rio.open(dsm_file) as dsm_image:
448
+ alt_values = dsm_image.read(1, window=rio_window)
449
+ target_mask = dsm_image.read_masks(1, window=rio_window)
450
+ dsm_profile = dsm_image.profile
451
+
452
+ if output_geoid:
453
+ if output_geoid is True:
454
+ geoid_file = geom_plugin.geoid
455
+ else:
456
+ geoid_file = output_geoid
457
+ with rio.open(geoid_file) as in_geoid:
458
+ # Reproject the geoid data to match the DSM
459
+ output_geoid_data = np.empty(
460
+ alt_values.shape, dtype=in_geoid.dtypes[0]
461
+ )
462
+
463
+ reproject(
464
+ source=rio.band(in_geoid, 1),
465
+ destination=output_geoid_data,
466
+ src_transform=in_geoid.transform,
467
+ src_crs=in_geoid.crs,
468
+ dst_transform=transform,
469
+ dst_crs=crs,
470
+ resampling=Resampling.bilinear,
471
+ )
472
+ alt_values += output_geoid_data
473
+
474
+ nodata_color = None
475
+ nodata_classif = None
476
+
477
+ if os.path.exists(color_file):
478
+ with rio.open(color_file) as color_image:
479
+ profile = color_image.profile
480
+ nodata_color = color_image.nodata
481
+
482
+ number_of_color_bands = color_image.count
483
+ color_band_names = list(color_image.descriptions)
484
+
485
+ color_values = color_image.read(window=rio_window)
486
+
487
+ if mode == "fill_nan":
488
+ target_mask = target_mask & ~color_image.read_masks(
489
+ 1, window=rio_window
490
+ )
491
+ else:
492
+ profile = dsm_profile
493
+ number_of_color_bands = inputs.rasterio_get_nb_bands(
494
+ sensor_inputs[list(sensor_inputs.keys())[0]].get("texture", None)
495
+ )
496
+ color_values = np.full(
497
+ (number_of_color_bands, *target_mask.shape), np.nan
498
+ )
499
+ color_band_names = inputs.get_descriptions_bands(
500
+ sensor_inputs[list(sensor_inputs.keys())[0]].get("texture", None)
501
+ )
502
+ # update profile
503
+ profile.update(count=number_of_color_bands)
504
+
505
+ number_of_classification_bands = 0
506
+ classification_values = None
507
+ classification_band_names = None
508
+
509
+ if classification_file is not None:
510
+ if os.path.exists(classification_file):
511
+ with rio.open(classification_file) as classification_image:
512
+ nodata_classif = None
513
+
514
+ number_of_classification_bands = classification_image.count
515
+
516
+ classification_values = classification_image.read(
517
+ window=rio_window
518
+ )
519
+ classification_band_names = list(
520
+ classification_image.descriptions
521
+ )
522
+ else:
523
+ profile = dsm_profile
524
+ classif_sample = sensor_inputs[list(sensor_inputs.keys())[0]].get(
525
+ "classification", None
526
+ )
527
+ if classif_sample is None:
528
+ raise RuntimeError(
529
+ "No classification file found for auxiliary filling"
530
+ )
531
+ number_of_classification_bands = len(classif_sample["values"])
532
+ classification_values = np.full(
533
+ (number_of_classification_bands, *target_mask.shape), np.nan
534
+ )
535
+ classification_band_names = inputs.get_descriptions_bands(
536
+ classif_sample
537
+ )
538
+ # update profile
539
+ profile.update(count=number_of_classification_bands)
540
+
541
+ # 1D index list from target mask
542
+ index_1d = target_mask.flatten().nonzero()[0]
543
+
544
+ # Remove sensor that don't intesects with current tile
545
+ filtered_sensor_inputs = auxiliary_filling_wrappers.filter_sensor_inputs(
546
+ sensor_inputs, sensor_bounds, ground_polygon
547
+ )
548
+
549
+ if len(index_1d) > 0:
550
+ # Fill required pixels
551
+ color_values_filled, classification_values_filled = (
552
+ auxiliary_filling_algo.fill_auxiliary(
553
+ filtered_sensor_inputs,
554
+ pairing,
555
+ lon_lat[index_1d, 0],
556
+ lon_lat[index_1d, 1],
557
+ alt_values.ravel()[index_1d],
558
+ geom_plugin,
559
+ number_of_color_bands,
560
+ number_of_classification_bands,
561
+ texture_bands,
562
+ texture_interpolator=texture_interpolator,
563
+ use_mask=use_mask,
564
+ )
565
+ )
566
+
567
+ # Change nan to nodata
568
+ if nodata_color is not None:
569
+ color_values_filled[np.isnan(color_values_filled)] = nodata_color
570
+ if nodata_classif is not None:
571
+ classification_values_filled[
572
+ np.isnan(classification_values_filled)
573
+ ] = nodata_classif
574
+
575
+ # forward filled values in the output buffer
576
+ for band_index in range(number_of_color_bands):
577
+ np.put(
578
+ color_values[band_index, :, :],
579
+ index_1d,
580
+ color_values_filled[band_index, :],
581
+ )
582
+
583
+ for band_index in range(number_of_classification_bands):
584
+ np.put(
585
+ classification_values[band_index, :, :],
586
+ index_1d,
587
+ classification_values_filled[band_index, :],
588
+ )
589
+
590
+ row_arr = np.array(range(row_min, row_max))
591
+ col_arr = np.array(range(col_min, col_max))
592
+
593
+ values = {}
594
+ coords = {cst.ROW: row_arr, cst.COL: col_arr}
595
+
596
+ if len(color_band_names) == 0 or None in color_band_names:
597
+ color_band_names = [
598
+ str(current_band) for current_band in range(number_of_color_bands)
599
+ ]
600
+
601
+ values[cst.RASTER_COLOR_IMG] = (
602
+ [cst.BAND_IM, cst.ROW, cst.COL],
603
+ color_values,
604
+ )
605
+ coords[cst.BAND_IM] = list(color_band_names)
606
+
607
+ if classification_values is not None:
608
+ values[cst.RASTER_CLASSIF] = (
609
+ [cst.BAND_CLASSIF, cst.ROW, cst.COL],
610
+ classification_values,
611
+ )
612
+ coords[cst.BAND_CLASSIF] = list(classification_band_names)
613
+
614
+ attributes = {}
615
+
616
+ dataset = xr.Dataset(
617
+ values,
618
+ coords=coords,
619
+ )
620
+
621
+ profile.update(crs=crs.to_wkt())
622
+
623
+ cars_dataset.fill_dataset(
624
+ dataset,
625
+ saving_info=saving_info,
626
+ window=window,
627
+ profile=profile,
628
+ attributes=attributes,
629
+ overlaps=None,
630
+ )
631
+
632
+ return dataset