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,762 @@
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
+ this module contains the bicubic_resampling application class.
23
+ """
24
+ # pylint: disable=too-many-lines
25
+ # TODO refacto: factorize disributed code, and remove too-many-lines
26
+
27
+ # Standard imports
28
+ import logging
29
+ import os
30
+ from typing import Dict, Tuple
31
+
32
+ # Third party imports
33
+ import numpy as np
34
+ import xarray as xr
35
+ from json_checker import And, Checker, Or
36
+ from shapely.geometry import Polygon
37
+
38
+ # CARS imports
39
+ import cars.orchestrator.orchestrator as ocht
40
+ from cars.applications import application_constants
41
+ from cars.applications.resampling import (
42
+ resampling_algo,
43
+ resampling_constants,
44
+ resampling_wrappers,
45
+ )
46
+ from cars.applications.resampling.abstract_resampling_app import Resampling
47
+ from cars.core import constants as cst
48
+ from cars.core import inputs, tiling
49
+ from cars.core.utils import safe_makedirs
50
+ from cars.data_structures import cars_dataset, format_transformation
51
+ from cars.pipelines.parameters import sensor_inputs_constants as sens_cst
52
+
53
+
54
+ class BicubicResampling(Resampling, short_name="bicubic"):
55
+ """
56
+ BicubicResampling
57
+ """
58
+
59
+ # pylint: disable=too-many-instance-attributes
60
+
61
+ def __init__(self, conf=None):
62
+ """
63
+ Init function of BicubicResampling
64
+
65
+ :param conf: configuration for resampling
66
+ :return: an application_to_use object
67
+ """
68
+ super().__init__(conf=conf)
69
+
70
+ # check conf
71
+ self.used_method = self.used_config["method"]
72
+ self.strip_height = self.used_config["strip_height"]
73
+ self.step = self.used_config["step"]
74
+
75
+ # Saving bools
76
+ self.save_intermediate_data = self.used_config["save_intermediate_data"]
77
+
78
+ self.interpolator_image = self.used_config["interpolator_image"]
79
+ self.interpolator_classif = self.used_config["interpolator_classif"]
80
+ self.interpolator_mask = self.used_config["interpolator_mask"]
81
+
82
+ # Init orchestrator
83
+ self.orchestrator = None
84
+
85
+ def check_conf(self, conf):
86
+ """
87
+ Check configuration
88
+
89
+ :param conf: configuration to check
90
+ :type conf: dict
91
+
92
+ :return: overloaded configuration
93
+ :rtype: dict
94
+
95
+ """
96
+
97
+ # init conf
98
+ if conf is not None:
99
+ overloaded_conf = conf.copy()
100
+ else:
101
+ conf = {}
102
+ overloaded_conf = {}
103
+
104
+ # Overload conf
105
+
106
+ # get rasterization parameter
107
+ overloaded_conf["method"] = conf.get("method", "bicubic")
108
+ overloaded_conf["strip_height"] = conf.get("strip_height", 60)
109
+ overloaded_conf["interpolator_image"] = conf.get(
110
+ "interpolator_image", "bicubic"
111
+ )
112
+ overloaded_conf["interpolator_classif"] = conf.get(
113
+ "interpolator_classif", "nearest"
114
+ )
115
+ overloaded_conf["interpolator_mask"] = conf.get(
116
+ "interpolator_mask", "nearest"
117
+ )
118
+ overloaded_conf["step"] = conf.get("step", 500)
119
+
120
+ # Saving bools
121
+ overloaded_conf["save_intermediate_data"] = conf.get(
122
+ "save_intermediate_data", False
123
+ )
124
+
125
+ rectification_schema = {
126
+ "method": str,
127
+ "strip_height": And(int, lambda x: x > 0),
128
+ "interpolator_image": str,
129
+ "interpolator_classif": str,
130
+ "interpolator_mask": str,
131
+ "step": Or(None, int),
132
+ "save_intermediate_data": bool,
133
+ }
134
+
135
+ # Check conf
136
+ checker = Checker(rectification_schema)
137
+ checker.validate(overloaded_conf)
138
+
139
+ return overloaded_conf
140
+
141
+ def pre_run(
142
+ self,
143
+ grid_left,
144
+ tile_width,
145
+ tile_height,
146
+ ):
147
+ """
148
+ Pre run some computations : tiling grid
149
+
150
+ :param grid_left: left grid
151
+ :type grid_left: dict
152
+ :param optimum_tile_size: optimum tile size
153
+ :type optimum_tile_size: int
154
+
155
+
156
+ :return: epipolar_regions_grid, epipolar_regions,
157
+ opt_epipolar_tile_size, largest_epipolar_region,
158
+ """
159
+
160
+ # Get largest epipolar regions from configuration file
161
+ largest_epipolar_region = [
162
+ 0,
163
+ 0,
164
+ grid_left["epipolar_size_x"],
165
+ grid_left["epipolar_size_y"],
166
+ ]
167
+
168
+ origin = grid_left["grid_origin"]
169
+ spacing = grid_left["grid_spacing"]
170
+
171
+ logging.info(
172
+ "Size of epipolar image: {}".format(largest_epipolar_region)
173
+ )
174
+ logging.debug("Origin of epipolar grid: {}".format(origin))
175
+ logging.debug("Spacing of epipolar grid: {}".format(spacing))
176
+
177
+ if tile_width is None:
178
+ tile_width = grid_left["epipolar_size_x"]
179
+ if tile_height is None:
180
+ tile_height = self.strip_height
181
+
182
+ logging.info(
183
+ "Tile size for epipolar regions: "
184
+ "{width}x{height} pixels".format(
185
+ width=tile_width, height=tile_height
186
+ )
187
+ )
188
+
189
+ epipolar_regions_grid = tiling.generate_tiling_grid(
190
+ 0,
191
+ 0,
192
+ grid_left["epipolar_size_y"],
193
+ grid_left["epipolar_size_x"],
194
+ tile_height,
195
+ tile_width,
196
+ )
197
+
198
+ logging.info(
199
+ "Epipolar image will be processed in {} splits".format(
200
+ epipolar_regions_grid.shape[0] * epipolar_regions_grid.shape[1]
201
+ )
202
+ )
203
+
204
+ return (
205
+ epipolar_regions_grid,
206
+ tile_width,
207
+ tile_height,
208
+ largest_epipolar_region,
209
+ )
210
+
211
+ def run( # pylint: disable=too-many-positional-arguments # noqa: C901
212
+ self,
213
+ sensor_image_left,
214
+ sensor_image_right,
215
+ grid_left,
216
+ grid_right,
217
+ geom_plugin,
218
+ orchestrator=None,
219
+ pair_folder=None,
220
+ pair_key="PAIR_0",
221
+ margins_fun=None,
222
+ tile_width=None,
223
+ tile_height=None,
224
+ add_classif=True,
225
+ epipolar_roi=None,
226
+ required_bands=None,
227
+ texture_bands=None,
228
+ resolution=1,
229
+ ):
230
+ """
231
+ Run resampling application.
232
+
233
+ Creates left and right CarsDataset filled with xarray.Dataset,
234
+ corresponding to sensor images resampled in epipolar geometry.
235
+
236
+ :param sensor_images_left: tiled sensor left image
237
+ Dict Must contain keys : "image", "geomodel",
238
+ "no_data", "mask", "classification". Paths must be absolutes
239
+ :type sensor_images_left: CarsDataset
240
+ :param sensor_images_right: tiled sensor right image
241
+ Dict Must contain keys : "image", "geomodel",
242
+ "no_data", "mask", "classification". Paths must be absolutes
243
+ :type sensor_images_right: CarsDataset
244
+ :param grid_left: left epipolar grid
245
+ Grid dict contains :
246
+ - "grid_spacing", "grid_origin", \
247
+ "epipolar_size_x", "epipolar_size_y", "epipolar_origin_x",\
248
+ "epipolar_origin_y", epipolar_spacing_x",\
249
+ "epipolar_spacing", "disp_to_alt_ratio", "path"
250
+ :type grid_left: dict
251
+ :param grid_right: right epipolar grid. Grid dict contains :
252
+ - "grid_spacing", "grid_origin",\
253
+ "epipolar_size_x", "epipolar_size_y", "epipolar_origin_x",\
254
+ "epipolar_origin_y", epipolar_spacing_x",\
255
+ "epipolar_spacing", "disp_to_alt_ratio", "path"
256
+ :type grid_right: dict
257
+ :param orchestrator: orchestrator used
258
+ :param pair_folder: folder used for current pair
259
+ :type pair_folder: directory to save files to
260
+ :param pair_key: pair id
261
+ :type pair_key: str
262
+ :param margins_fun: margins function to use
263
+ :type margins_fun: fun
264
+ :param optimum_tile_size: optimum tile size to use
265
+ :type optimum_tile_size: int
266
+ :param tile_width: width of tile
267
+ :type tile_width: int
268
+ :param tile_height: height of tile
269
+ :type tile_height: int
270
+ :param add_classif: add classif to dataset
271
+ :type add_classif: bool
272
+ :param epipolar_roi: Epipolar roi to use if set.
273
+ Set None tiles outsize roi
274
+ :type epipolar_roi: list(int), [row_min, row_max, col_min, col_max]
275
+ :param required_bands: bands to resample on left and right image
276
+ :type required_bands: dict
277
+ :param texture_bands: name of bands used for output texture
278
+ :type texture_bands: list
279
+ :param resolution: resolution for downsampling
280
+ :type resolution: int
281
+
282
+ :return: left epipolar image, right epipolar image. \
283
+ Each CarsDataset contains:
284
+
285
+ - N x M Delayed tiles. \
286
+ Each tile will be a future xarray Dataset containing:
287
+
288
+ - data with keys : "im", "msk", "classif"
289
+ - attrs with keys: "margins" with "disp_min" and "disp_max"\
290
+ "transform", "crs", "valid_pixels", "no_data_mask",
291
+ "no_data_img"
292
+ - attributes containing: \
293
+ "largest_epipolar_region","opt_epipolar_tile_size",
294
+ "disp_min_tiling", "disp_max_tiling"
295
+
296
+ :rtype: Tuple(CarsDataset, CarsDataset)
297
+ """
298
+
299
+ # Default orchestrator
300
+ if orchestrator is None:
301
+ # Create default sequential orchestrator for current application
302
+ # be aware, no out_json will be shared between orchestrators
303
+ # No files saved
304
+ self.orchestrator = ocht.Orchestrator(
305
+ orchestrator_conf={"mode": "sequential"}
306
+ )
307
+ else:
308
+ self.orchestrator = orchestrator
309
+
310
+ if pair_folder is None:
311
+ pair_folder = os.path.join(self.orchestrator.out_dir, "tmp")
312
+
313
+ step = int(self.step / resolution)
314
+
315
+ # Create zeros margins if not provided
316
+ if margins_fun is None:
317
+
318
+ def margins_fun( # pylint: disable=unused-argument
319
+ row_min, row_max, col_min, col_max
320
+ ):
321
+ """
322
+ Default margin function, returning zeros
323
+ """
324
+ corner = ["left", "up", "right", "down"]
325
+ data = np.zeros(len(corner))
326
+ col = np.arange(len(corner))
327
+ margins = xr.Dataset(
328
+ {"left_margin": (["col"], data)}, coords={"col": col}
329
+ )
330
+ margins["right_margin"] = xr.DataArray(data, dims=["col"])
331
+ return margins
332
+
333
+ # Get grids and regions for current pair
334
+ (
335
+ epipolar_regions_grid,
336
+ tile_width,
337
+ tile_height,
338
+ largest_epipolar_region,
339
+ ) = self.pre_run(
340
+ grid_left,
341
+ tile_width,
342
+ tile_height,
343
+ )
344
+
345
+ # Create CarsDataset
346
+ # Epipolar_images
347
+ epipolar_images_left = cars_dataset.CarsDataset(
348
+ "arrays", name="resampling_left_" + pair_key
349
+ )
350
+ epipolar_images_right = cars_dataset.CarsDataset(
351
+ "arrays", name="resampling_" + pair_key
352
+ )
353
+
354
+ # Compute tiling grid
355
+ epipolar_images_left.tiling_grid = epipolar_regions_grid
356
+
357
+ # Generate tiling grid
358
+ epipolar_images_right.tiling_grid = epipolar_regions_grid
359
+
360
+ # Compute overlaps
361
+ (
362
+ epipolar_images_left.overlaps,
363
+ epipolar_images_right.overlaps,
364
+ used_disp_min,
365
+ used_disp_max,
366
+ ) = format_transformation.grid_margins_2_overlaps(
367
+ epipolar_images_left.tiling_grid, margins_fun
368
+ )
369
+
370
+ # add image type in attributes for future checking
371
+ if texture_bands is not None:
372
+ im_type = inputs.rasterio_get_image_type(
373
+ sensor_image_left[sens_cst.INPUT_IMG]["bands"][
374
+ texture_bands[0]
375
+ ]["path"]
376
+ )
377
+ else:
378
+ im_type = inputs.rasterio_get_image_type(
379
+ sensor_image_left[sens_cst.INPUT_IMG]["bands"]["b0"]["path"]
380
+ )
381
+
382
+ # update attributes
383
+ epipolar_images_attributes = {
384
+ "largest_epipolar_region": largest_epipolar_region,
385
+ "tile_width": tile_width,
386
+ "tile_height": tile_height,
387
+ "disp_min_tiling": used_disp_min,
388
+ "disp_max_tiling": used_disp_max,
389
+ "image_type": im_type,
390
+ }
391
+
392
+ epipolar_images_left.attributes.update(epipolar_images_attributes)
393
+ epipolar_images_right.attributes.update(epipolar_images_attributes)
394
+
395
+ # Save objects
396
+ if self.save_intermediate_data:
397
+ safe_makedirs(pair_folder)
398
+
399
+ self.orchestrator.add_to_save_lists(
400
+ os.path.join(pair_folder, "epi_img_left.tif"),
401
+ cst.EPI_IMAGE,
402
+ epipolar_images_left,
403
+ cars_ds_name="epi_img_left",
404
+ )
405
+ self.orchestrator.add_to_save_lists(
406
+ os.path.join(pair_folder, "epi_img_right.tif"),
407
+ cst.EPI_IMAGE,
408
+ epipolar_images_right,
409
+ cars_ds_name="epi_img_right",
410
+ )
411
+
412
+ self.orchestrator.add_to_save_lists(
413
+ os.path.join(pair_folder, "epi_img_left_mask.tif"),
414
+ cst.EPI_MSK,
415
+ epipolar_images_left,
416
+ cars_ds_name="epi_img_left_mask",
417
+ dtype=np.uint8,
418
+ )
419
+
420
+ self.orchestrator.add_to_save_lists(
421
+ os.path.join(pair_folder, "epi_img_right_mask.tif"),
422
+ cst.EPI_MSK,
423
+ epipolar_images_right,
424
+ cars_ds_name="epi_img_right_mask",
425
+ dtype=np.uint8,
426
+ )
427
+
428
+ if self.save_intermediate_data and add_classif:
429
+ self.orchestrator.add_to_save_lists(
430
+ os.path.join(pair_folder, "epi_img_left_classif.tif"),
431
+ cst.EPI_CLASSIFICATION,
432
+ epipolar_images_left,
433
+ cars_ds_name="epi_img_left_classif",
434
+ dtype=np.uint8,
435
+ optional_data=True,
436
+ )
437
+
438
+ self.orchestrator.add_to_save_lists(
439
+ os.path.join(pair_folder, "epi_img_right_classif.tif"),
440
+ cst.EPI_CLASSIFICATION,
441
+ epipolar_images_right,
442
+ cars_ds_name="epi_img_right_classif",
443
+ dtype=np.uint8,
444
+ optional_data=True,
445
+ )
446
+
447
+ # Get saving infos in order to save tiles when they are computed
448
+ [
449
+ saving_info_left,
450
+ saving_info_right,
451
+ ] = self.orchestrator.get_saving_infos(
452
+ [epipolar_images_left, epipolar_images_right]
453
+ )
454
+
455
+ logging.info(
456
+ "Number of tiles in epipolar resampling: "
457
+ "row: {} "
458
+ "col: {}".format(
459
+ epipolar_images_left.tiling_grid.shape[0],
460
+ epipolar_images_left.tiling_grid.shape[1],
461
+ )
462
+ )
463
+
464
+ # Add infos to orchestrator.out_json
465
+ updating_dict = {
466
+ application_constants.APPLICATION_TAG: {
467
+ resampling_constants.RESAMPLING_RUN_TAG: {
468
+ pair_key: {resampling_constants.METHOD: self.used_method},
469
+ }
470
+ }
471
+ }
472
+ self.orchestrator.update_out_info(updating_dict)
473
+
474
+ # retrieve data
475
+ epipolar_size_x = grid_left["epipolar_size_x"]
476
+ epipolar_size_y = grid_left["epipolar_size_y"]
477
+ left_images = resampling_wrappers.get_paths_and_bands_from_image(
478
+ sensor_image_left[sens_cst.INPUT_IMG],
479
+ required_bands["left"],
480
+ )
481
+ right_images = resampling_wrappers.get_paths_and_bands_from_image(
482
+ sensor_image_right[sens_cst.INPUT_IMG],
483
+ required_bands["right"],
484
+ )
485
+ grid1 = grid_left
486
+ grid2 = grid_right
487
+ nodata1 = sensor_image_left[sens_cst.INPUT_IMG].get(
488
+ sens_cst.INPUT_NODATA, None
489
+ )
490
+ nodata2 = sensor_image_right[sens_cst.INPUT_IMG].get(
491
+ sens_cst.INPUT_NODATA, None
492
+ )
493
+ mask1 = sensor_image_left.get(sens_cst.INPUT_MSK, None)
494
+ mask2 = sensor_image_right.get(sens_cst.INPUT_MSK, None)
495
+ left_classifs = sensor_image_left.get(
496
+ sens_cst.INPUT_CLASSIFICATION, None
497
+ )
498
+ if left_classifs is not None:
499
+ left_classifs = (
500
+ resampling_wrappers.get_path_and_values_from_classif(
501
+ left_classifs
502
+ )
503
+ )
504
+ right_classifs = sensor_image_right.get(
505
+ sens_cst.INPUT_CLASSIFICATION, None
506
+ )
507
+ if right_classifs is not None:
508
+ right_classifs = (
509
+ resampling_wrappers.get_path_and_values_from_classif(
510
+ right_classifs
511
+ )
512
+ )
513
+
514
+ # Set Epipolar roi
515
+ epi_tilling_grid = epipolar_images_left.tiling_grid
516
+ if epipolar_roi is None:
517
+ epipolar_roi = [
518
+ np.min(epi_tilling_grid[:, :, 0]),
519
+ np.max(epi_tilling_grid[:, :, 1]),
520
+ np.min(epi_tilling_grid[:, :, 2]),
521
+ np.max(epi_tilling_grid[:, :, 3]),
522
+ ]
523
+ # Convert roi to polygon
524
+ epipolar_roi_poly = Polygon(
525
+ [
526
+ [epipolar_roi[0], epipolar_roi[2]],
527
+ [epipolar_roi[0], epipolar_roi[3]],
528
+ [epipolar_roi[1], epipolar_roi[3]],
529
+ [epipolar_roi[1], epipolar_roi[2]],
530
+ [epipolar_roi[0], epipolar_roi[2]],
531
+ ]
532
+ )
533
+
534
+ # Check if tiles are in sensors
535
+ in_sensor_left_array, in_sensor_right_array = (
536
+ resampling_wrappers.check_tiles_in_sensor(
537
+ sensor_image_left,
538
+ sensor_image_right,
539
+ epi_tilling_grid,
540
+ grid_left,
541
+ grid_right,
542
+ geom_plugin,
543
+ )
544
+ )
545
+
546
+ # broadcast grids
547
+ broadcasted_grid1 = self.orchestrator.cluster.scatter(grid1)
548
+ broadcasted_grid2 = self.orchestrator.cluster.scatter(grid2)
549
+
550
+ # Generate Image pair
551
+ for col in range(epipolar_images_left.shape[1]):
552
+ for row in range(epipolar_images_left.shape[0]):
553
+ # Create polygon corresponding to tile
554
+ tile = epi_tilling_grid[row, col]
555
+ tile_roi_poly = Polygon(
556
+ [
557
+ [tile[0], tile[2]],
558
+ [tile[0], tile[3]],
559
+ [tile[1], tile[3]],
560
+ [tile[1], tile[2]],
561
+ [tile[0], tile[2]],
562
+ ]
563
+ )
564
+
565
+ if epipolar_roi_poly.intersects(tile_roi_poly) and (
566
+ in_sensor_left_array[row, col]
567
+ or in_sensor_right_array[row, col]
568
+ ):
569
+ # get overlaps
570
+ left_overlap = cars_dataset.overlap_array_to_dict(
571
+ epipolar_images_left.overlaps[row, col]
572
+ )
573
+ right_overlap = cars_dataset.overlap_array_to_dict(
574
+ epipolar_images_right.overlaps[row, col]
575
+ )
576
+ # get window
577
+ left_window = epipolar_images_left.get_window_as_dict(
578
+ row, col
579
+ )
580
+
581
+ # update saving infos for potential replacement
582
+ full_saving_info_left = ocht.update_saving_infos(
583
+ saving_info_left, row=row, col=col
584
+ )
585
+ full_saving_info_right = ocht.update_saving_infos(
586
+ saving_info_right, row=row, col=col
587
+ )
588
+
589
+ # Compute images
590
+ (
591
+ epipolar_images_left[row, col],
592
+ epipolar_images_right[row, col],
593
+ ) = self.orchestrator.cluster.create_task(
594
+ generate_epipolar_images_wrapper, nout=2
595
+ )(
596
+ left_overlap,
597
+ right_overlap,
598
+ left_window,
599
+ epipolar_size_x,
600
+ epipolar_size_y,
601
+ left_images,
602
+ right_images,
603
+ broadcasted_grid1,
604
+ broadcasted_grid2,
605
+ self.interpolator_image,
606
+ self.interpolator_classif,
607
+ self.interpolator_mask,
608
+ step,
609
+ resolution,
610
+ used_disp_min=used_disp_min[row, col],
611
+ used_disp_max=used_disp_max[row, col],
612
+ add_classif=add_classif,
613
+ mask1=mask1,
614
+ mask2=mask2,
615
+ left_classifs=left_classifs,
616
+ right_classifs=right_classifs,
617
+ nodata1=nodata1,
618
+ nodata2=nodata2,
619
+ saving_info_left=full_saving_info_left,
620
+ saving_info_right=full_saving_info_right,
621
+ )
622
+
623
+ # Remove tile with all nan
624
+ if not in_sensor_left_array[row, col]:
625
+ epipolar_images_left[row, col] = None
626
+ if not in_sensor_right_array[row, col]:
627
+ epipolar_images_right[row, col] = None
628
+
629
+ return epipolar_images_left, epipolar_images_right
630
+
631
+
632
+ # pylint: disable=too-many-positional-arguments
633
+ def generate_epipolar_images_wrapper(
634
+ left_overlaps,
635
+ right_overlaps,
636
+ window,
637
+ epipolar_size_x,
638
+ epipolar_size_y,
639
+ left_imgs,
640
+ right_imgs,
641
+ grid1,
642
+ grid2,
643
+ interpolator_image,
644
+ interpolator_classif,
645
+ interpolator_mask,
646
+ step=None,
647
+ resolution=1,
648
+ used_disp_min=None,
649
+ used_disp_max=None,
650
+ add_classif=True,
651
+ mask1=None,
652
+ mask2=None,
653
+ left_classifs=None,
654
+ right_classifs=None,
655
+ nodata1=0,
656
+ nodata2=0,
657
+ saving_info_left=None,
658
+ saving_info_right=None,
659
+ ) -> Dict[str, Tuple[xr.Dataset, xr.Dataset]]:
660
+ """
661
+ Compute disparity maps from image objects. This function will be run
662
+ as a delayed task. If user want to correctly save dataset, the user must
663
+ provide saving_info_left and right. See cars_dataset.fill_dataset.
664
+
665
+
666
+ :param left_overlaps: Overlaps of left image, with row_min, row_max,
667
+ col_min and col_max keys.
668
+ :type left_overlaps: dict
669
+ :param right_overlaps: Overlaps of right image, with row_min, row_max,
670
+ col_min and col_max keys.
671
+ :type right_overlaps: dict
672
+ :param window: Window considered in generation, with row_min, row_max,
673
+ col_min and col_max keys.
674
+ :type window: dict
675
+
676
+ :return: Left image object, Right image object (if exists)
677
+
678
+ Returned objects are composed of dataset with :
679
+
680
+ - cst.EPI_IMAGE
681
+ - cst.EPI_MSK (if given)
682
+ - cst.EPI_TEXTURE (for left, if given)
683
+ """
684
+
685
+ region, margins = format_transformation.region_margins_from_window(
686
+ window,
687
+ left_overlaps,
688
+ right_overlaps,
689
+ used_disp_min=used_disp_min,
690
+ used_disp_max=used_disp_max,
691
+ )
692
+ # Rectify images
693
+ (
694
+ left_dataset,
695
+ right_dataset,
696
+ left_classif_dataset,
697
+ right_classif_dataset,
698
+ ) = resampling_algo.epipolar_rectify_images(
699
+ left_imgs,
700
+ right_imgs,
701
+ grid1,
702
+ grid2,
703
+ region,
704
+ margins,
705
+ epipolar_size_x,
706
+ epipolar_size_y,
707
+ interpolator_image,
708
+ interpolator_classif,
709
+ interpolator_mask,
710
+ step=step,
711
+ resolution=resolution,
712
+ mask1=mask1,
713
+ mask2=mask2,
714
+ left_classifs=left_classifs,
715
+ right_classifs=right_classifs,
716
+ nodata1=nodata1,
717
+ nodata2=nodata2,
718
+ add_classif=add_classif,
719
+ )
720
+
721
+ # Add classification layers to dataset
722
+ if add_classif:
723
+ if left_classif_dataset:
724
+ left_dataset.coords[cst.BAND_CLASSIF] = left_classif_dataset.attrs[
725
+ cst.BAND_NAMES
726
+ ]
727
+ left_dataset[cst.EPI_CLASSIFICATION] = xr.DataArray(
728
+ left_classif_dataset[cst.EPI_IMAGE].values,
729
+ dims=[cst.BAND_CLASSIF, cst.ROW, cst.COL],
730
+ ).astype(bool)
731
+ if right_classif_dataset:
732
+ right_dataset.coords[cst.BAND_CLASSIF] = (
733
+ right_classif_dataset.attrs[cst.BAND_NAMES]
734
+ )
735
+ right_dataset[cst.EPI_CLASSIFICATION] = xr.DataArray(
736
+ right_classif_dataset[cst.EPI_IMAGE].values,
737
+ dims=[cst.BAND_CLASSIF, cst.ROW, cst.COL],
738
+ ).astype(bool)
739
+
740
+ # Add attributes info
741
+ attributes = {}
742
+ # fill datasets with saving info, window, profile, overlaps for correct
743
+ # saving
744
+ cars_dataset.fill_dataset(
745
+ left_dataset,
746
+ saving_info=saving_info_left,
747
+ window=window,
748
+ profile=None,
749
+ attributes=attributes,
750
+ overlaps=left_overlaps,
751
+ )
752
+
753
+ cars_dataset.fill_dataset(
754
+ right_dataset,
755
+ saving_info=saving_info_right,
756
+ window=window,
757
+ profile=None,
758
+ attributes=attributes,
759
+ overlaps=right_overlaps,
760
+ )
761
+
762
+ return left_dataset, right_dataset