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,599 @@
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 abstract matching application class.
23
+ """
24
+ import logging
25
+ import math
26
+ import os
27
+ from abc import ABCMeta, abstractmethod
28
+ from typing import Dict
29
+
30
+ import numpy as np
31
+ import xarray as xr
32
+ from shareloc.geofunctions.rectification_grid import RectificationGrid
33
+
34
+ import cars.applications.sparse_matching.sparse_matching_constants as sm_cst
35
+ import cars.applications.sparse_matching.sparse_matching_wrappers as sm_wrapper
36
+ import cars.orchestrator.orchestrator as ocht
37
+ from cars.applications import application_constants
38
+ from cars.applications.application import Application
39
+ from cars.applications.application_template import ApplicationTemplate
40
+ from cars.core import constants as cst
41
+ from cars.core import inputs
42
+ from cars.core.utils import safe_makedirs
43
+
44
+
45
+ @Application.register("sparse_matching")
46
+ class SparseMatching(ApplicationTemplate, metaclass=ABCMeta):
47
+ """
48
+ SparseMatching
49
+ """
50
+
51
+ available_applications: Dict = {}
52
+ default_application = "sift"
53
+
54
+ def __new__(cls, conf=None): # pylint: disable=W0613
55
+ """
56
+ Return the required application
57
+ :raises:
58
+ - KeyError when the required application is not registered
59
+
60
+ :param conf: configuration for matching
61
+ :return: a application_to_use object
62
+ """
63
+
64
+ matching_method = cls.default_application
65
+ if bool(conf) is False or "method" not in conf:
66
+ logging.info(
67
+ "Sparse Matching method not specified, default "
68
+ " {} is used".format(matching_method)
69
+ )
70
+ else:
71
+ matching_method = conf.get("method", cls.default_application)
72
+
73
+ if matching_method not in cls.available_applications:
74
+ logging.error(
75
+ "No matching application named {} registered".format(
76
+ matching_method
77
+ )
78
+ )
79
+ raise KeyError(
80
+ "No matching application named {} registered".format(
81
+ matching_method
82
+ )
83
+ )
84
+
85
+ logging.info(
86
+ "The SparseMatching({}) application will be used".format(
87
+ matching_method
88
+ )
89
+ )
90
+
91
+ return super(SparseMatching, cls).__new__(
92
+ cls.available_applications[matching_method]
93
+ )
94
+
95
+ def __init_subclass__(cls, short_name, **kwargs): # pylint: disable=E0302
96
+ super().__init_subclass__(**kwargs)
97
+ for name in short_name:
98
+ cls.available_applications[name] = cls
99
+
100
+ def __init__(self, conf=None):
101
+ """
102
+ Init function of SparseMatching
103
+
104
+ :param conf: configuration
105
+ :return: an application_to_use object
106
+ """
107
+
108
+ super().__init__(conf=conf)
109
+
110
+ @abstractmethod
111
+ def get_tile_margin(self):
112
+ """
113
+ Get tile margin corresponding to sparse matches
114
+
115
+ :return: margin
116
+
117
+ """
118
+
119
+ @abstractmethod
120
+ def get_epipolar_error_upper_bound(self):
121
+ """
122
+ Get epipolar error upper bound corresponding to sparse matches
123
+
124
+ :return: margin
125
+
126
+ """
127
+
128
+ @abstractmethod
129
+ def get_epipolar_error_maximum_bias(self):
130
+ """
131
+ Get epipolar error lower bound corresponding to sparse matches
132
+
133
+ :return: margin
134
+
135
+ """
136
+
137
+ @abstractmethod
138
+ def get_match_filter_constant(self):
139
+ """
140
+ Get get_match_filter_constant :
141
+ constant in the formula to compute threshold of outliers
142
+
143
+ :return: match_filter_constant
144
+
145
+ """
146
+
147
+ @abstractmethod
148
+ def get_match_filter_mean_factor(self):
149
+ """
150
+ Get match_filter_mean_factor :
151
+ factor of mean in the formula
152
+ to compute threshold of outliers
153
+
154
+ :return: match_filter_mean_factor
155
+
156
+ """
157
+
158
+ @abstractmethod
159
+ def get_match_filter_knn(self):
160
+ """
161
+ Get match_filter_knn :
162
+ number of neighboors used to measure isolation of matches
163
+
164
+ :return: match_filter_knn
165
+
166
+ """
167
+
168
+ @abstractmethod
169
+ def get_match_filter_dev_factor(self):
170
+ """
171
+ Get match_filter_dev_factor :
172
+ factor of deviation in the formula
173
+ to compute threshold of outliers
174
+
175
+ :return: match_filter_dev_factor
176
+
177
+ """
178
+
179
+ @abstractmethod
180
+ def get_minimum_nb_matches(self):
181
+ """
182
+ Get minimum_nb_matches :
183
+ get the minimum number of matches
184
+
185
+ :return: minimum_nb_matches
186
+
187
+ """
188
+
189
+ def get_margins_strip_fun(
190
+ self, disp_min=None, disp_max=None, method="sift"
191
+ ):
192
+ """
193
+ Get margins function to use in resampling
194
+
195
+ :param disp_min: disp min for info
196
+ :param disp_max: disp max for info
197
+ :param method: method for the margins
198
+
199
+ :return: margins function
200
+ :rtype: function generating xr.Dataset
201
+
202
+ """
203
+
204
+ # Compute margins
205
+ corner = ["left", "up", "right", "down"]
206
+ data = np.zeros(len(corner))
207
+ col = np.arange(len(corner))
208
+ margins = xr.Dataset(
209
+ {"left_margin": (["col"], data)}, coords={"col": col}
210
+ )
211
+ margins["right_margin"] = xr.DataArray(data, dims=["col"])
212
+
213
+ left_margin = self.get_tile_margin()
214
+
215
+ if method == "sift":
216
+ right_margin = self.get_tile_margin() + int(
217
+ math.floor(
218
+ self.get_epipolar_error_upper_bound()
219
+ + self.get_epipolar_error_maximum_bias()
220
+ )
221
+ )
222
+ else:
223
+ right_margin = left_margin
224
+
225
+ # Compute margins for left region
226
+ margins["left_margin"].data = [0, left_margin, 0, left_margin]
227
+
228
+ # Compute margins for right region
229
+ margins["right_margin"].data = [0, right_margin, 0, right_margin]
230
+
231
+ # add disp range info
232
+ margins.attrs["disp_min"] = disp_min
233
+ margins.attrs["disp_max"] = disp_max
234
+
235
+ logging.info(
236
+ "Margins added to left region for matching: {}".format(
237
+ margins["left_margin"].data
238
+ )
239
+ )
240
+
241
+ logging.info(
242
+ "Margins added to right region for matching: {}".format(
243
+ margins["right_margin"].data
244
+ )
245
+ )
246
+
247
+ def margins_wrapper( # pylint: disable=unused-argument
248
+ row_min, row_max, col_min, col_max
249
+ ):
250
+ """
251
+ Generates margins Dataset used in resampling
252
+
253
+ :param row_min: row min
254
+ :param row_max: row max
255
+ :param col_min: col min
256
+ :param col_max: col max
257
+
258
+ :return: margins
259
+ :rtype: xr.Dataset
260
+ """
261
+
262
+ # Constant margins for all tiles
263
+ return margins
264
+
265
+ return margins_wrapper
266
+
267
+ def get_margins_tile_fun(self, grid_left, disp_range_grid, method="sift"):
268
+ """
269
+ Get Margins function that generates margins needed by
270
+ matching method, to use during resampling
271
+
272
+ :param grid_left: left epipolar grid
273
+ :type grid_left: dict
274
+ :param disp_range_grid: minimum and maximum disparity grid
275
+ :return: function that generates margin for given roi
276
+
277
+ """
278
+
279
+ if method == "sift":
280
+ right_margin = self.get_tile_margin() + int(
281
+ math.floor(
282
+ self.get_epipolar_error_upper_bound()
283
+ + self.get_epipolar_error_maximum_bias()
284
+ )
285
+ )
286
+ else:
287
+ right_margin = self.get_tile_margin()
288
+
289
+ disp_min_grid_arr, _ = inputs.rasterio_read_as_array(
290
+ disp_range_grid["grid_min_path"]
291
+ )
292
+ disp_max_grid_arr, _ = inputs.rasterio_read_as_array(
293
+ disp_range_grid["grid_max_path"]
294
+ )
295
+ step_row = disp_range_grid["step_row"]
296
+ step_col = disp_range_grid["step_col"]
297
+ row_range = disp_range_grid["row_range"]
298
+ col_range = disp_range_grid["col_range"]
299
+
300
+ # get disp_to_alt_ratio
301
+ disp_to_alt_ratio = grid_left["disp_to_alt_ratio"]
302
+
303
+ # Compute global range of logging
304
+ disp_min_global = np.min(disp_min_grid_arr)
305
+ disp_max_global = np.max(disp_max_grid_arr)
306
+
307
+ logging.info(
308
+ "Global Disparity range for current pair: "
309
+ "[{:.3f} pix., {:.3f} pix.] "
310
+ "(or [{:.3f} m., {:.3f} m.])".format(
311
+ disp_min_global,
312
+ disp_max_global,
313
+ disp_min_global * disp_to_alt_ratio,
314
+ disp_max_global * disp_to_alt_ratio,
315
+ )
316
+ )
317
+
318
+ def margins_wrapper(row_min, row_max, col_min, col_max):
319
+ """
320
+ Generates margins Dataset used in resampling
321
+
322
+ :param row_min: row min
323
+ :param row_max: row max
324
+ :param col_min: col min
325
+ :param col_max: col max
326
+
327
+ :return: margins
328
+ :rtype: xr.Dataset
329
+ """
330
+
331
+ assert row_min < row_max
332
+ assert col_min < col_max
333
+
334
+ # Get region in grid
335
+
336
+ grid_row_min = max(0, int(np.floor((row_min - 1) / step_row)) - 1)
337
+ grid_row_max = min(
338
+ len(row_range), int(np.ceil((row_max + 1) / step_row) + 1)
339
+ )
340
+ grid_col_min = max(0, int(np.floor((col_min - 1) / step_col)) - 1)
341
+ grid_col_max = min(
342
+ len(col_range), int(np.ceil((col_max + 1) / step_col)) + 1
343
+ )
344
+
345
+ # Compute disp min and max in row
346
+ disp_min = np.min(
347
+ disp_min_grid_arr[
348
+ grid_row_min:grid_row_max, grid_col_min:grid_col_max
349
+ ]
350
+ )
351
+ disp_max = np.max(
352
+ disp_max_grid_arr[
353
+ grid_row_min:grid_row_max, grid_col_min:grid_col_max
354
+ ]
355
+ )
356
+ # round disp min and max
357
+ disp_min = int(math.floor(disp_min))
358
+ disp_max = int(math.ceil(disp_max))
359
+
360
+ # Compute margins for the correlator
361
+ margins = sm_wrapper.get_margins(
362
+ self.get_tile_margin(), right_margin, disp_min, disp_max
363
+ )
364
+
365
+ return margins
366
+
367
+ return margins_wrapper
368
+
369
+ def filter_matches( # pylint: disable=too-many-positional-arguments
370
+ self,
371
+ epipolar_matches_left,
372
+ grid_left,
373
+ grid_right,
374
+ geom_plugin,
375
+ orchestrator=None,
376
+ pair_key="pair_0",
377
+ pair_folder=None,
378
+ save_matches=False,
379
+ ):
380
+ """
381
+ Transform matches CarsDataset to numpy matches, and filters matches
382
+
383
+ :param cars_orchestrator: orchestrator
384
+ :param epipolar_matches_left: matches. CarsDataset contains:
385
+
386
+ - N x M Delayed tiles \
387
+ Each tile will be a future pandas DataFrame containing:
388
+
389
+ - data : (L, 4) shape matches
390
+ - attributes containing "disp_lower_bound", "disp_upper_bound", \
391
+ "elevation_delta_lower_bound","elevation_delta_upper_bound"
392
+ :type epipolar_matches_left: CarsDataset
393
+ :param grid_left: left epipolar grid dict
394
+ :type grid_left: dict
395
+ :param grid_right: right epipolar grid dict
396
+ :type grid_right: dict
397
+ :param save_matches: true is matches needs to be saved
398
+ :type save_matches: bool
399
+
400
+ :return filtered matches
401
+ :rtype: np.ndarray
402
+
403
+ """
404
+
405
+ # Default orchestrator
406
+ if orchestrator is None:
407
+ # Create default sequential orchestrator for current application
408
+ # be awere, no out_json will be shared between orchestrators
409
+ # No files saved
410
+ cars_orchestrator = ocht.Orchestrator(
411
+ orchestrator_conf={"mode": "sequential"}
412
+ )
413
+ else:
414
+ cars_orchestrator = orchestrator
415
+
416
+ if pair_folder is None:
417
+ pair_folder = os.path.join(cars_orchestrator.out_dir, "tmp")
418
+
419
+ epipolar_error_upper_bound = self.get_epipolar_error_upper_bound()
420
+ epipolar_error_maximum_bias = self.get_epipolar_error_maximum_bias()
421
+
422
+ grid_left = RectificationGrid(
423
+ grid_left["path"],
424
+ interpolator=geom_plugin.interpolator,
425
+ )
426
+ grid_right = RectificationGrid(
427
+ grid_right["path"],
428
+ interpolator=geom_plugin.interpolator,
429
+ )
430
+
431
+ # Concatenated matches
432
+ list_matches = []
433
+ for row in range(epipolar_matches_left.shape[0]):
434
+ for col in range(epipolar_matches_left.shape[1]):
435
+ # CarsDataset containing Pandas DataFrame, not Delayed anymore
436
+ if epipolar_matches_left[row, col] is not None:
437
+ epipolar_matches = epipolar_matches_left[
438
+ row, col
439
+ ].to_numpy()
440
+
441
+ sensor_matches = geom_plugin.matches_to_sensor_coords(
442
+ grid_left,
443
+ grid_right,
444
+ epipolar_matches,
445
+ cst.MATCHES_MODE,
446
+ )
447
+ sensor_matches = np.concatenate(sensor_matches, axis=1)
448
+ matches = np.concatenate(
449
+ [
450
+ epipolar_matches,
451
+ sensor_matches,
452
+ ],
453
+ axis=1,
454
+ )
455
+ list_matches.append(matches)
456
+
457
+ matches = np.concatenate(list_matches)
458
+
459
+ raw_nb_matches = matches.shape[0]
460
+
461
+ logging.info(
462
+ "Raw number of matches found: {} matches".format(raw_nb_matches)
463
+ )
464
+
465
+ # Export matches
466
+ raw_matches_array_path = None
467
+ if save_matches:
468
+ safe_makedirs(pair_folder)
469
+
470
+ logging.info("Writing raw matches file")
471
+ raw_matches_array_path = os.path.join(
472
+ pair_folder, "raw_matches.npy"
473
+ )
474
+ np.save(raw_matches_array_path, matches)
475
+
476
+ # Filter matches that are out of margin
477
+ epipolar_median_shift = np.median(matches[:, 3] - matches[:, 1])
478
+
479
+ if np.abs(epipolar_median_shift) > epipolar_error_maximum_bias:
480
+ epipolar_median_shift = epipolar_error_maximum_bias * np.sign(
481
+ epipolar_median_shift
482
+ )
483
+
484
+ matches = matches[
485
+ ((matches[:, 3] - matches[:, 1]) - epipolar_median_shift)
486
+ >= -epipolar_error_upper_bound
487
+ ]
488
+ matches = matches[
489
+ ((matches[:, 3] - matches[:, 1]) - epipolar_median_shift)
490
+ <= epipolar_error_upper_bound
491
+ ]
492
+
493
+ matches_discarded_message = (
494
+ "{} matches discarded because their epipolar error "
495
+ "is greater than --epipolar_error_upper_bound = {} pix"
496
+ ).format(raw_nb_matches - matches.shape[0], epipolar_error_upper_bound)
497
+
498
+ if epipolar_error_maximum_bias != 0:
499
+ matches_discarded_message += (
500
+ " considering a shift of {} pix".format(epipolar_median_shift)
501
+ )
502
+
503
+ logging.info(matches_discarded_message)
504
+
505
+ filtered_matches_array_path = None
506
+ if save_matches:
507
+ logging.info("Writing filtered matches file")
508
+ filtered_matches_array_path = os.path.join(
509
+ pair_folder, "filtered_matches.npy"
510
+ )
511
+ np.save(filtered_matches_array_path, matches)
512
+
513
+ # Retrieve number of matches
514
+ nb_matches = matches.shape[0]
515
+
516
+ # Check if we have enough matches
517
+ # TODO: we could also make it a warning and continue
518
+ # with uncorrected grid
519
+ # and default disparity range
520
+ if nb_matches < self.get_minimum_nb_matches():
521
+ error_message_matches = (
522
+ "Insufficient amount of matches found ({} < {}), "
523
+ "can not safely estimate epipolar error correction "
524
+ " and disparity range".format(
525
+ nb_matches, self.get_minimum_nb_matches()
526
+ )
527
+ )
528
+ logging.warning(error_message_matches)
529
+
530
+ logging.info(
531
+ "Number of matches kept for epipolar "
532
+ "error correction: {} matches".format(nb_matches)
533
+ )
534
+
535
+ # Compute epipolar error
536
+ if matches.shape[0] > 0:
537
+ epipolar_error = matches[:, 1] - matches[:, 3]
538
+ epi_error_mean = np.mean(epipolar_error)
539
+ epi_error_std = np.std(epipolar_error)
540
+ epi_error_max = np.max(np.fabs(epipolar_error))
541
+ else:
542
+ epi_error_mean = 0
543
+ epi_error_std = 0
544
+ epi_error_max = 0
545
+ logging.info(
546
+ "Epipolar error before correction: mean = {:.3f} pix., "
547
+ "standard deviation = {:.3f} pix., max = {:.3f} pix.".format(
548
+ epi_error_mean,
549
+ epi_error_std,
550
+ epi_error_max,
551
+ )
552
+ )
553
+
554
+ # Update orchestrator out_json
555
+ raw_matches_infos = {
556
+ application_constants.APPLICATION_TAG: {
557
+ sm_cst.MATCH_FILTERING_TAG: {
558
+ pair_key: {
559
+ sm_cst.NUMBER_MATCHES_TAG: nb_matches,
560
+ sm_cst.RAW_NUMBER_MATCHES_TAG: raw_nb_matches,
561
+ sm_cst.BEFORE_CORRECTION_EPI_ERROR_MEAN: epi_error_mean,
562
+ sm_cst.BEFORE_CORRECTION_EPI_ERROR_STD: epi_error_std,
563
+ sm_cst.BEFORE_CORRECTION_EPI_ERROR_MAX: epi_error_max,
564
+ }
565
+ }
566
+ }
567
+ }
568
+ cars_orchestrator.update_out_info(raw_matches_infos)
569
+
570
+ return matches
571
+
572
+ @abstractmethod
573
+ def get_save_matches(self):
574
+ """
575
+ Get save_matches parameter
576
+
577
+ :return: true is save_matches activated
578
+ :rtype: bool
579
+ """
580
+
581
+ @abstractmethod
582
+ def run( # pylint: disable=too-many-positional-arguments
583
+ self,
584
+ epipolar_image_left,
585
+ epipolar_image_right,
586
+ disp_to_alt_ratio,
587
+ orchestrator=None,
588
+ pair_folder=None,
589
+ pair_key="PAIR_0",
590
+ classif_bands_to_mask=None,
591
+ ):
592
+ """
593
+ Run Matching application.
594
+
595
+ Create left and right CarsDataset filled with pandas.DataFrame ,
596
+ corresponding to epipolar 2D disparities, on the same geometry
597
+ that epipolar_images_left and epipolar_images_right.
598
+
599
+ """