cars 1.0.0rc3__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
Files changed (220) hide show
  1. cars/__init__.py +74 -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 +46 -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.cpython-313-x86_64-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 +597 -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 +278 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  56. cars/applications/dsm_merging/__init__.py +28 -0
  57. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  58. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  59. cars/applications/grid_correction/__init__.py +30 -0
  60. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  61. cars/applications/grid_correction/grid_correction_app.py +557 -0
  62. cars/applications/grid_generation/__init__.py +30 -0
  63. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  64. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  65. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  66. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  67. cars/applications/grid_generation/transform_grid.py +88 -0
  68. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  69. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  70. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  71. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  72. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  73. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  74. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  76. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  77. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  78. cars/applications/rasterization/__init__.py +30 -0
  79. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  80. cars/applications/rasterization/rasterization_algo.py +534 -0
  81. cars/applications/rasterization/rasterization_constants.py +38 -0
  82. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  83. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  84. cars/applications/resampling/__init__.py +28 -0
  85. cars/applications/resampling/abstract_resampling_app.py +187 -0
  86. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  87. cars/applications/resampling/resampling_algo.py +590 -0
  88. cars/applications/resampling/resampling_constants.py +36 -0
  89. cars/applications/resampling/resampling_wrappers.py +309 -0
  90. cars/applications/sensors_subsampling/__init__.py +32 -0
  91. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  92. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  93. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  94. cars/applications/sparse_matching/__init__.py +30 -0
  95. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  96. cars/applications/sparse_matching/sift_app.py +724 -0
  97. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  98. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  99. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  100. cars/applications/triangulation/__init__.py +32 -0
  101. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  102. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  103. cars/applications/triangulation/pc_transform.py +552 -0
  104. cars/applications/triangulation/triangulation_algo.py +371 -0
  105. cars/applications/triangulation/triangulation_constants.py +38 -0
  106. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  107. cars/bundleadjustment.py +750 -0
  108. cars/cars.py +179 -0
  109. cars/conf/__init__.py +23 -0
  110. cars/conf/geoid/egm96.grd +0 -0
  111. cars/conf/geoid/egm96.grd.hdr +15 -0
  112. cars/conf/input_parameters.py +156 -0
  113. cars/conf/mask_cst.py +35 -0
  114. cars/core/__init__.py +23 -0
  115. cars/core/cars_logging.py +402 -0
  116. cars/core/constants.py +191 -0
  117. cars/core/constants_disparity.py +50 -0
  118. cars/core/datasets.py +140 -0
  119. cars/core/geometry/__init__.py +27 -0
  120. cars/core/geometry/abstract_geometry.py +1130 -0
  121. cars/core/geometry/shareloc_geometry.py +604 -0
  122. cars/core/inputs.py +568 -0
  123. cars/core/outputs.py +176 -0
  124. cars/core/preprocessing.py +722 -0
  125. cars/core/projection.py +843 -0
  126. cars/core/roi_tools.py +215 -0
  127. cars/core/tiling.py +774 -0
  128. cars/core/utils.py +164 -0
  129. cars/data_structures/__init__.py +23 -0
  130. cars/data_structures/cars_dataset.py +1544 -0
  131. cars/data_structures/cars_dict.py +74 -0
  132. cars/data_structures/corresponding_tiles_tools.py +186 -0
  133. cars/data_structures/dataframe_converter.py +185 -0
  134. cars/data_structures/format_transformation.py +297 -0
  135. cars/devibrate.py +689 -0
  136. cars/extractroi.py +264 -0
  137. cars/orchestrator/__init__.py +23 -0
  138. cars/orchestrator/achievement_tracker.py +125 -0
  139. cars/orchestrator/cluster/__init__.py +37 -0
  140. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  141. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  142. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  143. cars/orchestrator/cluster/dask_config/README.md +94 -0
  144. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  145. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  146. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  147. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  152. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  153. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  154. cars/orchestrator/cluster/log_wrapper.py +728 -0
  155. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  156. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  160. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  162. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  163. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  164. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  165. cars/orchestrator/memory_tools.py +47 -0
  166. cars/orchestrator/orchestrator.py +755 -0
  167. cars/orchestrator/orchestrator_constants.py +29 -0
  168. cars/orchestrator/registry/__init__.py +23 -0
  169. cars/orchestrator/registry/abstract_registry.py +143 -0
  170. cars/orchestrator/registry/compute_registry.py +106 -0
  171. cars/orchestrator/registry/id_generator.py +116 -0
  172. cars/orchestrator/registry/replacer_registry.py +213 -0
  173. cars/orchestrator/registry/saver_registry.py +363 -0
  174. cars/orchestrator/registry/unseen_registry.py +118 -0
  175. cars/orchestrator/tiles_profiler.py +279 -0
  176. cars/pipelines/__init__.py +26 -0
  177. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  178. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  179. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  180. cars/pipelines/default/__init__.py +26 -0
  181. cars/pipelines/default/default_pipeline.py +1095 -0
  182. cars/pipelines/filling/__init__.py +26 -0
  183. cars/pipelines/filling/filling.py +981 -0
  184. cars/pipelines/formatting/__init__.py +26 -0
  185. cars/pipelines/formatting/formatting.py +190 -0
  186. cars/pipelines/merging/__init__.py +26 -0
  187. cars/pipelines/merging/merging.py +439 -0
  188. cars/pipelines/parameters/__init__.py +0 -0
  189. cars/pipelines/parameters/advanced_parameters.py +256 -0
  190. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  191. cars/pipelines/parameters/application_parameters.py +72 -0
  192. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  193. cars/pipelines/parameters/dsm_inputs.py +349 -0
  194. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  195. cars/pipelines/parameters/output_constants.py +52 -0
  196. cars/pipelines/parameters/output_parameters.py +435 -0
  197. cars/pipelines/parameters/sensor_inputs.py +859 -0
  198. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  199. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  200. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  202. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  204. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  206. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  207. cars/pipelines/pipeline.py +119 -0
  208. cars/pipelines/pipeline_constants.py +38 -0
  209. cars/pipelines/pipeline_template.py +135 -0
  210. cars/pipelines/subsampling/__init__.py +26 -0
  211. cars/pipelines/subsampling/subsampling.py +358 -0
  212. cars/pipelines/surface_modeling/__init__.py +26 -0
  213. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  214. cars/pipelines/tie_points/__init__.py +26 -0
  215. cars/pipelines/tie_points/tie_points.py +536 -0
  216. cars/starter.py +167 -0
  217. cars-1.0.0rc3.dist-info/METADATA +289 -0
  218. cars-1.0.0rc3.dist-info/RECORD +220 -0
  219. cars-1.0.0rc3.dist-info/WHEEL +6 -0
  220. cars-1.0.0rc3.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,639 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ # pylint: disable=too-many-lines
