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,981 @@
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
+ # pylint: disable=too-many-lines
22
+ # attribute-defined-outside-init is disabled so that we can create and use
23
+ # attributes however we need, to stick to the "everything is attribute" logic
24
+ # introduced in issue#895
25
+ # pylint: disable=attribute-defined-outside-init
26
+ # pylint: disable=too-many-nested-blocks
27
+ """
28
+ CARS filling pipeline class file
29
+ """
30
+ # pylint: disable=C0302
31
+ from __future__ import print_function
32
+
33
+ import copy
34
+ import logging
35
+ import os
36
+ import warnings
37
+ from collections import OrderedDict
38
+
39
+ import numpy as np
40
+ import rasterio
41
+ from json_checker import Checker, OptionalKey, Or
42
+ from pyproj import CRS
43
+ from rasterio.errors import NodataShadowWarning
44
+
45
+ from cars.applications.application import Application
46
+ from cars.core import cars_logging, inputs, projection
47
+ from cars.core.inputs import read_vector
48
+ from cars.core.utils import safe_makedirs
49
+ from cars.orchestrator import orchestrator
50
+ from cars.orchestrator.cluster.log_wrapper import cars_profile
51
+ from cars.pipelines.parameters import advanced_parameters
52
+ from cars.pipelines.parameters import advanced_parameters_constants as adv_cst
53
+ from cars.pipelines.parameters import output_constants as out_cst
54
+ from cars.pipelines.parameters import output_parameters, sensor_inputs
55
+ from cars.pipelines.parameters import sensor_inputs_constants as sens_cst
56
+ from cars.pipelines.parameters.output_constants import AUXILIARY
57
+ from cars.pipelines.pipeline import Pipeline
58
+ from cars.pipelines.pipeline_constants import (
59
+ ADVANCED,
60
+ APPLICATIONS,
61
+ INPUT,
62
+ ORCHESTRATOR,
63
+ OUTPUT,
64
+ )
65
+ from cars.pipelines.pipeline_template import PipelineTemplate
66
+
67
+ PIPELINE = "filling"
68
+
69
+
70
+ @Pipeline.register(
71
+ PIPELINE,
72
+ )
73
+ class FillingPipeline(PipelineTemplate):
74
+ """
75
+ FillingPipeline
76
+ """
77
+
78
+ # pylint: disable=too-many-instance-attributes
79
+
80
+ def __init__(self, conf, config_dir=None, pre_check=False): # noqa: C901
81
+ """
82
+ Creates pipeline
83
+
84
+ :param pipeline_name: name of the pipeline.
85
+ :type pipeline_name: str
86
+ :param cfg: configuration {'matching_cost_method': value}
87
+ :type cfg: dictionary
88
+ :param config_dir: path to dir containing json or yaml file
89
+ :type config_dir: str
90
+ """
91
+
92
+ self.config_dir = config_dir
93
+ # Transform relative path to absolute path
94
+ if config_dir is not None:
95
+ config_dir = os.path.abspath(config_dir)
96
+
97
+ # Check global conf
98
+ self.check_global_schema(conf)
99
+
100
+ if PIPELINE in conf:
101
+ self.check_pipeline_conf(conf)
102
+
103
+ self.out_dir = os.path.abspath(conf[OUTPUT][out_cst.OUT_DIRECTORY])
104
+
105
+ self.filling_dir = os.path.join(self.out_dir, "filling")
106
+
107
+ # Check input
108
+ conf[INPUT] = self.check_inputs(conf)
109
+
110
+ pipeline_conf = conf.get(PIPELINE, {})
111
+
112
+ # check advanced
113
+ conf[PIPELINE][ADVANCED] = self.check_advanced(
114
+ pipeline_conf, conf[INPUT]
115
+ )
116
+ # check output
117
+ conf[OUTPUT] = self.check_output(conf)
118
+
119
+ self.used_conf = {}
120
+
121
+ # Check conf orchestrator
122
+ self.used_conf[ORCHESTRATOR] = self.check_orchestrator(
123
+ conf.get(ORCHESTRATOR, None)
124
+ )
125
+ self.used_conf[INPUT] = conf[INPUT]
126
+ self.used_conf[OUTPUT] = conf[OUTPUT]
127
+ self.used_conf[ADVANCED] = conf[PIPELINE][ADVANCED]
128
+ self.save_all_intermediate_data = self.used_conf[ADVANCED][
129
+ adv_cst.SAVE_INTERMEDIATE_DATA
130
+ ]
131
+
132
+ filling_applications = self.generate_filling_applications(
133
+ self.used_conf[INPUT]
134
+ )
135
+
136
+ applications_conf = self.overide_pipeline_conf(
137
+ pipeline_conf.get(APPLICATIONS, {}),
138
+ filling_applications,
139
+ append_classification=True,
140
+ )
141
+
142
+ self.used_conf[APPLICATIONS] = self.check_applications(
143
+ applications_conf
144
+ )
145
+ # Used classification values, for filling -> will be masked
146
+ self.used_classif_values_for_filling = self.get_classif_values_filling(
147
+ self.used_conf[INPUT]
148
+ )
149
+ self.dump_dir = os.path.join(self.filling_dir, "dump_dir")
150
+
151
+ if isinstance(self.used_conf[INPUT]["dsm_to_fill"], str):
152
+ self.dsm_to_fill = {"dsm": self.used_conf[INPUT]["dsm_to_fill"]}
153
+ else:
154
+ self.dsm_to_fill = self.used_conf[INPUT]["dsm_to_fill"]
155
+
156
+ if not pre_check:
157
+ for key, path in self.dsm_to_fill.items():
158
+ self.dsm_to_fill[key] = os.path.abspath(path)
159
+
160
+ raster_crs = inputs.rasterio_get_crs(self.dsm_to_fill["dsm"])
161
+
162
+ crs = CRS.from_user_input(raster_crs)
163
+
164
+ # Un CRS COMPOSÉ contient 2 sous-CRS : horizontal + vertical
165
+ if len(crs.sub_crs_list) == 2:
166
+ self.epsg = crs.sub_crs_list[0].to_epsg()
167
+ self.vertical_crs = inputs.rasterio_get_crs(
168
+ self.dsm_to_fill["dsm"]
169
+ )
170
+
171
+ def check_pipeline_conf(self, conf):
172
+ """
173
+ Check pipeline configuration
174
+ """
175
+
176
+ # Validate inputs
177
+ pipeline_schema = {
178
+ OptionalKey(ADVANCED): dict,
179
+ OptionalKey(APPLICATIONS): dict,
180
+ }
181
+
182
+ checker_inputs = Checker(pipeline_schema)
183
+ checker_inputs.validate(conf[PIPELINE])
184
+
185
+ def check_inputs(self, conf, config_json_dir=None):
186
+ """
187
+ Check the inputs given
188
+
189
+ :param conf: configuration
190
+ :type conf: dict
191
+ :param config_dir: directory of used json, if
192
+ user filled paths with relative paths
193
+ :type config_dir: str
194
+
195
+ :return: overloader inputs
196
+ :rtype: dict
197
+ """
198
+ return sensor_inputs.sensors_check_inputs(
199
+ conf[INPUT], config_dir=config_json_dir
200
+ )
201
+
202
+ def check_output(self, conf):
203
+ """
204
+ Check the output given
205
+
206
+ :param conf: configuration of output
207
+ :type conf: dict
208
+
209
+ :return overloader output
210
+ :rtype : dict
211
+ """
212
+ conf_output, _ = output_parameters.check_output_parameters(
213
+ conf[INPUT], conf[OUTPUT], self.scaling_coeff
214
+ )
215
+ return conf_output
216
+
217
+ def check_advanced(self, conf, conf_input, output_dem_dir=None):
218
+ """
219
+ Check all conf for advanced configuration
220
+
221
+ :return: overridden advanced conf
222
+ :rtype: dict
223
+ """
224
+
225
+ conf_advanced = conf.get(ADVANCED, {})
226
+
227
+ inputs_conf = conf_input
228
+
229
+ overloaded_conf = conf_advanced.copy()
230
+
231
+ overloaded_conf[adv_cst.SAVE_INTERMEDIATE_DATA] = conf.get(
232
+ adv_cst.SAVE_INTERMEDIATE_DATA, False
233
+ )
234
+ # Check geometry plugin and overwrite geomodel in conf inputs
235
+ (
236
+ inputs_conf,
237
+ overloaded_conf[adv_cst.GEOMETRY_PLUGIN],
238
+ self.geom_plugin_without_dem_and_geoid,
239
+ self.geom_plugin_with_dem_and_geoid,
240
+ self.scaling_coeff,
241
+ ) = sensor_inputs.check_geometry_plugin(
242
+ inputs_conf,
243
+ conf_advanced.get(adv_cst.GEOMETRY_PLUGIN, None),
244
+ output_dem_dir,
245
+ )
246
+
247
+ schema = {
248
+ adv_cst.SAVE_INTERMEDIATE_DATA: Or(dict, bool),
249
+ adv_cst.GEOMETRY_PLUGIN: Or(str, dict),
250
+ }
251
+ checker_advanced_parameters = Checker(schema)
252
+ checker_advanced_parameters.validate(overloaded_conf)
253
+
254
+ return overloaded_conf
255
+
256
+ def check_applications(self, conf):
257
+ """
258
+ Check the given configuration for applications
259
+
260
+ :param conf: configuration of applications
261
+ :type conf: dict
262
+ """
263
+ used_conf = {}
264
+ self.dsm_filling_apps = {}
265
+
266
+ needed_applications = []
267
+ needed_applications += [
268
+ "auxiliary_filling",
269
+ ]
270
+
271
+ for key in conf:
272
+ if key.startswith("dsm_filling"):
273
+ needed_applications += [key]
274
+
275
+ for app_key in needed_applications:
276
+ used_conf[app_key] = conf.get(app_key, {})
277
+
278
+ if used_conf[app_key] is None:
279
+ continue
280
+ used_conf[app_key]["save_intermediate_data"] = (
281
+ self.save_all_intermediate_data
282
+ or used_conf[app_key].get("save_intermediate_data", False)
283
+ )
284
+
285
+ if app_key == "auxiliary_filling":
286
+ if used_conf[app_key] is not None:
287
+ used_conf[app_key]["activated"] = used_conf[app_key].get(
288
+ "activated", True
289
+ )
290
+
291
+ for app_key, app_conf in used_conf.items():
292
+ if not app_key.startswith("dsm_filling"):
293
+ continue
294
+
295
+ if app_conf is None:
296
+ self.dsm_filling_apps = {}
297
+ # keep over multiple runs
298
+ used_conf["dsm_filling"] = None
299
+ break
300
+
301
+ if app_key in self.dsm_filling_apps:
302
+ msg = (
303
+ f"The key {app_key} is defined twice in the input "
304
+ "configuration."
305
+ )
306
+ logging.error(msg)
307
+ raise NameError(msg)
308
+
309
+ if app_key[11:] == ".1":
310
+ app_conf.setdefault("method", "exogenous_filling")
311
+ if app_key[11:] == ".2":
312
+ app_conf.setdefault("method", "bulldozer")
313
+ if app_key[11:] == ".3":
314
+ app_conf.setdefault("method", "border_interpolation")
315
+
316
+ self.dsm_filling_apps[app_key] = Application(
317
+ "dsm_filling",
318
+ cfg=app_conf,
319
+ scaling_coeff=self.scaling_coeff,
320
+ )
321
+ used_conf[app_key] = self.dsm_filling_apps[app_key].get_conf()
322
+
323
+ methods_str = "\n".join(
324
+ f" - {k}={a.used_method}" for k, a in self.dsm_filling_apps.items()
325
+ )
326
+ logging.info(
327
+ "{} dsm filling apps registered:\n{}".format(
328
+ len(self.dsm_filling_apps), methods_str
329
+ )
330
+ )
331
+
332
+ # Auxiliary filling
333
+ self.auxiliary_filling_application = Application(
334
+ "auxiliary_filling",
335
+ cfg=conf.get("auxiliary_filling", {}),
336
+ scaling_coeff=self.scaling_coeff,
337
+ )
338
+ used_conf["auxiliary_filling"] = (
339
+ self.auxiliary_filling_application.get_conf()
340
+ )
341
+
342
+ # MNT generation
343
+ self.dem_generation_application = Application(
344
+ "dem_generation",
345
+ cfg=used_conf.get("dem_generation", {}),
346
+ scaling_coeff=self.scaling_coeff,
347
+ )
348
+ used_conf["dem_generation"] = self.dem_generation_application.get_conf()
349
+
350
+ return used_conf
351
+
352
+ def generate_filling_applications(self, inputs_conf):
353
+ """
354
+ Generate filling applications configuration according to inputs
355
+
356
+ :param inputs_conf: inputs configuration
357
+ :type inputs_conf: dict
358
+ """
359
+
360
+ filling_applications = {}
361
+
362
+ # Generate applications configuration
363
+ for filling_name, classif_values in inputs_conf[
364
+ sens_cst.FILLING
365
+ ].items():
366
+ # No filling
367
+ if classif_values is None:
368
+ continue
369
+
370
+ classif_values = list(map(str, classif_values))
371
+
372
+ # Update application configuration
373
+ if filling_name == "fill_with_geoid":
374
+ new_filling_conf = {
375
+ "dsm_filling.1": {
376
+ "method": "exogenous_filling",
377
+ "classification": classif_values,
378
+ "fill_with_geoid": classif_values,
379
+ },
380
+ }
381
+ elif filling_name == "interpolate_from_borders":
382
+ new_filling_conf = {
383
+ "dsm_filling.2": {
384
+ "method": "bulldozer",
385
+ "classification": classif_values,
386
+ },
387
+ "dsm_filling.3": {
388
+ "method": "border_interpolation",
389
+ "classification": classif_values,
390
+ },
391
+ }
392
+ elif filling_name == "fill_with_endogenous_dem":
393
+ new_filling_conf = {
394
+ "dsm_filling.1": {
395
+ "method": "exogenous_filling",
396
+ "classification": classif_values,
397
+ },
398
+ "dsm_filling.2": {
399
+ "method": "bulldozer",
400
+ "classification": classif_values,
401
+ },
402
+ }
403
+ elif filling_name == "fill_with_exogenous_dem":
404
+ new_filling_conf = {
405
+ "dsm_filling.2": {
406
+ "method": "bulldozer",
407
+ "classification": classif_values,
408
+ },
409
+ }
410
+ else:
411
+ new_filling_conf = {}
412
+
413
+ # Update application configuration
414
+ filling_applications = self.overide_pipeline_conf(
415
+ filling_applications,
416
+ new_filling_conf,
417
+ append_classification=True,
418
+ )
419
+
420
+ return filling_applications
421
+
422
+ def overide_pipeline_conf(
423
+ self, conf, overiding_conf, append_classification=False
424
+ ):
425
+ """
426
+ Merge two dictionaries recursively without removing keys
427
+ from the base conf.
428
+
429
+ :param conf: base configuration dictionary
430
+ :type conf: dict
431
+ :param overiding_conf: overriding configuration dictionary
432
+ :type overiding_conf: dict
433
+ :return: merged configuration
434
+ :rtype: dict
435
+ """
436
+ result = copy.deepcopy(conf)
437
+
438
+ def merge_recursive(base_dict, override_dict):
439
+ """
440
+ Main recursive function
441
+ """
442
+ for key, value in override_dict.items():
443
+ if (
444
+ key in base_dict
445
+ and isinstance(base_dict[key], dict)
446
+ and isinstance(value, dict)
447
+ ):
448
+ merge_recursive(base_dict[key], value)
449
+ elif (
450
+ append_classification
451
+ and key in base_dict
452
+ and isinstance(base_dict[key], list)
453
+ and isinstance(value, list)
454
+ and key == "classification"
455
+ ):
456
+ # extend list, avoiding duplicates
457
+ base_dict[key] = list(
458
+ OrderedDict.fromkeys(base_dict[key] + value)
459
+ )
460
+ else:
461
+ base_dict[key] = value
462
+
463
+ merge_recursive(result, overiding_conf)
464
+
465
+ return result
466
+
467
+ def get_classif_values_filling(self, inputs_conf):
468
+ """
469
+ Get values in classif, used for filling
470
+
471
+ :param inputs_conf: inputs
472
+ :type inputs_conf: dict
473
+
474
+ :return: list of values
475
+ :rtype: list
476
+ """
477
+
478
+ if (
479
+ sens_cst.FILLING not in inputs_conf
480
+ or inputs_conf[sens_cst.FILLING] is None
481
+ ):
482
+ logging.info("No filling in input configuration")
483
+ return None
484
+
485
+ filling_classif_values = []
486
+ for _, classif_values in inputs_conf[sens_cst.FILLING].items():
487
+ # Add new value to filling bands
488
+ if classif_values is not None:
489
+ if isinstance(classif_values, str):
490
+ classif_values = [classif_values]
491
+ filling_classif_values += classif_values
492
+
493
+ simplified_list = list(OrderedDict.fromkeys(filling_classif_values))
494
+ res_as_string_list = [str(value) for value in simplified_list]
495
+ return res_as_string_list
496
+
497
+ @cars_profile(name="merge filling bands", interval=0.5)
498
+ def merge_filling_bands(self, filling_path, aux_filling, dsm_file):
499
+ """
500
+ Merge filling bands to get mono band in output
501
+ """
502
+
503
+ with rasterio.open(dsm_file) as in_dsm:
504
+ dsm_msk = in_dsm.read_masks(1)
505
+
506
+ with rasterio.open(filling_path) as src:
507
+ nb_bands = src.count
508
+
509
+ if nb_bands == 1:
510
+ return False
511
+
512
+ filling_multi_bands = src.read()
513
+ filling_mono_bands = np.zeros(filling_multi_bands.shape[1:3])
514
+ descriptions = src.descriptions
515
+ dict_temp = {name: i for i, name in enumerate(descriptions)}
516
+ profile = src.profile
517
+
518
+ with warnings.catch_warnings():
519
+ warnings.simplefilter("ignore", NodataShadowWarning)
520
+ filling_mask = src.read_masks(1)
521
+
522
+ filling_mono_bands[filling_mask == 0] = 0
523
+
524
+ filling_bands_list = {
525
+ "fill_with_geoid": ["filling_exogenous"],
526
+ "interpolate_from_borders": [
527
+ "bulldozer",
528
+ "border_interpolation",
529
+ ],
530
+ "fill_with_endogenous_dem": [
531
+ "filling_exogenous",
532
+ "bulldozer",
533
+ ],
534
+ "fill_with_exogenous_dem": ["bulldozer"],
535
+ }
536
+
537
+ # To get the right footprint
538
+ filling_mono_bands = np.logical_or(dsm_msk, filling_mask).astype(
539
+ np.uint8
540
+ )
541
+
542
+ # to keep the previous classif convention
543
+ filling_mono_bands[filling_mono_bands == 0] = src.nodata
544
+ filling_mono_bands[filling_mono_bands == 1] = 0
545
+
546
+ no_match = False
547
+ for key, value in aux_filling.items():
548
+ if isinstance(value, str):
549
+ value = [value]
550
+
551
+ if isinstance(value, list):
552
+ for elem in value:
553
+ if elem != "other":
554
+ filling_method = filling_bands_list[elem]
555
+
556
+ if all(
557
+ method in descriptions
558
+ for method in filling_method
559
+ ):
560
+ indices_true = [
561
+ dict_temp[m] for m in filling_method
562
+ ]
563
+
564
+ mask_true = np.all(
565
+ filling_multi_bands[indices_true, :, :]
566
+ == 1,
567
+ axis=0,
568
+ )
569
+
570
+ indices_false = [
571
+ i
572
+ for i in range(filling_multi_bands.shape[0])
573
+ if i not in indices_true
574
+ ]
575
+
576
+ mask_false = np.all(
577
+ filling_multi_bands[indices_false, :, :]
578
+ == 0,
579
+ axis=0,
580
+ )
581
+
582
+ mask = mask_true & mask_false
583
+
584
+ filling_mono_bands[mask] = key
585
+ else:
586
+ no_match = True
587
+
588
+ if no_match:
589
+ mask_1 = np.all(
590
+ filling_multi_bands[1:, :, :] == 1,
591
+ axis=0,
592
+ )
593
+
594
+ mask_2 = np.all(
595
+ filling_mono_bands == 0,
596
+ axis=0,
597
+ )
598
+
599
+ filling_mono_bands[mask_1 & mask_2] = (
600
+ aux_filling["other"] if "other" in aux_filling else 50
601
+ )
602
+
603
+ profile.update(count=1, dtype=filling_mono_bands.dtype)
604
+ with rasterio.open(filling_path, "w", **profile) as src:
605
+ src.write(filling_mono_bands, 1)
606
+
607
+ return True
608
+
609
+ @cars_profile(name="merge classif bands", interval=0.5)
610
+ def merge_classif_bands(self, classif_path, aux_classif, dsm_file):
611
+ """
612
+ Merge classif bands to get mono band in output
613
+ """
614
+ with rasterio.open(dsm_file) as in_dsm:
615
+ dsm_msk = in_dsm.read_masks(1)
616
+
617
+ with rasterio.open(classif_path) as src:
618
+ nb_bands = src.count
619
+
620
+ if nb_bands == 1:
621
+ return False
622
+
623
+ classif_multi_bands = src.read()
624
+ classif_mono_band = np.zeros(classif_multi_bands.shape[1:3])
625
+ descriptions = src.descriptions
626
+ profile = src.profile
627
+ classif_mask = src.read_masks(1)
628
+ classif_mono_band[classif_mask == 0] = 0
629
+
630
+ # To get the right footprint
631
+ classif_mono_band = np.logical_or(dsm_msk, classif_mask).astype(
632
+ np.uint8
633
+ )
634
+
635
+ # to keep the previous classif convention
636
+ classif_mono_band[classif_mono_band == 0] = src.nodata
637
+ classif_mono_band[classif_mono_band == 1] = 0
638
+
639
+ for key, value in aux_classif.items():
640
+ if isinstance(value, int):
641
+ num_band = descriptions.index(str(value))
642
+ mask_1 = classif_mono_band == 0
643
+ mask_2 = classif_multi_bands[num_band, :, :] == 1
644
+ classif_mono_band[mask_1 & mask_2] = key
645
+ elif isinstance(value, list):
646
+ for elem in value:
647
+ num_band = descriptions.index(str(elem))
648
+ mask_1 = classif_mono_band == 0
649
+ mask_2 = classif_multi_bands[num_band, :, :] == 1
650
+ classif_mono_band[mask_1 & mask_2] = key
651
+
652
+ profile.update(count=1, dtype=classif_mono_band.dtype)
653
+ with rasterio.open(classif_path, "w", **profile) as src:
654
+ src.write(classif_mono_band, 1)
655
+
656
+ return True
657
+
658
+ def monoband_to_multiband(self, input_raster, output_raster, bands_classif):
659
+ """
660
+ Convert classification from monoband to multiband
661
+
662
+ :param input_raster: the intput classification path
663
+ :type input_raster: str
664
+ :param output_raster: the output classification path
665
+ :type output_raster: str
666
+ :param bands_classif: the bands values
667
+ :type bands_classif: list
668
+ """
669
+
670
+ with rasterio.open(input_raster) as src:
671
+ mono = src.read(1)
672
+ mono_msk = src.read_masks(1)
673
+ profile = src.profile
674
+ nodata_value = src.nodata
675
+
676
+ multiband = np.zeros(
677
+ (len(bands_classif), mono.shape[0], mono.shape[1]), dtype=np.uint8
678
+ )
679
+ multiband_msk = np.broadcast_to(mono_msk, multiband.shape)
680
+
681
+ for i, cls in enumerate(bands_classif):
682
+ multiband[i] = mono == cls
683
+
684
+ multiband[multiband_msk == 0] = nodata_value
685
+
686
+ profile.update(count=len(bands_classif))
687
+
688
+ with rasterio.open(output_raster, "w", **profile) as dst:
689
+ dst.write(multiband)
690
+
691
+ for i, cls in enumerate(bands_classif, start=1):
692
+ dst.update_tags(band=i, class_name=str(cls))
693
+ dst.set_band_description(i, str(cls))
694
+
695
+ return output_raster
696
+
697
+ def filling(self): # noqa: C901
698
+ """
699
+ Filling method
700
+ """
701
+ inputs_conf = self.used_conf[INPUT]
702
+
703
+ dsm_file_name = self.dsm_to_fill["dsm"]
704
+
705
+ self.texture_bands = self.used_conf[OUTPUT][AUXILIARY][
706
+ out_cst.AUX_IMAGE
707
+ ]
708
+
709
+ dsm_filled_dir = os.path.join(self.filling_dir, "dsm/")
710
+ os.makedirs(dsm_filled_dir, exist_ok=True)
711
+
712
+ color_file_name = (
713
+ self.dsm_to_fill["image"]
714
+ if "image" in self.used_conf[INPUT]["dsm_to_fill"]
715
+ else None
716
+ )
717
+
718
+ first_key = list(inputs_conf[sens_cst.SENSORS].keys())[0]
719
+ input_classif = inputs_conf[sens_cst.SENSORS][first_key][
720
+ sens_cst.INPUT_CLASSIFICATION
721
+ ]
722
+ bands_classif = None
723
+ if input_classif is not None:
724
+ bands_classif = input_classif["values"]
725
+
726
+ classif_file_name = (
727
+ self.monoband_to_multiband(
728
+ self.dsm_to_fill["classification"],
729
+ os.path.join(dsm_filled_dir, "classification.tif"),
730
+ bands_classif,
731
+ )
732
+ if sens_cst.INPUT_CLASSIFICATION
733
+ in self.used_conf[INPUT]["dsm_to_fill"]
734
+ else None
735
+ )
736
+
737
+ filling_file_name = (
738
+ self.dsm_to_fill["filling"]
739
+ if "filling" in self.used_conf[INPUT]["dsm_to_fill"]
740
+ else None
741
+ )
742
+
743
+ if inputs_conf[sens_cst.INITIAL_ELEVATION][sens_cst.DEM_PATH] is None:
744
+ dems = {}
745
+
746
+ dem_generation_output_dir = os.path.join(
747
+ self.dump_dir, "dem_generation"
748
+ )
749
+ safe_makedirs(dem_generation_output_dir)
750
+
751
+ # Use initial elevation if provided, and generate dems
752
+ _, paths, _ = self.dem_generation_application.run(
753
+ dsm_file_name,
754
+ dem_generation_output_dir,
755
+ input_geoid=self.used_conf[INPUT][sens_cst.INITIAL_ELEVATION][
756
+ sens_cst.GEOID
757
+ ],
758
+ output_geoid=self.used_conf[OUTPUT][out_cst.OUT_GEOID],
759
+ initial_elevation=(
760
+ self.used_conf[INPUT][sens_cst.INITIAL_ELEVATION][
761
+ sens_cst.DEM_PATH
762
+ ]
763
+ ),
764
+ default_alt=self.geom_plugin_with_dem_and_geoid.default_alt,
765
+ cars_orchestrator=self.cars_orchestrator,
766
+ )
767
+
768
+ dem_median = paths["dem_median"]
769
+ dem_min = paths["dem_min"]
770
+ dem_max = paths["dem_max"]
771
+
772
+ dems["dem_median"] = dem_median
773
+ dems["dem_min"] = dem_min
774
+ dems["dem_max"] = dem_max
775
+
776
+ # Override initial elevation
777
+ inputs_conf[sens_cst.INITIAL_ELEVATION][
778
+ sens_cst.DEM_PATH
779
+ ] = dem_median
780
+
781
+ # Check advanced parameters with new initial elevation
782
+ output_dem_dir = os.path.join(
783
+ self.used_conf[OUTPUT][out_cst.OUT_DIRECTORY],
784
+ "dump_dir",
785
+ "initial_elevation",
786
+ )
787
+ safe_makedirs(output_dem_dir)
788
+ (
789
+ inputs_conf,
790
+ _,
791
+ self.geometry_plugin,
792
+ self.geom_plugin_without_dem_and_geoid,
793
+ self.geom_plugin_with_dem_and_geoid,
794
+ _,
795
+ _,
796
+ _,
797
+ ) = advanced_parameters.check_advanced_parameters(
798
+ inputs_conf,
799
+ self.used_conf.get(ADVANCED, {}),
800
+ output_dem_dir=output_dem_dir,
801
+ )
802
+
803
+ if not hasattr(self, "list_intersection_poly"):
804
+ if (
805
+ self.used_conf[INPUT][sens_cst.INITIAL_ELEVATION][
806
+ sens_cst.DEM_PATH
807
+ ]
808
+ is not None
809
+ ):
810
+ sensor_inputs.load_geomodels(
811
+ inputs_conf, self.geom_plugin_without_dem_and_geoid
812
+ )
813
+ self.list_sensor_pairs = sensor_inputs.generate_pairs(
814
+ self.used_conf[INPUT]
815
+ )
816
+
817
+ self.list_intersection_poly = []
818
+ for _, (
819
+ pair_key,
820
+ sensor_image_left,
821
+ sensor_image_right,
822
+ ) in enumerate(self.list_sensor_pairs):
823
+ pair_folder = os.path.join(
824
+ self.dump_dir, "terrain_bbox", pair_key
825
+ )
826
+ safe_makedirs(pair_folder)
827
+ geojson1 = os.path.join(
828
+ pair_folder, "left_envelope.geojson"
829
+ )
830
+ geojson2 = os.path.join(
831
+ pair_folder, "right_envelope.geojson"
832
+ )
833
+ out_envelopes_intersection = os.path.join(
834
+ pair_folder, "envelopes_intersection.geojson"
835
+ )
836
+
837
+ inter_poly, _ = projection.ground_intersection_envelopes(
838
+ sensor_image_left[sens_cst.INPUT_IMG]["bands"]["b0"][
839
+ "path"
840
+ ],
841
+ sensor_image_right[sens_cst.INPUT_IMG]["bands"]["b0"][
842
+ "path"
843
+ ],
844
+ sensor_image_left[sens_cst.INPUT_GEO_MODEL],
845
+ sensor_image_right[sens_cst.INPUT_GEO_MODEL],
846
+ self.geom_plugin_with_dem_and_geoid,
847
+ geojson1,
848
+ geojson2,
849
+ out_envelopes_intersection,
850
+ envelope_file_driver="GeoJSON",
851
+ intersect_file_driver="GeoJSON",
852
+ )
853
+
854
+ # Retrieve bounding box of the grd inters of the envelopes
855
+ inter_poly, inter_epsg = read_vector(
856
+ out_envelopes_intersection
857
+ )
858
+
859
+ # Project polygon if epsg is different
860
+ if self.vertical_crs != CRS(inter_epsg):
861
+ inter_poly = projection.polygon_projection_crs(
862
+ inter_poly, CRS(inter_epsg), self.vertical_crs
863
+ )
864
+
865
+ self.list_intersection_poly.append(inter_poly)
866
+ else:
867
+ self.list_intersection_poly = None
868
+
869
+ dtm_file_name = None
870
+ for app_key, app in self.dsm_filling_apps.items():
871
+
872
+ app_dump_dir = os.path.join(
873
+ self.dump_dir, app_key.replace(".", "_")
874
+ )
875
+
876
+ if app.get_conf()["method"] == "exogenous_filling":
877
+ _ = app.run(
878
+ dsm_file=dsm_file_name,
879
+ classif_file=classif_file_name,
880
+ filling_file=filling_file_name,
881
+ dump_dir=app_dump_dir,
882
+ roi_polys=self.list_intersection_poly,
883
+ roi_epsg=self.epsg,
884
+ output_geoid=self.used_conf[OUTPUT][sens_cst.GEOID],
885
+ geom_plugin=self.geom_plugin_with_dem_and_geoid,
886
+ dsm_dir=dsm_filled_dir,
887
+ )
888
+ elif app.get_conf()["method"] == "bulldozer":
889
+ dtm_file_name = app.run(
890
+ dsm_file=dsm_file_name,
891
+ classif_file=classif_file_name,
892
+ filling_file=filling_file_name,
893
+ dump_dir=app_dump_dir,
894
+ roi_polys=self.list_intersection_poly,
895
+ roi_epsg=self.epsg,
896
+ orchestrator=self.cars_orchestrator,
897
+ dsm_dir=dsm_filled_dir,
898
+ )
899
+ elif app.get_conf()["method"] == "border_interpolation":
900
+ _ = app.run(
901
+ dsm_file=dsm_file_name,
902
+ classif_file=classif_file_name,
903
+ filling_file=filling_file_name,
904
+ dtm_file=dtm_file_name,
905
+ dump_dir=app_dump_dir,
906
+ roi_polys=self.list_intersection_poly,
907
+ roi_epsg=self.epsg,
908
+ dsm_dir=dsm_filled_dir,
909
+ )
910
+
911
+ if not app.save_intermediate_data:
912
+ self.cars_orchestrator.add_to_clean(app_dump_dir)
913
+
914
+ if dsm_file_name == self.dsm_to_fill["dsm"]:
915
+ dsm_file_name = os.path.join(dsm_filled_dir, "dsm.tif")
916
+
917
+ if "filling" in self.used_conf[INPUT]["dsm_to_fill"]:
918
+ if filling_file_name == self.dsm_to_fill["filling"]:
919
+ filling_file_name = os.path.join(
920
+ dsm_filled_dir, "filling.tif"
921
+ )
922
+
923
+ _ = self.auxiliary_filling_application.run(
924
+ dsm_file=os.path.join(dsm_filled_dir, "dsm.tif"),
925
+ color_file=color_file_name,
926
+ classif_file=classif_file_name,
927
+ dump_dir=self.dump_dir,
928
+ sensor_inputs=self.used_conf[INPUT].get("sensors"),
929
+ pairing=self.used_conf[INPUT].get("pairing"),
930
+ geom_plugin=self.geom_plugin_with_dem_and_geoid,
931
+ texture_bands=self.texture_bands,
932
+ output_geoid=self.used_conf[OUTPUT][sens_cst.GEOID],
933
+ orchestrator=self.cars_orchestrator,
934
+ dsm_dir=dsm_filled_dir,
935
+ )
936
+ self.cars_orchestrator.breakpoint()
937
+
938
+ if (
939
+ os.path.join(dsm_filled_dir, "classification.tif") is not None
940
+ and self.used_conf[OUTPUT][out_cst.AUXILIARY][
941
+ out_cst.AUX_CLASSIFICATION
942
+ ]
943
+ ):
944
+ self.merge_classif_bands(
945
+ classif_file_name,
946
+ self.used_conf[OUTPUT][out_cst.AUXILIARY][
947
+ out_cst.AUX_CLASSIFICATION
948
+ ],
949
+ dsm_file_name,
950
+ )
951
+ if (
952
+ filling_file_name is not None
953
+ and self.used_conf[OUTPUT][out_cst.AUXILIARY][out_cst.AUX_FILLING]
954
+ ):
955
+ self.merge_filling_bands(
956
+ os.path.join(dsm_filled_dir, "filling.tif"),
957
+ self.used_conf[OUTPUT][out_cst.AUXILIARY][out_cst.AUX_FILLING],
958
+ dsm_file_name,
959
+ )
960
+
961
+ return True
962
+
963
+ @cars_profile(name="Run_subsampling_pipeline", interval=0.5)
964
+ def run(self): # noqa C901
965
+ """
966
+ Run pipeline
967
+ """
968
+ cars_logging.add_progress_message("Starting filling pipeline")
969
+
970
+ self.log_dir = os.path.join(self.filling_dir, "logs")
971
+
972
+ with orchestrator.Orchestrator(
973
+ orchestrator_conf=self.used_conf[ORCHESTRATOR],
974
+ out_dir=self.filling_dir,
975
+ log_dir=self.log_dir,
976
+ out_yaml_path=os.path.join(
977
+ self.filling_dir,
978
+ out_cst.INFO_FILENAME,
979
+ ),
980
+ ) as self.cars_orchestrator:
981
+ self.filling()