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,593 @@
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 pandora loader file
23
+ """
24
+
25
+ import copy
26
+ import json
27
+ import logging
28
+ import os
29
+ from collections import OrderedDict
30
+ from typing import Dict
31
+
32
+ import numpy as np
33
+ import pandora
34
+ import rasterio
35
+ import xarray as xr
36
+ from json_checker import Checker, Or
37
+ from pandora.check_configuration import (
38
+ check_pipeline_section,
39
+ concat_conf,
40
+ get_config_pipeline,
41
+ update_conf,
42
+ )
43
+ from pandora.state_machine import PandoraMachine
44
+ from rasterio.mask import mask
45
+ from shapely.geometry import mapping
46
+
47
+ from cars.core.projection import polygon_projection
48
+ from cars.orchestrator.cluster.log_wrapper import cars_profile
49
+
50
+
51
+ class PandoraLoader:
52
+ """
53
+ PandoraLoader
54
+
55
+ """
56
+
57
+ def __init__( # pylint: disable=too-many-positional-arguments # noqa: C901
58
+ self,
59
+ conf=None,
60
+ method_name=None,
61
+ generate_performance_map_from_risk=False,
62
+ generate_performance_map_from_intervals=False,
63
+ generate_ambiguity=False,
64
+ perf_eta_max_ambiguity=0.99,
65
+ perf_eta_max_risk=0.25,
66
+ perf_eta_step=0.04,
67
+ use_cross_validation=True,
68
+ denoise_disparity_map=False,
69
+ used_band="b0",
70
+ ):
71
+ """
72
+ Init function of PandoraLoader
73
+
74
+ If conf is profided, pandora will use it
75
+ If not, Pandora will use intern configuration :
76
+ census or mccnn, depending on method_name
77
+
78
+ :param conf: configuration of pandora to use
79
+ :type conf: dict
80
+ :param method_name: name of method to use
81
+ :param performance_map_conf: true if generate performance maps
82
+ :param use_cross_validation: true to add crossvalidation
83
+ :param denoise_disparity_map: true to add the disparity denoiser filter
84
+ :param used_band: name of band used for correlation
85
+ :type used_band: str
86
+ """
87
+
88
+ if method_name is None:
89
+ method_name = "census_sgm_default"
90
+
91
+ self.pandora_config = None
92
+
93
+ uses_cars_pandora_conf = False
94
+
95
+ if isinstance(conf, str):
96
+ # load file
97
+ with open(conf, "r", encoding="utf8") as fstream:
98
+ conf = json.load(fstream)
99
+
100
+ elif conf is None:
101
+ uses_cars_pandora_conf = True
102
+ package_path = os.path.dirname(__file__)
103
+
104
+ if method_name == "mccnn_sgm":
105
+ # Use mccn_conf
106
+
107
+ conf_file_path = os.path.join(package_path, "config_mccnn.json")
108
+ # Read conf
109
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
110
+ conf = json.load(fstream)
111
+ elif method_name == "census_sgm_urban":
112
+ # Use census sgm conf
113
+ conf_file_path = os.path.join(
114
+ package_path, "config_census_sgm_urban.json"
115
+ )
116
+ # read conf
117
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
118
+ conf = json.load(fstream)
119
+ elif method_name == "census_sgm_shadow":
120
+ # Use census sgm conf
121
+ conf_file_path = os.path.join(
122
+ package_path, "config_census_sgm_shadow.json"
123
+ )
124
+ # read conf
125
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
126
+ conf = json.load(fstream)
127
+ elif method_name == "census_sgm_mountain_and_vegetation":
128
+ # Use census sgm conf
129
+ conf_file_path = os.path.join(
130
+ package_path,
131
+ "config_census_sgm_mountain_and_vegetation.json",
132
+ )
133
+ # read conf
134
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
135
+ conf = json.load(fstream)
136
+ elif method_name == "census_sgm_homogeneous":
137
+ # Use census sgm conf
138
+ conf_file_path = os.path.join(
139
+ package_path, "config_census_sgm_homogeneous.json"
140
+ )
141
+ # read conf
142
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
143
+ conf = json.load(fstream)
144
+ elif method_name in ("census_sgm_default", "auto"):
145
+ # Use census sgm conf
146
+ conf_file_path = os.path.join(
147
+ package_path, "config_census_sgm_default.json"
148
+ )
149
+ # read conf
150
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
151
+ conf = json.load(fstream)
152
+ elif method_name == "census_sgm_sparse":
153
+ # Use census sgm conf
154
+ conf_file_path = os.path.join(
155
+ package_path, "config_census_sgm_sparse.json"
156
+ )
157
+ # read conf
158
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
159
+ conf = json.load(fstream)
160
+ else:
161
+ logging.error(
162
+ "No method named {} in pandora loader".format(method_name)
163
+ )
164
+ raise NameError(
165
+ "No method named {} in pandora loader".format(method_name)
166
+ )
167
+
168
+ perf_ambiguity_conf = {
169
+ "cost_volume_confidence.cars_1": {
170
+ "confidence_method": "ambiguity",
171
+ "eta_max": perf_eta_max_ambiguity,
172
+ "eta_step": perf_eta_step,
173
+ }
174
+ }
175
+
176
+ perf_risk_conf = {
177
+ "cost_volume_confidence.cars_2": {
178
+ "confidence_method": "risk",
179
+ "eta_max": perf_eta_max_risk,
180
+ "eta_step": perf_eta_step,
181
+ }
182
+ }
183
+ intervals_conf = {
184
+ "cost_volume_confidence.cars_3": {
185
+ "confidence_method": "interval_bounds",
186
+ }
187
+ }
188
+ # Cross validation
189
+ cross_validation_acc_conf = {
190
+ "validation": {
191
+ "validation_method": "cross_checking_accurate",
192
+ "cross_checking_threshold": 1.0,
193
+ }
194
+ }
195
+
196
+ cross_validation_fast_conf = {
197
+ "validation": {
198
+ "validation_method": "cross_checking_fast",
199
+ }
200
+ }
201
+
202
+ disparity_denoiser_conf = {
203
+ "filter": {"filter_method": "disparity_denoiser"}
204
+ }
205
+
206
+ confidences = {}
207
+ if generate_performance_map_from_risk:
208
+ confidences.update(perf_ambiguity_conf)
209
+ confidences.update(perf_risk_conf)
210
+ if generate_performance_map_from_intervals:
211
+ confidences.update(perf_ambiguity_conf)
212
+ confidences.update(intervals_conf)
213
+
214
+ if generate_ambiguity:
215
+ confidences.update(perf_ambiguity_conf)
216
+
217
+ if confidences:
218
+ conf["pipeline"] = overload_pandora_conf_with_confidence(
219
+ conf["pipeline"], confidences
220
+ )
221
+
222
+ # update with cross validation
223
+ if "validation" not in conf["pipeline"]:
224
+ if use_cross_validation in (True, "fast"):
225
+ conf["pipeline"].update(cross_validation_fast_conf)
226
+ elif use_cross_validation == "accurate":
227
+ conf["pipeline"].update(cross_validation_acc_conf)
228
+
229
+ if (
230
+ denoise_disparity_map
231
+ and conf["pipeline"]["filter"]["filter_method"]
232
+ != "disparity_denoiser"
233
+ ):
234
+ conf["pipeline"].update(disparity_denoiser_conf)
235
+
236
+ if "band" not in conf["pipeline"]["matching_cost"]:
237
+ conf["pipeline"]["matching_cost"]["band"] = used_band
238
+
239
+ if generate_performance_map_from_intervals:
240
+ # To ensure the consistency between the disparity map
241
+ # and the intervals, the median filter for intervals
242
+ # must be similar to the median filter. The filter is
243
+ # added at the end of the conf as it is applied during
244
+ # the disp_map state.
245
+ try:
246
+ filter_size = conf["pipeline"]["filter"]["filter_size"]
247
+ except KeyError:
248
+ filter_size = 3
249
+
250
+ conf_filter_interval = {
251
+ "filter.cars_3": {
252
+ "filter_method": "median_for_intervals",
253
+ "filter_size": filter_size,
254
+ "interval_indicator": "cars_3",
255
+ "regularization": True,
256
+ "ambiguity_indicator": "cars_1",
257
+ }
258
+ }
259
+ pipeline_dict = OrderedDict()
260
+ pipeline_dict.update(conf["pipeline"])
261
+ # Filter is placed after validation in config
262
+ # and should be placed before.
263
+ # However it does not have any incidence on operation
264
+ if uses_cars_pandora_conf:
265
+ pipeline_dict.update(conf_filter_interval)
266
+
267
+ conf["pipeline"] = pipeline_dict
268
+
269
+ if "filter" in conf["pipeline"]:
270
+ filter_conf = conf["pipeline"]["filter"]
271
+ if filter_conf["filter_method"] == "disparity_denoiser":
272
+ if "band" not in filter_conf:
273
+ conf["pipeline"]["filter"]["band"] = used_band
274
+
275
+ # Check conf
276
+ self.pandora_config = conf
277
+
278
+ def get_conf(self):
279
+ """
280
+ Get pandora configuration used
281
+
282
+ :return: pandora configuration
283
+ :rtype: dict
284
+
285
+ """
286
+
287
+ return self.pandora_config
288
+
289
+ def get_classif_bands(self):
290
+ """
291
+ Get the classification bands used in the pandora configuration
292
+
293
+ :return: list of classification bands
294
+ """
295
+
296
+ classif_bands = []
297
+
298
+ def search_classes_recursive(obj):
299
+ """
300
+ Recursive search of keys containing 'classes' in the configuration
301
+ """
302
+ if isinstance(obj, dict):
303
+ for key, value in obj.items():
304
+ if "classes" in key.lower():
305
+ if isinstance(value, list):
306
+ classif_bands.extend(value)
307
+ elif value is not None:
308
+ classif_bands.append(value)
309
+ # Continue recursive search
310
+ search_classes_recursive(value)
311
+
312
+ search_classes_recursive(self.pandora_config)
313
+
314
+ # Remove duplicates and return the list
315
+ return list(set(classif_bands))
316
+
317
+ @cars_profile(name="Find auto conf")
318
+ def find_auto_conf(
319
+ self, intersection_poly, land_cover_map, classif_to_config_mapping, epsg
320
+ ):
321
+ """
322
+ Find the configuration that suits the most on the
323
+ land cover map based on the roi
324
+ """
325
+ package_path = os.path.dirname(__file__)
326
+
327
+ # construct the path to the land_cover_map
328
+ if os.path.dirname(land_cover_map) == "":
329
+ land_cover_map_path = os.path.join(package_path, land_cover_map)
330
+ else:
331
+ land_cover_map_path = land_cover_map
332
+
333
+ with rasterio.open(land_cover_map_path) as src:
334
+ # Project the polygon to the right epsg
335
+ if src.crs != epsg:
336
+ poly = polygon_projection(
337
+ intersection_poly, epsg, src.crs.to_epsg()
338
+ )
339
+ else:
340
+ poly = intersection_poly
341
+
342
+ # Use a buffer because the land_cover_map resolution is coarse
343
+ data_land_cover, _ = mask(
344
+ src, [mapping(poly)], crop=True, all_touched=True
345
+ )
346
+
347
+ # Find the most common class in the roi
348
+ data_squeeze = data_land_cover.squeeze()
349
+ valid_data = data_squeeze[data_squeeze != src.nodata]
350
+
351
+ most_common_class = None
352
+ if valid_data.size > 0:
353
+ classes, counts = np.unique(valid_data, return_counts=True)
354
+ max_index = np.argmax(counts)
355
+ most_common_class = classes[max_index]
356
+
357
+ # Construct the path to the classification to configuration mapping
358
+ if os.path.dirname(classif_to_config_mapping) == "":
359
+ conf_file_path = os.path.join(
360
+ package_path, classif_to_config_mapping
361
+ )
362
+ else:
363
+ conf_file_path = classif_to_config_mapping
364
+
365
+ # read conf
366
+ with open(conf_file_path, "r", encoding="utf8") as fstream:
367
+ conf_mapping = json.load(fstream)
368
+
369
+ # Find the configuration that corresponds to the most common class
370
+ corresponding_conf_name = conf_mapping.get(str(most_common_class), None)
371
+
372
+ # If no equivalence has been found, we use the default configuration
373
+ if corresponding_conf_name is None:
374
+ corresponding_conf_name = "census_sgm_default"
375
+
376
+ logging.info(
377
+ "The conf that has been chosen regarding the "
378
+ "world classification map is {}".format(corresponding_conf_name)
379
+ )
380
+
381
+ # We return the corresponding configuration
382
+ json_conf_name = os.path.join(
383
+ package_path, "config_" + corresponding_conf_name + ".json"
384
+ )
385
+ with open(json_conf_name, "r", encoding="utf8") as fstream:
386
+ conf = json.load(fstream)
387
+
388
+ return conf
389
+
390
+ def check_conf( # pylint: disable=too-many-positional-arguments
391
+ self,
392
+ user_cfg,
393
+ nodata_left,
394
+ nodata_right,
395
+ bands_left,
396
+ bands_right,
397
+ bands_classif_left=None,
398
+ bands_classif_right=None,
399
+ ):
400
+ """
401
+ Check configuration
402
+
403
+ :param user_cfg: configuration
404
+ :type user_cfg: dict
405
+
406
+ :return: pandora configuration
407
+ :rtype: dict
408
+
409
+ """
410
+ # Import plugins before checking configuration
411
+ pandora.import_plugin()
412
+ # Check configuration and update the configuration with default values
413
+ # Instantiate pandora state machine
414
+ pandora_machine = PandoraMachine()
415
+ # check pipeline
416
+ metadata_left = overide_pandora_get_metadata(
417
+ bands_left, classif_bands=bands_classif_left
418
+ )
419
+ metadata_right = overide_pandora_get_metadata(
420
+ bands_right, classif_bands=bands_classif_right
421
+ )
422
+
423
+ metadata_left = metadata_left.assign_coords(band_im=bands_left)
424
+ metadata_right = metadata_right.assign_coords(band_im=bands_right)
425
+
426
+ user_cfg_pipeline = get_config_pipeline(user_cfg)
427
+ saved_schema = copy.deepcopy(
428
+ pandora.matching_cost.matching_cost.AbstractMatchingCost.schema
429
+ )
430
+ cfg_pipeline = check_pipeline_section(
431
+ user_cfg_pipeline, metadata_left, metadata_right, pandora_machine
432
+ )
433
+ # quick fix to remove when the problem is solved in pandora
434
+ pandora.matching_cost.matching_cost.AbstractMatchingCost.schema = (
435
+ saved_schema
436
+ )
437
+ # check a part of input section
438
+ user_cfg_input = get_config_input_custom_cars(
439
+ user_cfg, nodata_left, nodata_right
440
+ )
441
+ cfg_input = check_input_section_custom_cars(user_cfg_input)
442
+ # concatenate updated config
443
+ cfg = concat_conf([cfg_input, cfg_pipeline])
444
+
445
+ return cfg
446
+
447
+
448
+ input_configuration_schema_custom_cars = {
449
+ "nodata_left": Or(
450
+ int, lambda x: np.isnan(x) # pylint: disable=unnecessary-lambda
451
+ ),
452
+ "nodata_right": Or(
453
+ int, lambda x: np.isnan(x) # pylint: disable=unnecessary-lambda
454
+ ),
455
+ }
456
+
457
+ default_short_configuration_input_custom_cars = {
458
+ "input": {
459
+ "nodata_left": -9999,
460
+ "nodata_right": -9999,
461
+ }
462
+ }
463
+
464
+
465
+ def overide_pandora_get_metadata(
466
+ im_bands: list, classif_bands: list = None
467
+ ) -> xr.Dataset:
468
+ """
469
+ Read metadata from image, and return the corresponding xarray.DataSet
470
+
471
+ :param im_bands: list of band names
472
+ :param classif_bands: list of classification band names
473
+ :return: partial xarray.DataSet (attributes and coordinates)
474
+ :rtype: xarray.DataSet
475
+ """
476
+
477
+ coords = {
478
+ "band_im": list(im_bands),
479
+ "row": np.arange(10),
480
+ "col": np.arange(10),
481
+ }
482
+
483
+ data_vars = {
484
+ "image": (["row", "col"], np.zeros((10, 10))),
485
+ }
486
+
487
+ if classif_bands is not None:
488
+ coords["band_classif"] = list(classif_bands)
489
+ data_vars["classif"] = (
490
+ ["row", "col", "band_classif"],
491
+ np.zeros((10, 10, len(classif_bands)), dtype=np.int32),
492
+ )
493
+
494
+ # create the dataset
495
+ dataset = xr.Dataset(data_vars=data_vars, coords=coords)
496
+
497
+ dataset.attrs["disparity_source"] = None
498
+
499
+ return dataset
500
+
501
+
502
+ def get_config_input_custom_cars(
503
+ user_cfg: Dict[str, dict], nodata_left, nodata_right
504
+ ) -> Dict[str, dict]:
505
+ """
506
+ Get the input configuration
507
+
508
+ :param user_cfg: user configuration
509
+ :type user_cfg: dict
510
+ :return cfg: partial configuration
511
+ :rtype cfg: dict
512
+ """
513
+
514
+ cfg = {}
515
+
516
+ if "input" in user_cfg:
517
+ cfg["input"] = {}
518
+
519
+ if "nodata_left" in user_cfg["input"]:
520
+ cfg["input"]["nodata_left"] = user_cfg["input"]["nodata_left"]
521
+ else:
522
+ cfg["input"]["nodata_left"] = nodata_left
523
+
524
+ if "nodata_right" in user_cfg["input"]:
525
+ cfg["input"]["nodata_right"] = user_cfg["input"]["nodata_right"]
526
+ else:
527
+ cfg["input"]["nodata_right"] = nodata_right
528
+
529
+ return cfg
530
+
531
+
532
+ def check_input_section_custom_cars(
533
+ user_cfg: Dict[str, dict],
534
+ ) -> Dict[str, dict]:
535
+ """
536
+ Complete and check if the dictionary is correct
537
+
538
+ :param user_cfg: user configuration
539
+ :type user_cfg: dict
540
+ :return: cfg: global configuration
541
+ :rtype: cfg: dict
542
+ """
543
+ # Add missing steps and inputs defaults values in user_cfg
544
+ cfg = update_conf(default_short_configuration_input_custom_cars, user_cfg)
545
+
546
+ # check schema
547
+ configuration_schema = {"input": input_configuration_schema_custom_cars}
548
+
549
+ checker = Checker(configuration_schema)
550
+ checker.validate(cfg)
551
+
552
+ return cfg
553
+
554
+
555
+ def overload_pandora_conf_with_confidence(conf, confidence_conf):
556
+ """
557
+ Overload pandora pipeline configuration with given confidence to add
558
+ just before disparity computation.
559
+
560
+ :param conf: current pandora configuration
561
+ :type conf: OrderedDict
562
+ :param confidence_conf: confidence applications config
563
+ :type confidence_conf: OrderedDict
564
+
565
+ :return: updated pandora pipeline conf
566
+ :rtype: OrderedDict
567
+ """
568
+
569
+ out_dict = OrderedDict()
570
+ out_dict.update(conf)
571
+
572
+ conf_keys = list(conf.keys())
573
+ confidence_conf_keys = list(confidence_conf.keys())
574
+
575
+ for key in confidence_conf_keys:
576
+ if key in conf_keys:
577
+ logging.info("{} pandora key already in configuration".format(key))
578
+
579
+ # update confidence
580
+ out_dict.update(confidence_conf)
581
+
582
+ # move confidence keys right before disparity computation
583
+
584
+ # get position of key "disparity"
585
+ if "disparity" not in conf_keys:
586
+ raise RuntimeError("disparity key not in pandora configuration")
587
+ disp_index = conf_keys.index("disparity")
588
+
589
+ # move to end every key from disparity
590
+ for ind in range(disp_index, len(conf_keys)):
591
+ out_dict.move_to_end(conf_keys[ind])
592
+
593
+ return out_dict
@@ -0,0 +1,32 @@
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 dsm filling module init file
23
+ """
24
+ # flake8: noqa: F401
25
+
26
+ from cars.applications.dsm_filling.abstract_dsm_filling_app import DsmFilling
27
+
28
+ from . import (
29
+ border_interpolation_app,
30
+ bulldozer_filling_app,
31
+ exogenous_filling_app,
32
+ )