21
+ """
22
+ CARS dsm inputs
23
+ """
24
+
25
+ import collections
26
+ import logging
27
+ import os
28
+
29
+ import numpy as np
30
+ import rasterio
31
+ import xarray as xr
32
+ from affine import Affine
33
+ from json_checker import Checker
34
+ from rasterio.windows import from_bounds
35
+
36
+ # CARS imports
37
+ import cars.orchestrator.orchestrator as ocht
38
+ from cars.applications.rasterization.rasterization_wrappers import (
39
+ update_data,
40
+ update_weights,
41
+ )
42
+ from cars.core import constants as cst
43
+ from cars.core import inputs, preprocessing, tiling
44
+ from cars.core.utils import safe_makedirs
45
+ from cars.data_structures import cars_dataset
46
+
47
+ from .abstract_dsm_merging_app import DsmMerging
48
+
49
+
50
+ class WeightedFusion(DsmMerging, short_name="weighted_fusion"):
51
+ """
52
+ DSM merging app
53
+ """
54
+
55
+ def __init__(self, conf=None):
56
+ """
57
+ Init function of BulldozerFilling
58
+
59
+ :param conf: configuration for BulldozerFilling
60
+ :return: an application_to_use object
61
+ """
62
+ super().__init__(conf=conf)
63
+
64
+ # check conf
65
+ self.used_method = self.used_config["method"]
66
+ self.tile_size = self.used_config["tile_size"]
67
+ self.save_intermediate_data = self.used_config["save_intermediate_data"]
68
+
69
+ def check_conf(self, conf):
70
+
71
+ # init conf
72
+ if conf is not None:
73
+ overloaded_conf = conf.copy()
74
+ else:
75
+ conf = {}
76
+ overloaded_conf = {}
77
+
78
+ # Overload conf
79
+ overloaded_conf["method"] = conf.get("method", "weighted_fusion")
80
+ overloaded_conf["tile_size"] = conf.get("tile_size", 4000)
81
+ overloaded_conf["save_intermediate_data"] = conf.get(
82
+ "save_intermediate_data", False
83
+ )
84
+
85
+ rectification_schema = {
86
+ "method": str,
87
+ "tile_size": int,
88
+ "save_intermediate_data": bool,
89
+ }
90
+
91
+ # Check conf
92
+ checker = Checker(rectification_schema)
93
+ checker.validate(overloaded_conf)
94
+
95
+ return overloaded_conf
96
+
97
+ # pylint: disable=too-many-positional-arguments
98
+ def run( # noqa: C901
99
+ self,
100
+ dict_path,
101
+ orchestrator,
102
+ roi_poly,
103
+ dump_dir=None,
104
+ dsm_file_name=None,
105
+ color_file_name=None,
106
+ classif_file_name=None,
107
+ filling_file_name=None,
108
+ performance_map_file_name=None,
109
+ ambiguity_file_name=None,
110
+ contributing_pair_file_name=None,
111
+ ):
112
+ """
113
+ Merge all the dsms
114
+
115
+ :param dict_path: path of all variables from all dsms
116
+ :type dict_path: dict
117
+ :param orchestrator: orchestrator used
118
+ :param dump_dir: output path
119
+ :type dump_dir: str
120
+ :param dsm_file_name: name of the dsm output file
121
+ :type dsm_file_name: str
122
+ :param color_file_name: name of the color output file
123
+ :type color_file_name: str
124
+ :param classif_file_name: name of the classif output file
125
+ :type classif_file_name: str
126
+ :param filling_file_name: name of the filling output file
127
+ :type filling_file_name: str
128
+ :param performance_map_file_name: name of the performance_map file
129
+ :type performance_map_file_name: str
130
+ :param ambiguity_file_name: name of the ambiguity output file
131
+ :type ambiguity_file_name: str
132
+ :param contributing_pair_file_name: name of contributing_pair file
133
+ :type contributing_pair_file_name: str
134
+
135
+ :return: raster DSM. CarsDataset contains:
136
+
137
+ - Z x W Delayed tiles. \
138
+ Each tile will be a future xarray Dataset containing:
139
+
140
+ - data : with keys : "hgt", "img", "raster_msk",optional : \
141
+ "n_pts", "pts_in_cell", "hgt_mean", "hgt_stdev",\
142
+ "hgt_inf", "hgt_sup"
143
+ - attrs with keys: "epsg"
144
+ - attributes containing: None
145
+
146
+ :rtype : CarsDataset filled with xr.Dataset
147
+ """
148
+
149
+ # Create CarsDataset
150
+ terrain_raster = cars_dataset.CarsDataset(
151
+ "arrays", name="rasterization"
152
+ )
153
+
154
+ # find the global bounds of the dataset
155
+ dsm_nodata = None
156
+ epsg = None
157
+ resolution = None
158
+ for index, path in enumerate(dict_path["dsm"]):
159
+ with rasterio.open(path) as src:
160
+ if index == 0:
161
+ bounds = src.bounds
162
+ global_bounds = bounds
163
+ profile = src.profile
164
+ transform = list(profile["transform"])
165
+ res_x = transform[0]
166
+ res_y = transform[4]
167
+ resolution = (res_y, res_x)
168
+
169
+ epsg = src.crs
170
+
171
+ dsm_nodata = src.nodata
172
+ else:
173
+ bounds = src.bounds
174
+ global_bounds = (
175
+ min(bounds[0], global_bounds[0]), # xmin
176
+ min(bounds[1], global_bounds[1]), # ymin
177
+ max(bounds[2], global_bounds[2]), # xmax
178
+ max(bounds[3], global_bounds[3]), # ymax
179
+ )
180
+
181
+ if roi_poly is not None:
182
+ global_bounds = preprocessing.crop_terrain_bounds_with_roi(
183
+ roi_poly,
184
+ global_bounds[0],
185
+ global_bounds[1],
186
+ global_bounds[2],
187
+ global_bounds[3],
188
+ )
189
+
190
+ # Tiling of the dataset
191
+ [xmin, ymin, xmax, ymax] = global_bounds
192
+
193
+ terrain_raster.tiling_grid = tiling.generate_tiling_grid(
194
+ xmin,
195
+ ymin,
196
+ xmax,
197
+ ymax,
198
+ self.tile_size,
199
+ self.tile_size,
200
+ )
201
+
202
+ xsize, ysize = tiling.roi_to_start_and_size(
203
+ global_bounds, resolution[1]
204
+ )[2:]
205
+
206
+ # build the tranform of the dataset
207
+ # Generate profile
208
+ geotransform = (
209
+ global_bounds[0],
210
+ resolution[1],
211
+ 0.0,
212
+ global_bounds[3],
213
+ 0.0,
214
+ -resolution[1],
215
+ )
216
+
217
+ transform = Affine.from_gdal(*geotransform)
218
+ raster_profile = collections.OrderedDict(
219
+ {
220
+ "height": ysize,
221
+ "width": xsize,
222
+ "driver": "GTiff",
223
+ "dtype": "float32",
224
+ "transform": transform,
225
+ "crs": "EPSG:{}".format(epsg),
226
+ "tiled": True,
227
+ "no_data": dsm_nodata,
228
+ }
229
+ )
230
+
231
+ # Get sources pc
232
+ full_sources_band_descriptions = None
233
+ if cst.DSM_SOURCE_PC in list(dict_path.keys()):
234
+ full_sources_band_descriptions = []
235
+ for source_pc in dict_path[cst.DSM_SOURCE_PC]:
236
+ full_sources_band_descriptions += list(
237
+ inputs.get_descriptions_bands(source_pc)
238
+ )
239
+
240
+ # remove copies
241
+ full_sources_band_descriptions = list(
242
+ dict.fromkeys(full_sources_band_descriptions)
243
+ )
244
+
245
+ # Setup dump directory
246
+ if dump_dir is not None:
247
+ out_dump_dir = dump_dir
248
+ safe_makedirs(out_dump_dir)
249
+ else:
250
+ out_dump_dir = orchestrator.out_dir
251
+
252
+ if dsm_file_name is not None:
253
+ safe_makedirs(os.path.dirname(dsm_file_name))
254
+
255
+ # Save all file that are in inputs
256
+ for key in dict_path.keys():
257
+ if key in (cst.DSM_ALT, cst.DSM_COLOR, cst.DSM_WEIGHTS_SUM):
258
+ option = False
259
+ else:
260
+ option = True
261
+
262
+ if key == cst.DSM_ALT and dsm_file_name is not None:
263
+ out_file_name = dsm_file_name
264
+ elif key == cst.DSM_COLOR and color_file_name is not None:
265
+ out_file_name = color_file_name
266
+ elif key == cst.DSM_CLASSIF and classif_file_name is not None:
267
+ out_file_name = classif_file_name
268
+ elif key == cst.DSM_FILLING and filling_file_name is not None:
269
+ out_file_name = filling_file_name
270
+ elif (
271
+ key == cst.DSM_PERFORMANCE_MAP
272
+ and performance_map_file_name is not None
273
+ ):
274
+ out_file_name = performance_map_file_name
275
+ elif key == cst.DSM_AMBIGUITY and ambiguity_file_name is not None:
276
+ out_file_name = ambiguity_file_name
277
+ elif (
278
+ key == cst.DSM_SOURCE_PC
279
+ and contributing_pair_file_name is not None
280
+ ):
281
+ out_file_name = contributing_pair_file_name
282
+ else:
283
+ out_file_name = os.path.join(out_dump_dir, key + ".tif")
284
+
285
+ orchestrator.add_to_save_lists(
286
+ out_file_name,
287
+ key,
288
+ terrain_raster,
289
+ dtype=inputs.rasterio_get_dtype(dict_path[key][0]),
290
+ nodata=inputs.rasterio_get_nodata(dict_path[key][0]),
291
+ cars_ds_name=key,
292
+ optional_data=option,
293
+ )
294
+
295
+ [saving_info] = orchestrator.get_saving_infos([terrain_raster])
296
+ logging.info(
297
+ "Merge DSM info in {} x {} tiles".format(
298
+ terrain_raster.shape[0], terrain_raster.shape[1]
299
+ )
300
+ )
301
+ for col in range(terrain_raster.shape[1]):
302
+ for row in range(terrain_raster.shape[0]):
303
+ # update saving infos for potential replacement
304
+ full_saving_info = ocht.update_saving_infos(
305
+ saving_info, row=row, col=col
306
+ )
307
+
308
+ # Delayed call to dsm merging operations using all
309
+ terrain_raster[row, col] = orchestrator.cluster.create_task(
310
+ dsm_merging_wrapper, nout=1
311
+ )(
312
+ dict_path,
313
+ terrain_raster.tiling_grid[row, col],
314
+ resolution,
315
+ raster_profile,
316
+ full_saving_info,
317
+ full_sources_band_descriptions,
318
+ )
319
+
320
+ return terrain_raster
321
+
322
+
323
+ def dsm_merging_wrapper( # pylint: disable=too-many-positional-arguments # noqa C901
324
+ dict_path,
325
+ tile_bounds,
326
+ resolution,
327
+ profile,
328
+ saving_info=None,
329
+ full_sources_band_descriptions=None,
330
+ ):
331
+ """
332
+ Merge all the variables
333
+
334
+ :param dict_path: path of all variables from all dsms
335
+ :type dict_path: dict
336
+ :param tile_bounds: list of tiles coordinates
337
+ :type tile_bounds: list
338
+ :param resolution: resolution of the dsms
339
+ :type resolution: list
340
+ :param profile: profile of the global dsm
341
+ :type profile: OrderedDict
342
+ :saving_info: the saving infos
343
+ """
344
+
345
+ # create the tile dataset
346
+ x_value = np.arange(tile_bounds[0], tile_bounds[1], resolution[1])
347
+ y_value = np.arange(tile_bounds[2], tile_bounds[3], resolution[1])
348
+ height = len(y_value)
349
+ width = len(x_value)
350
+
351
+ dataset = xr.Dataset(
352
+ data_vars={},
353
+ coords={
354
+ "y": y_value,
355
+ "x": x_value,
356
+ },
357
+ )
358
+
359
+ # calculate the bounds intersection between each path
360
+ list_intersection = []
361
+
362
+ for path in dict_path["dsm"]:
363
+ with rasterio.open(path) as src:
364
+ intersect_bounds = (
365
+ max(tile_bounds[0], src.bounds.left), # xmin
366
+ max(tile_bounds[2], src.bounds.bottom), # ymin
367
+ min(tile_bounds[1], src.bounds.right), # xmax
368
+ min(tile_bounds[3], src.bounds.top), # ymax
369
+ )
370
+
371
+ if (
372
+ intersect_bounds[0] < intersect_bounds[2]
373
+ and intersect_bounds[1] < intersect_bounds[3]
374
+ ):
375
+ list_intersection.append(intersect_bounds)
376
+ else:
377
+ list_intersection.append("no intersection")
378
+
379
+ # Update the data
380
+ for key in dict_path.keys():
381
+ # Choose the method regarding the variable
382
+ if key in [cst.DSM_NB_PTS, cst.DSM_NB_PTS_IN_CELL]:
383
+ method = "sum"
384
+ elif key in [
385
+ cst.DSM_SOURCE_PC,
386
+ ]:
387
+ method = "bool"
388
+ elif key in [
389
+ cst.DSM_FILLING,
390
+ cst.DSM_CLASSIF,
391
+ ]:
392
+ method = "max"
393
+ else:
394
+ method = "basic"
395
+
396
+ # take band description information
397
+ band_descriptions = list(
398
+ inputs.get_descriptions_bands(dict_path[key][0])
399
+ )
400
+ nb_bands = inputs.rasterio_get_nb_bands(dict_path[key][0])
401
+ if len(band_descriptions) == 0:
402
+ band_descriptions = []
403
+ elif (
404
+ key
405
+ in [
406
+ cst.DSM_COLOR,
407
+ cst.DSM_SOURCE_PC,
408
+ ]
409
+ and None in band_descriptions
410
+ ):
411
+ band_descriptions = [
412
+ str(current_band) for current_band in range(nb_bands)
413
+ ]
414
+
415
+ # Define the dimension of the data in the dataset
416
+ if key == cst.DSM_COLOR:
417
+ dataset.coords[cst.BAND_IM] = (cst.BAND_IM, band_descriptions)
418
+ dim = [cst.BAND_IM, cst.Y, cst.X]
419
+ elif key == cst.DSM_SOURCE_PC:
420
+ dataset.coords[cst.BAND_SOURCE_PC] = (
421
+ cst.BAND_SOURCE_PC,
422
+ full_sources_band_descriptions,
423
+ )
424
+ dim = [cst.BAND_SOURCE_PC, cst.Y, cst.X]
425
+ else:
426
+ dim = [cst.Y, cst.X]
427
+
428
+ # Update data
429
+ if key == cst.DSM_ALT:
430
+ # Update dsm_value and weights once
431
+ value, weights = assemblage(
432
+ dict_path[key],
433
+ dict_path[cst.DSM_WEIGHTS_SUM],
434
+ method,
435
+ list_intersection,
436
+ tile_bounds,
437
+ height,
438
+ width,
439
+ band_descriptions,
440
+ )
441
+
442
+ dataset[key] = (dim, value)
443
+ dataset[cst.DSM_WEIGHTS_SUM] = (dim, weights)
444
+ elif key == cst.DSM_SOURCE_PC:
445
+ value, _ = assemblage(
446
+ dict_path[key],
447
+ dict_path[cst.DSM_WEIGHTS_SUM],
448
+ method,
449
+ list_intersection,
450
+ tile_bounds,
451
+ height,
452
+ width,
453
+ full_sources_band_descriptions,
454
+ merge_sources=True,
455
+ )
456
+ dataset[key] = (dim, value)
457
+ elif key != cst.DSM_WEIGHTS_SUM:
458
+ # Update other variables
459
+ value, _ = assemblage(
460
+ dict_path[key],
461
+ dict_path[cst.DSM_WEIGHTS_SUM],
462
+ method,
463
+ list_intersection,
464
+ tile_bounds,
465
+ height,
466
+ width,
467
+ band_descriptions,
468
+ )
469
+
470
+ dataset[key] = (dim, value)
471
+
472
+ # add performance map classes
473
+ if key == cst.DSM_PERFORMANCE_MAP:
474
+ perf_map_classes = inputs.rasterio_get_tags(dict_path[key][0])[
475
+ "CLASSES"
476
+ ]
477
+ dataset.attrs[cst.RIO_TAG_PERFORMANCE_MAP_CLASSES] = (
478
+ perf_map_classes
479
+ )
480
+
481
+ # Define the tile transform
482
+ bounds = [tile_bounds[0], tile_bounds[2], tile_bounds[1], tile_bounds[3]]
483
+ xstart, ystart, xsize, ysize = tiling.roi_to_start_and_size(
484
+ bounds, resolution[1]
485
+ )
486
+ transform = rasterio.Affine(*profile["transform"][0:6])
487
+
488
+ row_pix_pos, col_pix_pos = rasterio.transform.AffineTransformer(
489
+ transform
490
+ ).rowcol(xstart, ystart)
491
+ window = [
492
+ row_pix_pos,
493
+ row_pix_pos + ysize,
494
+ col_pix_pos,
495
+ col_pix_pos + xsize,
496
+ ]
497
+
498
+ window = cars_dataset.window_array_to_dict(window)
499
+
500
+ # Fill dataset
501
+ cars_dataset.fill_dataset(
502
+ dataset,
503
+ saving_info=saving_info,
504
+ window=window,
505
+ profile=profile,
506
+ overlaps=None,
507
+ )
508
+
509
+ return dataset
510
+
511
+
512
+ def assemblage( # pylint: disable=too-many-positional-arguments
513
+ out,
514
+ current_weights,
515
+ method,
516
+ intersect_bounds,
517
+ tile_bounds,
518
+ height,
519
+ width,
520
+ band_descriptions=None,
521
+ merge_sources=False,
522
+ ):
523
+ """
524
+ Update data
525
+
526
+ :param out: the data to update
527
+ :type out: list of path
528
+ :param current_weights: the current weights of the data
529
+ :type current_weights: list of path
530
+ :param method: the method used to update the data
531
+ :type method: str
532
+ :param intersect_bounds: the bounds intersection
533
+ :type intersect_bounds: list of bounds
534
+ :param height: the height of the tile
535
+ :type height: int
536
+ :param width: the width of the tile
537
+ :type width: int
538
+ :param band_descriptions: the band description of the data
539
+ :type band_descriptions: str of list
540
+ :param merge_sources: merge source pc, using full band_description
541
+ :type merge_sources: bool
542
+
543
+ """
544
+ # Initialize the tile
545
+ if merge_sources:
546
+ nb_bands = len(band_descriptions)
547
+ else:
548
+ nb_bands = inputs.rasterio_get_nb_bands(out[0])
549
+ dtype = inputs.rasterio_get_dtype(out[0])
550
+ nodata = inputs.rasterio_get_nodata(out[0])
551
+
552
+ if band_descriptions[0] is not None:
553
+ tile = np.full((nb_bands, height, width), nodata, dtype=dtype)
554
+ else:
555
+ tile = np.full((height, width), nodata, dtype=dtype)
556
+
557
+ # Initialize the weights
558
+ weights = np.full((height, width), 0, dtype=dtype)
559
+
560
+ for idx, path in enumerate(out):
561
+ with (
562
+ rasterio.open(path) as src,
563
+ rasterio.open(current_weights[idx]) as drt,
564
+ ):
565
+ if intersect_bounds[idx] != "no intersection":
566
+ # Build the window
567
+ window = from_bounds(
568
+ *intersect_bounds[idx], transform=src.transform
569
+ )
570
+
571
+ # Extract the data
572
+ current_nb_bands = src.count
573
+ if current_nb_bands > 1:
574
+ data = src.read(window=window)
575
+ _, rows, cols = data.shape
576
+ else:
577
+ data = src.read(1, window=window)
578
+ rows, cols = data.shape
579
+
580
+ indexes = list(range(current_nb_bands))
581
+ if merge_sources:
582
+ # Extract current band description
583
+ current_band_descriptions = list(src.descriptions)
584
+ # Get position
585
+ indexes = []
586
+ for current_band in current_band_descriptions:
587
+ indexes.append(band_descriptions.index(current_band))
588
+
589
+ current_weights_window = drt.read(1, window=window)
590
+
591
+ # Calculate the x and y offset because the current_data
592
+ # doesn't equal to the entire tile
593
+ x_offset = int(
594
+ (intersect_bounds[idx][0] - tile_bounds[0])
595
+ / np.abs(src.res[0])
596
+ )
597
+ y_offset = int(
598
+ (tile_bounds[3] - intersect_bounds[idx][3])
599
+ / np.abs(src.res[1])
600
+ )
601
+
602
+ if cols > 0 and rows > 0:
603
+ tab_x = np.arange(x_offset, x_offset + cols)
604
+
605
+ tab_y = np.arange(y_offset, y_offset + rows)
606
+
607
+ # Update data
608
+ if band_descriptions[0] is not None:
609
+
610
+ tile[np.ix_(indexes, tab_y, tab_x)] = np.reshape(
611
+ update_data(
612
+ tile[np.ix_(indexes, tab_y, tab_x)],
613
+ data,
614
+ current_weights_window,
615
+ weights[np.ix_(tab_y, tab_x)],
616
+ nodata,
617
+ method=method,
618
+ ),
619
+ tile[np.ix_(indexes, tab_y, tab_x)].shape,
620
+ )
621
+ else:
622
+ tile[np.ix_(tab_y, tab_x)] = np.reshape(
623
+ update_data(
624
+ tile[np.ix_(tab_y, tab_x)],
625
+ data,
626
+ current_weights_window,
627
+ weights[np.ix_(tab_y, tab_x)],
628
+ nodata,
629
+ method=method,
630
+ ),
631
+ tile[np.ix_(tab_y, tab_x)].shape,
632
+ )
633
+
634
+ # Update weights
635
+ weights[np.ix_(tab_y, tab_x)] = update_weights(
636
+ weights[np.ix_(tab_y, tab_x)], current_weights_window
637
+ )
638
+
639
+ return tile, weights
@@ -0,0 +1,30 @@
1
+ # !/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ """
22
+ CARS grid_correction module init file
23
+ """
24
+ # flake8: noqa: F401
25
+
26
+ from cars.applications.grid_correction.abstract_grid_correction_app import (
27
+ GridCorrection,
28
+ )
29
+
30
+ from . import grid_correction_app