cars 1.0.0rc3__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +40 -0
  3. cars/applications/application.py +117 -0
  4. cars/applications/application_constants.py +29 -0
  5. cars/applications/application_template.py +146 -0
  6. cars/applications/auxiliary_filling/__init__.py +29 -0
  7. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
  10. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
  11. cars/applications/dem_generation/__init__.py +30 -0
  12. cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
  13. cars/applications/dem_generation/bulldozer_config/base_config.yaml +46 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
  15. cars/applications/dem_generation/bulldozer_memory.py +55 -0
  16. cars/applications/dem_generation/dem_generation_algo.py +107 -0
  17. cars/applications/dem_generation/dem_generation_constants.py +32 -0
  18. cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
  19. cars/applications/dense_match_filling/__init__.py +30 -0
  20. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
  21. cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
  22. cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
  23. cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
  24. cars/applications/dense_match_filling/zero_padding_app.py +302 -0
  25. cars/applications/dense_matching/__init__.py +30 -0
  26. cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
  27. cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-313-x86_64-linux-gnu.so +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  31. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  32. cars/applications/dense_matching/cpp/meson.build +9 -0
  33. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  34. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  35. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  36. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  37. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  38. cars/applications/dense_matching/disparity_grid_algo.py +597 -0
  39. cars/applications/dense_matching/loaders/__init__.py +23 -0
  40. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  46. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  47. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  48. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  49. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  50. cars/applications/dsm_filling/__init__.py +32 -0
  51. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  52. cars/applications/dsm_filling/border_interpolation_app.py +278 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  56. cars/applications/dsm_merging/__init__.py +28 -0
  57. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  58. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  59. cars/applications/grid_correction/__init__.py +30 -0
  60. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  61. cars/applications/grid_correction/grid_correction_app.py +557 -0
  62. cars/applications/grid_generation/__init__.py +30 -0
  63. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  64. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  65. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  66. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  67. cars/applications/grid_generation/transform_grid.py +88 -0
  68. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  69. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  70. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  71. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  72. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  73. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  74. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  76. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  77. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  78. cars/applications/rasterization/__init__.py +30 -0
  79. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  80. cars/applications/rasterization/rasterization_algo.py +534 -0
  81. cars/applications/rasterization/rasterization_constants.py +38 -0
  82. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  83. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  84. cars/applications/resampling/__init__.py +28 -0
  85. cars/applications/resampling/abstract_resampling_app.py +187 -0
  86. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  87. cars/applications/resampling/resampling_algo.py +590 -0
  88. cars/applications/resampling/resampling_constants.py +36 -0
  89. cars/applications/resampling/resampling_wrappers.py +309 -0
  90. cars/applications/sensors_subsampling/__init__.py +32 -0
  91. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  92. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  93. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  94. cars/applications/sparse_matching/__init__.py +30 -0
  95. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  96. cars/applications/sparse_matching/sift_app.py +724 -0
  97. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  98. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  99. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  100. cars/applications/triangulation/__init__.py +32 -0
  101. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  102. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  103. cars/applications/triangulation/pc_transform.py +552 -0
  104. cars/applications/triangulation/triangulation_algo.py +371 -0
  105. cars/applications/triangulation/triangulation_constants.py +38 -0
  106. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  107. cars/bundleadjustment.py +750 -0
  108. cars/cars.py +179 -0
  109. cars/conf/__init__.py +23 -0
  110. cars/conf/geoid/egm96.grd +0 -0
  111. cars/conf/geoid/egm96.grd.hdr +15 -0
  112. cars/conf/input_parameters.py +156 -0
  113. cars/conf/mask_cst.py +35 -0
  114. cars/core/__init__.py +23 -0
  115. cars/core/cars_logging.py +402 -0
  116. cars/core/constants.py +191 -0
  117. cars/core/constants_disparity.py +50 -0
  118. cars/core/datasets.py +140 -0
  119. cars/core/geometry/__init__.py +27 -0
  120. cars/core/geometry/abstract_geometry.py +1130 -0
  121. cars/core/geometry/shareloc_geometry.py +604 -0
  122. cars/core/inputs.py +568 -0
  123. cars/core/outputs.py +176 -0
  124. cars/core/preprocessing.py +722 -0
  125. cars/core/projection.py +843 -0
  126. cars/core/roi_tools.py +215 -0
  127. cars/core/tiling.py +774 -0
  128. cars/core/utils.py +164 -0
  129. cars/data_structures/__init__.py +23 -0
  130. cars/data_structures/cars_dataset.py +1544 -0
  131. cars/data_structures/cars_dict.py +74 -0
  132. cars/data_structures/corresponding_tiles_tools.py +186 -0
  133. cars/data_structures/dataframe_converter.py +185 -0
  134. cars/data_structures/format_transformation.py +297 -0
  135. cars/devibrate.py +689 -0
  136. cars/extractroi.py +264 -0
  137. cars/orchestrator/__init__.py +23 -0
  138. cars/orchestrator/achievement_tracker.py +125 -0
  139. cars/orchestrator/cluster/__init__.py +37 -0
  140. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  141. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  142. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  143. cars/orchestrator/cluster/dask_config/README.md +94 -0
  144. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  145. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  146. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  147. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  152. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  153. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  154. cars/orchestrator/cluster/log_wrapper.py +728 -0
  155. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  156. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  160. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  162. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  163. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  164. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  165. cars/orchestrator/memory_tools.py +47 -0
  166. cars/orchestrator/orchestrator.py +755 -0
  167. cars/orchestrator/orchestrator_constants.py +29 -0
  168. cars/orchestrator/registry/__init__.py +23 -0
  169. cars/orchestrator/registry/abstract_registry.py +143 -0
  170. cars/orchestrator/registry/compute_registry.py +106 -0
  171. cars/orchestrator/registry/id_generator.py +116 -0
  172. cars/orchestrator/registry/replacer_registry.py +213 -0
  173. cars/orchestrator/registry/saver_registry.py +363 -0
  174. cars/orchestrator/registry/unseen_registry.py +118 -0
  175. cars/orchestrator/tiles_profiler.py +279 -0
  176. cars/pipelines/__init__.py +26 -0
  177. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  178. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  179. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  180. cars/pipelines/default/__init__.py +26 -0
  181. cars/pipelines/default/default_pipeline.py +1095 -0
  182. cars/pipelines/filling/__init__.py +26 -0
  183. cars/pipelines/filling/filling.py +981 -0
  184. cars/pipelines/formatting/__init__.py +26 -0
  185. cars/pipelines/formatting/formatting.py +190 -0
  186. cars/pipelines/merging/__init__.py +26 -0
  187. cars/pipelines/merging/merging.py +439 -0
  188. cars/pipelines/parameters/__init__.py +0 -0
  189. cars/pipelines/parameters/advanced_parameters.py +256 -0
  190. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  191. cars/pipelines/parameters/application_parameters.py +72 -0
  192. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  193. cars/pipelines/parameters/dsm_inputs.py +349 -0
  194. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  195. cars/pipelines/parameters/output_constants.py +52 -0
  196. cars/pipelines/parameters/output_parameters.py +435 -0
  197. cars/pipelines/parameters/sensor_inputs.py +859 -0
  198. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  199. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  200. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  202. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  204. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  206. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  207. cars/pipelines/pipeline.py +119 -0
  208. cars/pipelines/pipeline_constants.py +38 -0
  209. cars/pipelines/pipeline_template.py +135 -0
  210. cars/pipelines/subsampling/__init__.py +26 -0
  211. cars/pipelines/subsampling/subsampling.py +358 -0
  212. cars/pipelines/surface_modeling/__init__.py +26 -0
  213. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  214. cars/pipelines/tie_points/__init__.py +26 -0
  215. cars/pipelines/tie_points/tie_points.py +536 -0
  216. cars/starter.py +167 -0
  217. cars-1.0.0rc3.dist-info/METADATA +289 -0
  218. cars-1.0.0rc3.dist-info/RECORD +220 -0
  219. cars-1.0.0rc3.dist-info/WHEEL +6 -0
  220. cars-1.0.0rc3.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,388 @@
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
+ Grids module:
23
+ contains functions used for epipolar grid creation and correction
24
+ """
25
+
26
+ # Standard imports
27
+ from __future__ import absolute_import
28
+
29
+ import logging
30
+ import math
31
+ import os
32
+
33
+ # Third party imports
34
+ import numpy as np
35
+ import pandas
36
+ import rasterio as rio
37
+ import xarray as xr
38
+ from affine import Affine
39
+
40
+ # TODO depends on another step (and a later one) : make it independent
41
+ from cars.applications.triangulation.triangulation_algo import (
42
+ triangulate_matches,
43
+ )
44
+ from cars.core import constants as cst
45
+ from cars.core import inputs, projection, tiling
46
+ from cars.orchestrator.cluster.log_wrapper import cars_profile
47
+
48
+
49
+ def get_new_path(path):
50
+ """
51
+ Check path, if exists, creates new one
52
+
53
+ :param path: path to check
54
+ :type path: str
55
+
56
+ :return : new path
57
+ :rtype: str
58
+ """
59
+
60
+ current_increment = 0
61
+ head, tail = os.path.splitext(path)
62
+
63
+ current_path = path
64
+ while os.path.exists(current_path):
65
+ current_increment += 1
66
+ current_path = head + "_" + repr(current_increment) + tail
67
+
68
+ return current_path
69
+
70
+
71
+ def write_grid(grid, fname, origin, spacing):
72
+ """
73
+ Write an epipolar rectification grid to file
74
+
75
+ :param grid: the grid to write
76
+ :type grid: 3D numpy array
77
+ :param fname: the filename to which the grid will be written
78
+ :type fname: string
79
+ :param origin: origin of the grid
80
+ :type origin: (float, float)
81
+ :param spacing: spacing of the grid
82
+ :type spacing: (float, float)
83
+ """
84
+
85
+ geotransform = (
86
+ origin[0] - 0.5 * spacing[0],
87
+ spacing[0],
88
+ 0.0,
89
+ origin[1] - 0.5 * spacing[1],
90
+ 0.0,
91
+ spacing[1],
92
+ )
93
+
94
+ transform = Affine.from_gdal(*geotransform)
95
+
96
+ with rio.open(
97
+ fname,
98
+ "w",
99
+ height=grid.shape[0],
100
+ width=grid.shape[1],
101
+ count=2,
102
+ driver="GTiff",
103
+ dtype=grid.dtype,
104
+ transform=transform,
105
+ ) as dst:
106
+ dst.write_band(1, grid[:, :, 0])
107
+ dst.write_band(2, grid[:, :, 1])
108
+
109
+
110
+ def generate_epipolar_grids( # pylint: disable=too-many-positional-arguments
111
+ sensor1, sensor2, geomodel1, geomodel2, geometry_plugin, epipolar_step
112
+ ):
113
+ """
114
+ Computes the left and right epipolar grids
115
+
116
+ :param sensor1: path to left sensor image
117
+ :param sensor2: path to right sensor image
118
+ :param geomodel1: path and attributes for left geomodel
119
+ :param geomodel2: path and attributes for right geomodel
120
+ :param geometry_plugin: geometry plugin to use
121
+ :type geometry_plugin: AbstractGeometry
122
+ :param epipolar_step: step to use to construct the epipolar grids
123
+ :return: Tuple composed of :
124
+
125
+ - the left epipolar grid as a numpy array
126
+ - the right epipolar grid as a numpy array
127
+ - the left grid origin as a list of float
128
+ - the left grid spacing as a list of float
129
+ - the epipolar image size as a list of int\
130
+ (x-axis size is given with the index 0, y-axis size with index 1)
131
+ - the disparity to altitude ratio as a float
132
+ """
133
+ logging.info("Generating epipolar rectification grid ...")
134
+
135
+ return geometry_plugin.generate_epipolar_grids(
136
+ sensor1,
137
+ sensor2,
138
+ geomodel1,
139
+ geomodel2,
140
+ epipolar_step=epipolar_step,
141
+ )
142
+
143
+
144
+ # pylint: disable=too-many-positional-arguments
145
+ @cars_profile(name="Compute epipolar grid min max", interval=0.5)
146
+ def compute_epipolar_grid_min_max(
147
+ geometry_plugin,
148
+ grid,
149
+ sensor1,
150
+ sensor2,
151
+ geomodel1,
152
+ geomodel2,
153
+ grid1,
154
+ grid2,
155
+ epsg,
156
+ disp_min_tiling,
157
+ disp_max_tiling,
158
+ ):
159
+ """
160
+ Compute ground terrain location of epipolar grids at disp_min and disp_max
161
+
162
+ :param geometry_plugin: geometry plugin to use
163
+ :type geometry_plugin: AbstractGeometry
164
+ :param grid: The epipolar grid to project
165
+ :type grid: np.ndarray of shape (N,M,2)
166
+ :param sensor1: path to left sensor image
167
+ :type sensor1: str
168
+ :param sensor2: path to right sensor image
169
+ :type sensor2: str
170
+ :param geomodel1: path and attributes for left geomodel
171
+ :type geomodel1: dict
172
+ :param geomodel2: path and attributes for right geomodel
173
+ :type geomodel2: dict
174
+ :param grid1: dict of the reference image grid file
175
+ :type grid1: dict
176
+ :param grid2: dict of the secondary image grid file
177
+ :type grid2: dict
178
+ :param epsg: EPSG code of the terrain projection
179
+ :type epsg: Int
180
+ :param disp_min_tiling: Minimum disparity tiling
181
+ :type disp_min_tiling: np ndarray or int
182
+ :param disp_max_tiling: Maximum disparity tiling
183
+ :type disp_max_tiling: np ndarray or int
184
+ :return: a tuple of location grid at disp_min and disp_max
185
+ :rtype: Tuple(np.ndarray, np.ndarray) same shape as grid param
186
+ """
187
+
188
+ if isinstance(disp_min_tiling, np.ndarray):
189
+ disp_min_tiling = np.floor(disp_min_tiling).flatten()
190
+ else:
191
+ disp_min_tiling = math.floor(disp_min_tiling)
192
+ if isinstance(disp_max_tiling, np.ndarray):
193
+ disp_max_tiling = np.ceil(disp_max_tiling).flatten()
194
+ else:
195
+ disp_max_tiling = math.ceil(disp_max_tiling)
196
+
197
+ image_bounds = inputs.rasterio_get_bounds(grid2["path"])
198
+ min_px_right = image_bounds[0]
199
+ max_px_right = image_bounds[2]
200
+
201
+ # Generate disp_min and disp_max matches
202
+ right_cols_min = grid[:, :, 0].flatten() + disp_min_tiling
203
+ matches_min = np.stack(
204
+ (
205
+ grid[:, :, 0].flatten(),
206
+ grid[:, :, 1].flatten(),
207
+ np.clip(right_cols_min, min_px_right, max_px_right),
208
+ grid[:, :, 1].flatten(),
209
+ ),
210
+ axis=1,
211
+ )
212
+
213
+ right_cols_max = grid[:, :, 0].flatten() + disp_max_tiling
214
+ matches_max = np.stack(
215
+ (
216
+ grid[:, :, 0].flatten(),
217
+ grid[:, :, 1].flatten(),
218
+ np.clip(right_cols_max, min_px_right, max_px_right),
219
+ grid[:, :, 1].flatten(),
220
+ ),
221
+ axis=1,
222
+ )
223
+
224
+ # If the matches had to be clipped, log it
225
+ clipped_matches_min = np.argwhere(right_cols_min != matches_min[:, 2])
226
+ clipped_matches_max = np.argwhere(right_cols_max != matches_max[:, 2])
227
+
228
+ nb_elems_clipped = len(clipped_matches_min) + len(clipped_matches_max)
229
+ if nb_elems_clipped > 0:
230
+ logging.info(
231
+ f"{nb_elems_clipped} points were clipped to the right "
232
+ "image's bounds."
233
+ )
234
+
235
+ # Generate corresponding point clouds
236
+ pc_min = triangulate_matches(
237
+ geometry_plugin,
238
+ sensor1,
239
+ sensor2,
240
+ geomodel1,
241
+ geomodel2,
242
+ grid1,
243
+ grid2,
244
+ matches_min,
245
+ interpolation_method="linear",
246
+ )
247
+ pc_max = triangulate_matches(
248
+ geometry_plugin,
249
+ sensor1,
250
+ sensor2,
251
+ geomodel1,
252
+ geomodel2,
253
+ grid1,
254
+ grid2,
255
+ matches_max,
256
+ interpolation_method="linear",
257
+ )
258
+
259
+ # Convert to correct EPSG
260
+ projection.point_cloud_conversion_dataset(pc_min, epsg)
261
+ projection.point_cloud_conversion_dataset(pc_max, epsg)
262
+
263
+ # Form grid_min and grid_max
264
+ grid_min = None
265
+ grid_max = None
266
+ if isinstance(pc_min, xr.Dataset):
267
+ grid_min = np.concatenate(
268
+ (pc_min[cst.X].values, pc_min[cst.Y].values), axis=1
269
+ )
270
+ grid_max = np.concatenate(
271
+ (pc_max[cst.X].values, pc_max[cst.Y].values), axis=1
272
+ )
273
+ elif isinstance(pc_min, pandas.DataFrame):
274
+ grid_min = np.stack(
275
+ (pc_min[cst.X].to_numpy(), pc_min[cst.Y].to_numpy()), axis=-1
276
+ )
277
+ grid_max = np.stack(
278
+ (pc_max[cst.X].to_numpy(), pc_max[cst.Y].to_numpy()), axis=-1
279
+ )
280
+ else:
281
+ logging.error("pc min/max error: point cloud is unknown")
282
+
283
+ return grid_min, grid_max
284
+
285
+
286
+ def terrain_region_to_epipolar( # pylint: disable=too-many-positional-arguments
287
+ region,
288
+ sensor1,
289
+ sensor2,
290
+ geomodel1,
291
+ geomodel2,
292
+ grid_left,
293
+ grid_right,
294
+ geometry_plugin,
295
+ epsg=4326,
296
+ disp_min=0,
297
+ disp_max=0,
298
+ tile_size=100,
299
+ epipolar_size_x=None,
300
+ epipolar_size_y=None,
301
+ ):
302
+ """
303
+ Transform terrain region to epipolar region
304
+
305
+ :param region: terrain region to use
306
+ :param sensor1: path to left sensor image
307
+ :param sensor2: path to right sensor image
308
+ :param geomodel1: path and attributes for left geomodel
309
+ :param geomodel2: path and attributes for right geomodel
310
+ :param grid1: dataset of the reference image grid file
311
+ :param grid2: dataset of the secondary image grid file
312
+ :param geometry_plugin: geometry plugin to use
313
+ :param epsg: epsg
314
+ :param disp_min: minimum disparity
315
+ :param disp_max: maximum disparity
316
+ :param tile_size: tile size for grid
317
+ :param epipolar_size_x: epipolar_size_x
318
+ :param epipolar_size_y: epipolar_size_y
319
+
320
+ :return: epipolar region to use, with tile_size a sample
321
+ """
322
+
323
+ disp_min = int(disp_min)
324
+ disp_max = int(disp_max)
325
+
326
+ # Generate terrain grid only on roi
327
+ xmin = region[0]
328
+ xmax = region[2]
329
+ ymin = region[1]
330
+ ymax = region[3]
331
+ opt_terrain_size = max((xmax - xmin), (ymax - ymin))
332
+ region_grid = tiling.generate_tiling_grid(
333
+ xmin,
334
+ ymin,
335
+ xmax,
336
+ ymax,
337
+ opt_terrain_size,
338
+ opt_terrain_size,
339
+ )
340
+
341
+ # Generate fake epipolar grid
342
+ epipolar_grid = tiling.generate_tiling_grid(
343
+ 0,
344
+ 0,
345
+ epipolar_size_y,
346
+ epipolar_size_x,
347
+ tile_size,
348
+ tile_size,
349
+ )
350
+
351
+ # Compute disp_min and disp_max location for epipolar grid
352
+ (
353
+ epipolar_grid_min,
354
+ epipolar_grid_max,
355
+ ) = compute_epipolar_grid_min_max(
356
+ geometry_plugin,
357
+ tiling.transform_four_layers_to_two_layers_grid(epipolar_grid),
358
+ sensor1,
359
+ sensor2,
360
+ geomodel1,
361
+ geomodel2,
362
+ grid_left,
363
+ grid_right,
364
+ epsg,
365
+ disp_min,
366
+ disp_max,
367
+ )
368
+
369
+ # Compute epipolar points min and max on terrain region
370
+ points_min, points_max = tiling.terrain_grid_to_epipolar(
371
+ region_grid, epipolar_grid, epipolar_grid_min, epipolar_grid_max, epsg
372
+ )
373
+
374
+ # Bouding region of corresponding cell
375
+ epipolar_region_minx = np.min(points_min[:, :, 0])
376
+ epipolar_region_miny = np.min(points_min[:, :, 1])
377
+ epipolar_region_maxx = np.max(points_max[:, :, 0])
378
+ epipolar_region_maxy = np.max(points_max[:, :, 1])
379
+
380
+ # Generate epipolar region
381
+ epipolar_region = [
382
+ epipolar_region_miny,
383
+ epipolar_region_maxy,
384
+ epipolar_region_minx,
385
+ epipolar_region_maxx,
386
+ ]
387
+
388
+ return epipolar_region
@@ -0,0 +1,46 @@
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
+ grid_generation_constants contains all the constants
23
+ used in grid_generation module
24
+ """
25
+
26
+
27
+ GRID_GENERATION_RUN_TAG = "grid_generation"
28
+
29
+ # Run infos
30
+
31
+ GRID_CORRECTION_TAG = "grid_correction"
32
+ CORRECTED_MATCHES_TAG = "corrected_filtered_matches"
33
+
34
+ EPIPOLAR_SIZE_X_TAG = "epipolar_size_x"
35
+ EPIPOLAR_SIZE_Y_TAG = "epipolar_size_y"
36
+ EPIPOLAR_ORIGIN_X_TAG = "epipolar_origin_x"
37
+ EPIPOLAR_ORIGIN_Y_TAG = "epipolar_origin_y"
38
+ EPIPOLAR_SPACING_X_TAG = "epipolar_spacing_x"
39
+ EPIPOLAR_SPACING_Y_TAG = "epipolar_spacing_y"
40
+
41
+ DISP_TO_ALT_RATIO_TAG = "disp_to_alt_ratio"
42
+ LEFT_AZIMUTH_ANGLE_TAG = "left_azimuth_angle"
43
+ LEFT_ELEVATION_ANGLE_TAG = "left_elevation_angle"
44
+ RIGHT_AZIMUTH_ANGLE_TAG = "right_azimuth_angle"
45
+ RIGHT_ELEVATION_ANGLE_TAG = "right_elevation_angle"
46
+ CONVERGENCE_ANGLE_TAG = "convergence_angle"
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2025 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
+ Grids module:
23
+ contains functions used for grid transformation
24
+ """
25
+
26
+ import numpy as np
27
+ import rasterio
28
+
29
+ from cars.applications.grid_generation import grid_generation_algo
30
+
31
+
32
+ def transform_grid_func(grid, resolution, right=False):
33
+ """
34
+ Transform the grid for low res resampling
35
+
36
+ :param grid: the grid
37
+ :type grid: cars_dataset
38
+ :param resolution: the resolution for the resampling
39
+ :type resolution: int
40
+ """
41
+ for key, value in grid.items():
42
+ if right:
43
+ if key not in ("grid_origin", "grid_spacing"):
44
+ scale(key, value, grid, resolution)
45
+ else:
46
+ scale(key, value, grid, resolution)
47
+
48
+ # we need to charge the data to override it
49
+ with rasterio.open(grid["path"]) as src:
50
+ data_left = src.read()
51
+
52
+ grid_generation_algo.write_grid(
53
+ np.transpose(data_left, (1, 2, 0)),
54
+ grid["path"],
55
+ grid["grid_origin"],
56
+ grid["grid_spacing"],
57
+ )
58
+
59
+ return grid
60
+
61
+
62
+ def scale(key, value, grid, resolution):
63
+ """
64
+ Scale attributes by the resolution
65
+ """
66
+
67
+ if key == "grid_origin":
68
+ for i, _ in enumerate(value):
69
+ grid[key][i] = np.floor(value[i] / resolution)
70
+ elif key == "grid_spacing":
71
+ for i, _ in enumerate(value):
72
+ grid[key][i] = np.floor(value[i] / resolution)
73
+ elif key == "disp_to_alt_ratio":
74
+ grid[key] = value * resolution
75
+ elif key == "epipolar_size_x":
76
+ grid[key] = np.floor(value / resolution)
77
+ elif key == "epipolar_size_y":
78
+ grid[key] = np.floor(value / resolution)
79
+ elif key == "epipolar_origin_x":
80
+ grid[key] = np.floor(value / resolution)
81
+ elif key == "epipolar_origin_y":
82
+ grid[key] = np.floor(value / resolution)
83
+ elif key == "epipolar_spacing_x":
84
+ grid[key] = np.floor(value / resolution)
85
+ elif key == "epipolar_spacing":
86
+ grid[key] = np.floor(value / resolution)
87
+ elif key == "epipolar_step":
88
+ grid[key] = np.floor(value / resolution)
@@ -0,0 +1,30 @@
1
+ # !/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2024 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ """
22
+ CARS core epipolar matches ground truth generation module init file
23
+ """
24
+ # flake8: noqa: F401, E501
25
+
26
+ from cars.applications.ground_truth_reprojection import (
27
+ abstract_ground_truth_reprojection_app,
28
+ )
29
+
30
+ from . import direct_localization_app
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2024 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 ground_truth_reprojection
23
+ application class.
24
+ """
25
+
26
+ import logging
27
+ from abc import ABCMeta, abstractmethod
28
+ from typing import Dict
29
+
30
+ from cars.applications.application import Application
31
+ from cars.applications.application_template import ApplicationTemplate
32
+
33
+
34
+ @Application.register("ground_truth_reprojection")
35
+ class GroundTruthReprojection(ApplicationTemplate, metaclass=ABCMeta):
36
+ """
37
+ Epipolar matches ground truth computation
38
+
39
+ """
40
+
41
+ available_applications: Dict = {}
42
+ default_application = "direct_loc"
43
+
44
+ def __new__(cls, conf=None): # pylint: disable=W0613
45
+ """
46
+ Return the required application
47
+ :raises: KeyError when the required application is not registered
48
+ :param conf: configuration for grid generation
49
+ :return: an application_to_use object
50
+
51
+ """
52
+
53
+ ground_truth_computation_method = cls.default_application
54
+
55
+ if bool(conf) is False or "method" not in conf:
56
+ logging.info(
57
+ "Ground truth reprojection method not specified"
58
+ ", default {} is used".format(ground_truth_computation_method)
59
+ )
60
+ else:
61
+ ground_truth_computation_method = conf.get(
62
+ "method", cls.default_application
63
+ )
64
+
65
+ if ground_truth_computation_method not in cls.available_applications:
66
+ logging.error(
67
+ "No GroundTruthReprojection application named {} "
68
+ "registered".format(ground_truth_computation_method)
69
+ )
70
+ raise KeyError(
71
+ "No GroundTruthReprojection application named {} "
72
+ "registered".format(ground_truth_computation_method)
73
+ )
74
+
75
+ logging.info(
76
+ "The GroundTruthReprojection({}) application will be "
77
+ "used".format(ground_truth_computation_method)
78
+ )
79
+
80
+ return super(GroundTruthReprojection, cls).__new__(
81
+ cls.available_applications[ground_truth_computation_method]
82
+ )
83
+
84
+ def __init_subclass__(cls, short_name, **kwargs): # pylint: disable=E0302
85
+ super().__init_subclass__(**kwargs)
86
+ cls.available_applications[short_name] = cls
87
+
88
+ def __init__(self, conf=None):
89
+ """
90
+ Init function of Epipolar matches ground truth computation
91
+
92
+ :param conf: configuration
93
+ :return: an application_to_use object
94
+
95
+ """
96
+
97
+ super().__init__(conf=conf)
98
+
99
+ @abstractmethod
100
+ def run( # pylint: disable=too-many-positional-arguments
101
+ self,
102
+ sensor_left,
103
+ sensor_right,
104
+ grid_left,
105
+ grid_right,
106
+ geom_plugin,
107
+ geom_plugin_dem_median,
108
+ disp_to_alt_ratio,
109
+ auxiliary_values,
110
+ auxiliary_interp,
111
+ orchestrator=None,
112
+ pair_folder=None,
113
+ ): # noqa: C901
114
+ """
115
+ Compute disparity maps from a DSM. This function will be run
116
+ as a delayed task. If user want to correctly save dataset, the user must
117
+ provide saving_info_left and right. See cars_dataset.fill_dataset.
118
+
119
+ :param geom_plugin_dem_median: Geometry plugin with dem median
120
+ :type geom_plugin_dem_median: geometry_plugin
121
+ :param sensor_left: Tiled sensor left image.
122
+ Dict must contain keys: "image", "texture", "geomodel",
123
+ "no_data", "mask". Paths must be absolute.
124
+ :type sensor_left: CarsDataset
125
+ :param grid_left: Grid left.
126
+ :type grid_left: CarsDataset
127
+ :param geom_plugin: Geometry plugin with user's DSM used to generate
128
+ epipolar grids.
129
+ :type geom_plugin: GeometryPlugin
130
+ :param disp_to_alt_ratio: Disp to altitude ratio used for
131
+ performance map.
132
+ :type disp_to_alt_ratio: float
133
+ :param orchestrator: Orchestrator used.
134
+ :type orchestrator: Any
135
+ :param pair_folder: Folder used for current pair.
136
+ :type pair_folder: str
137
+ """