cars 1.0.0a3__cp311-cp311-win_amd64.whl → 1.0.0a4__cp311-cp311-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 (139) hide show
  1. cars/__init__.py +3 -3
  2. cars/applications/__init__.py +0 -3
  3. cars/applications/application_template.py +20 -0
  4. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +12 -2
  5. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +2 -2
  6. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +80 -36
  7. cars/applications/dem_generation/dem_generation_algo.py +1 -1
  8. cars/applications/dem_generation/dem_generation_wrappers.py +23 -57
  9. cars/applications/dem_generation/dichotomic_generation_app.py +3 -3
  10. cars/applications/dem_generation/rasterization_app.py +100 -41
  11. cars/applications/dense_match_filling/__init__.py +1 -1
  12. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +2 -15
  13. cars/applications/dense_match_filling/fill_disp_algo.py +32 -373
  14. cars/applications/dense_match_filling/fill_disp_wrappers.py +0 -343
  15. cars/applications/dense_match_filling/zero_padding_app.py +10 -5
  16. cars/applications/dense_matching/abstract_dense_matching_app.py +2 -1
  17. cars/applications/dense_matching/census_mccnn_sgm_app.py +38 -39
  18. cars/applications/dense_matching/cpp/dense_matching_cpp.cp311-win_amd64.dll.a +0 -0
  19. cars/applications/dense_matching/cpp/dense_matching_cpp.cp311-win_amd64.pyd +0 -0
  20. cars/applications/dense_matching/dense_matching_algo.py +48 -14
  21. cars/applications/dense_matching/dense_matching_wrappers.py +11 -3
  22. cars/applications/dense_matching/disparity_grid_algo.py +84 -62
  23. cars/applications/dense_matching/loaders/pandora_loader.py +91 -33
  24. cars/applications/dsm_filling/border_interpolation_app.py +1 -7
  25. cars/applications/dsm_filling/bulldozer_filling_app.py +2 -8
  26. cars/applications/dsm_filling/exogenous_filling_app.py +4 -9
  27. cars/applications/grid_generation/abstract_grid_generation_app.py +1 -1
  28. cars/applications/grid_generation/epipolar_grid_generation_app.py +4 -2
  29. cars/applications/grid_generation/grid_correction_app.py +4 -1
  30. cars/applications/grid_generation/grid_generation_algo.py +7 -2
  31. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +1 -1
  32. cars/applications/ground_truth_reprojection/direct_localization_app.py +2 -2
  33. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +2 -1
  34. cars/applications/point_cloud_fusion/abstract_pc_fusion_app.py +0 -155
  35. cars/applications/point_cloud_fusion/mapping_to_terrain_tiles_app.py +0 -658
  36. cars/applications/point_cloud_fusion/pc_fusion_algo.py +0 -1339
  37. cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +0 -869
  38. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +2 -1
  39. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +9 -8
  40. cars/applications/point_cloud_outlier_removal/small_components_app.py +96 -267
  41. cars/applications/point_cloud_outlier_removal/statistical_app.py +116 -275
  42. cars/applications/rasterization/abstract_pc_rasterization_app.py +1 -1
  43. cars/applications/rasterization/rasterization_algo.py +18 -6
  44. cars/applications/rasterization/rasterization_wrappers.py +2 -1
  45. cars/applications/rasterization/simple_gaussian_app.py +60 -113
  46. cars/applications/resampling/abstract_resampling_app.py +1 -1
  47. cars/applications/resampling/bicubic_resampling_app.py +3 -1
  48. cars/applications/resampling/resampling_algo.py +16 -4
  49. cars/applications/resampling/resampling_wrappers.py +3 -1
  50. cars/applications/sparse_matching/abstract_sparse_matching_app.py +1 -1
  51. cars/applications/sparse_matching/sift_app.py +3 -3
  52. cars/applications/sparse_matching/sparse_matching_algo.py +3 -2
  53. cars/applications/sparse_matching/sparse_matching_wrappers.py +1 -1
  54. cars/applications/triangulation/abstract_triangulation_app.py +1 -1
  55. cars/applications/triangulation/line_of_sight_intersection_app.py +13 -11
  56. cars/applications/triangulation/pc_transform.py +552 -0
  57. cars/applications/triangulation/triangulation_algo.py +6 -4
  58. cars/applications/triangulation/triangulation_wrappers.py +1 -0
  59. cars/bundleadjustment.py +6 -6
  60. cars/cars.py +11 -9
  61. cars/core/cars_logging.py +80 -49
  62. cars/core/constants.py +0 -1
  63. cars/core/datasets.py +5 -2
  64. cars/core/geometry/abstract_geometry.py +256 -25
  65. cars/core/geometry/shareloc_geometry.py +110 -82
  66. cars/core/inputs.py +57 -19
  67. cars/core/outputs.py +1 -1
  68. cars/core/preprocessing.py +17 -3
  69. cars/core/projection.py +9 -6
  70. cars/core/tiling.py +10 -3
  71. cars/data_structures/cars_dataset.py +5 -5
  72. cars/data_structures/corresponding_tiles_tools.py +0 -103
  73. cars/data_structures/format_transformation.py +4 -1
  74. cars/devibrate.py +6 -3
  75. cars/extractroi.py +20 -21
  76. cars/orchestrator/cluster/abstract_cluster.py +15 -5
  77. cars/orchestrator/cluster/abstract_dask_cluster.py +6 -2
  78. cars/orchestrator/cluster/dask_jobqueue_utils.py +1 -1
  79. cars/orchestrator/cluster/log_wrapper.py +148 -21
  80. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +11 -3
  81. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +2 -2
  82. cars/orchestrator/cluster/pbs_dask_cluster.py +1 -1
  83. cars/orchestrator/cluster/sequential_cluster.py +5 -4
  84. cars/orchestrator/cluster/slurm_dask_cluster.py +1 -1
  85. cars/orchestrator/orchestrator.py +14 -3
  86. cars/orchestrator/registry/id_generator.py +1 -0
  87. cars/orchestrator/registry/saver_registry.py +2 -2
  88. cars/pipelines/conf_resolution/conf_final_resolution.json +5 -3
  89. cars/pipelines/default/default_pipeline.py +462 -1073
  90. cars/pipelines/parameters/advanced_parameters.py +74 -64
  91. cars/pipelines/parameters/advanced_parameters_constants.py +2 -5
  92. cars/pipelines/parameters/application_parameters.py +71 -0
  93. cars/pipelines/parameters/depth_map_inputs.py +0 -314
  94. cars/pipelines/parameters/dsm_inputs.py +40 -4
  95. cars/pipelines/parameters/output_parameters.py +2 -2
  96. cars/pipelines/parameters/sensor_inputs.py +30 -75
  97. cars/pipelines/parameters/sensor_inputs_constants.py +0 -2
  98. cars/pipelines/parameters/sensor_loaders/__init__.py +4 -3
  99. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +106 -0
  100. cars/pipelines/parameters/sensor_loaders/{basic_sensor_loader.py → basic_image_loader.py} +16 -22
  101. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +121 -0
  102. cars/pipelines/parameters/sensor_loaders/{pivot_sensor_loader.py → pivot_image_loader.py} +10 -21
  103. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
  104. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +1 -3
  105. cars/pipelines/pipeline_template.py +1 -3
  106. cars/pipelines/unit/unit_pipeline.py +527 -1016
  107. cars/starter.py +4 -3
  108. cars-1.0.0a4.dist-info/DELVEWHEEL +2 -0
  109. {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/METADATA +135 -53
  110. {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/RECORD +115 -131
  111. cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
  112. cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
  113. cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
  114. cars/applications/dense_match_filling/cpp/__init__.py +0 -0
  115. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp311-win_amd64.dll.a +0 -0
  116. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp311-win_amd64.pyd +0 -0
  117. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.py +0 -72
  118. cars/applications/dense_match_filling/cpp/includes/dense_match_filling.hpp +0 -46
  119. cars/applications/dense_match_filling/cpp/meson.build +0 -9
  120. cars/applications/dense_match_filling/cpp/src/bindings.cpp +0 -11
  121. cars/applications/dense_match_filling/cpp/src/dense_match_filling.cpp +0 -142
  122. cars/applications/dense_match_filling/plane_app.py +0 -556
  123. cars/applications/hole_detection/__init__.py +0 -30
  124. cars/applications/hole_detection/abstract_hole_detection_app.py +0 -125
  125. cars/applications/hole_detection/cloud_to_bbox_app.py +0 -346
  126. cars/applications/hole_detection/hole_detection_algo.py +0 -144
  127. cars/applications/hole_detection/hole_detection_wrappers.py +0 -53
  128. cars/applications/point_cloud_denoising/__init__.py +0 -29
  129. cars/applications/point_cloud_denoising/abstract_pc_denoising_app.py +0 -273
  130. cars/applications/point_cloud_fusion/__init__.py +0 -30
  131. cars/applications/point_cloud_fusion/cloud_fusion_constants.py +0 -39
  132. cars/applications/sparse_matching/pandora_sparse_matching_app.py +0 -0
  133. cars/pipelines/parameters/depth_map_inputs_constants.py +0 -25
  134. cars-1.0.0a3.dist-info/DELVEWHEEL +0 -2
  135. cars.libs/libgcc_s_seh-1-ca70890bbc5723b6d0ea31e9c9cded2b.dll +0 -0
  136. cars.libs/libstdc++-6-00ee19f73d5122a1277c137b1c218401.dll +0 -0
  137. cars.libs/libwinpthread-1-f5042e8e3d21edce20c1bc99445f551b.dll +0 -0
  138. {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/WHEEL +0 -0
  139. {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/entry_points.txt +0 -0
@@ -33,7 +33,10 @@ from typing import Dict, List, Tuple, Union
33
33
  import numpy as np
34
34
  import rasterio as rio
35
35
  import xarray as xr
36
- from json_checker import And, Checker, Or
36
+ from affine import Affine
37
+ from json_checker import And, Checker
38
+ from rasterio.enums import Resampling
39
+ from rasterio.warp import reproject
37
40
  from scipy import interpolate
38
41
  from scipy.interpolate import LinearNDInterpolator
39
42
  from shapely.geometry import Polygon
@@ -41,19 +44,26 @@ from shareloc import proj_utils
41
44
  from shareloc.geofunctions.rectification_grid import RectificationGrid
42
45
 
43
46
  from cars.core import constants as cst
44
- from cars.core import inputs, outputs
47
+ from cars.core import inputs, outputs, projection
45
48
  from cars.core.utils import safe_makedirs
46
49
  from cars.data_structures import cars_dataset
50
+ from cars.orchestrator.cluster.log_wrapper import cars_profile
47
51
 
48
52
 
49
- class AbstractGeometry(metaclass=ABCMeta):
53
+ class AbstractGeometry(metaclass=ABCMeta): # pylint: disable=R0902
50
54
  """
51
55
  AbstractGeometry
52
56
  """
53
57
 
54
58
  available_plugins: Dict = {}
55
59
 
56
- def __new__(cls, geometry_plugin_conf=None, scaling_coeff=1, **kwargs):
60
+ def __new__(
61
+ cls,
62
+ geometry_plugin_conf=None,
63
+ pairs_for_roi=None,
64
+ scaling_coeff=1,
65
+ **kwargs,
66
+ ):
57
67
  """
58
68
  Return the required plugin
59
69
  :raises:
@@ -99,31 +109,218 @@ class AbstractGeometry(metaclass=ABCMeta):
99
109
  )
100
110
  return super().__new__(cls)
101
111
 
102
- def __init__(
112
+ def __init__( # pylint: disable=too-many-positional-arguments
103
113
  self,
104
114
  geometry_plugin_conf,
105
115
  dem=None,
106
116
  geoid=None,
107
117
  default_alt=None,
118
+ pairs_for_roi=None,
108
119
  scaling_coeff=1,
120
+ output_dem_dir=None,
109
121
  **kwargs,
110
122
  ):
111
-
112
123
  self.scaling_coeff = scaling_coeff
113
124
 
114
- config = self.check_conf(geometry_plugin_conf)
125
+ self.used_config = self.check_conf(geometry_plugin_conf)
115
126
 
116
- self.plugin_name = config["plugin_name"]
117
- self.interpolator = config["interpolator"]
118
- self.dem_roi_margin = config["dem_roi_margin"]
119
-
120
- self.dem = dem
127
+ self.plugin_name = self.used_config["plugin_name"]
128
+ self.interpolator = self.used_config["interpolator"]
129
+ self.dem_roi_margin = self.used_config["dem_roi_margin"]
130
+ self.dem = None
121
131
  self.dem_roi = None
122
132
  self.dem_roi_epsg = None
123
133
  self.geoid = geoid
124
134
  self.default_alt = default_alt
135
+ self.elevation = default_alt
136
+ # a margin is needed for cubic interpolation
137
+ self.rectification_grid_margin = 0
138
+ if self.interpolator == "cubic":
139
+ self.rectification_grid_margin = 5
125
140
  self.kwargs = kwargs
126
141
 
142
+ # compute roi only when generating geometry object with dem
143
+ if dem is not None:
144
+ self.dem = dem
145
+ self.default_alt = self.get_dem_median_value()
146
+ self.elevation = self.default_alt
147
+ logging.info(
148
+ "Median value of DEM ({}) will be used as default_alt".format(
149
+ self.default_alt
150
+ )
151
+ )
152
+ if pairs_for_roi is not None:
153
+ self.dem_roi_epsg = inputs.rasterio_get_epsg(dem)
154
+ self.dem_roi = self.get_roi(
155
+ pairs_for_roi,
156
+ self.dem_roi_epsg,
157
+ z_min=-1000,
158
+ z_max=9000,
159
+ linear_margin=self.dem_roi_margin[0],
160
+ constant_margin=self.dem_roi_margin[1],
161
+ )
162
+ if output_dem_dir is not None:
163
+ self.dem = self.extend_dem_to_roi(dem, output_dem_dir)
164
+
165
+ def get_dem_median_value(self):
166
+ """
167
+ Compute dem median value
168
+ :param dem: path of DEM
169
+ """
170
+ with rio.open(self.dem) as dem_file:
171
+ dem_data = dem_file.read(1)
172
+ median_value = np.nanmedian(dem_data)
173
+ median_value = float(median_value)
174
+ return median_value
175
+
176
+ def get_roi( # pylint: disable=too-many-positional-arguments
177
+ self,
178
+ pairs_for_roi,
179
+ epsg,
180
+ z_min=0,
181
+ z_max=0,
182
+ linear_margin=0,
183
+ constant_margin=0.012,
184
+ ):
185
+ """
186
+ Compute region of interest for intersection of DEM
187
+
188
+ :param pairs_for_roi: list of pairs of images and geomodels
189
+ :type pairs_for_roi: List[(str, dict, str, dict)]
190
+ :param dem_epsg: output EPSG code for ROI
191
+ :type dem_epsg: int
192
+ :param linear_margin: margin for ROI (factor of initial ROI size)
193
+ :type linear_margin: float
194
+ :param constant_margin: margin for ROI in degrees
195
+ :type constant_margin: float
196
+ """
197
+ coords_list = []
198
+ z_min = np.array(z_min)
199
+ z_max = np.array(z_max)
200
+ for image1, geomodel1, image2, geomodel2 in pairs_for_roi:
201
+ # Footprint of left image with altitude z_min
202
+ coords_list.extend(
203
+ self.image_envelope(
204
+ image1["main_file"], geomodel1, elevation=z_min
205
+ )
206
+ )
207
+ # Footprint of left image with altitude z_max
208
+ coords_list.extend(
209
+ self.image_envelope(
210
+ image1["main_file"], geomodel1, elevation=z_max
211
+ )
212
+ )
213
+ # Footprint of right image with altitude z_min
214
+ coords_list.extend(
215
+ self.image_envelope(
216
+ image2["main_file"], geomodel2, elevation=z_min
217
+ )
218
+ )
219
+ # Footprint of right image with altitude z_max
220
+ coords_list.extend(
221
+ self.image_envelope(
222
+ image2["main_file"], geomodel2, elevation=z_max
223
+ )
224
+ )
225
+ lon_list, lat_list = list(zip(*coords_list)) # noqa: B905
226
+ roi = [
227
+ min(lon_list) - constant_margin,
228
+ min(lat_list) - constant_margin,
229
+ max(lon_list) + constant_margin,
230
+ max(lat_list) + constant_margin,
231
+ ]
232
+ points = np.array(
233
+ [
234
+ (roi[0], roi[1], 0),
235
+ (roi[2], roi[3], 0),
236
+ (roi[0], roi[1], 0),
237
+ (roi[2], roi[3], 0),
238
+ ]
239
+ )
240
+ new_points = projection.point_cloud_conversion(points, 4326, epsg)
241
+ roi = [
242
+ min(new_points[:, 0]),
243
+ min(new_points[:, 1]),
244
+ max(new_points[:, 0]),
245
+ max(new_points[:, 1]),
246
+ ]
247
+
248
+ lon_size = roi[2] - roi[0]
249
+ lat_size = roi[3] - roi[1]
250
+
251
+ roi[0] -= linear_margin * lon_size
252
+ roi[1] -= linear_margin * lat_size
253
+ roi[2] += linear_margin * lon_size
254
+ roi[3] += linear_margin * lat_size
255
+
256
+ return roi
257
+
258
+ def extend_dem_to_roi(self, dem, output_dem_dir):
259
+ """
260
+ Extend the size of the dem to the required ROI and fill
261
+ :param dem: path to the input DEM
262
+ :param output_dem_dir: path to write the output extended DEM
263
+ """
264
+ with rio.open(dem) as in_dem:
265
+ src_dem = in_dem.read(1)
266
+ metadata = in_dem.meta
267
+ src_transform = in_dem.transform
268
+ crs = in_dem.crs
269
+ bounds = in_dem.bounds
270
+
271
+ logging.info(
272
+ "DEM bounds : {}, {}, {}, {}".format(
273
+ bounds.left, bounds.top, bounds.right, bounds.bottom
274
+ )
275
+ )
276
+ logging.info(
277
+ "ROI bounds : {}, {}, {}, {}".format(
278
+ self.dem_roi[0],
279
+ self.dem_roi[1],
280
+ self.dem_roi[2],
281
+ self.dem_roi[3],
282
+ )
283
+ )
284
+
285
+ # Longitude
286
+ lon_res = src_transform[0]
287
+ lon_shift = (self.dem_roi[0] - bounds.left) / lon_res
288
+ dst_width = int((self.dem_roi[2] - self.dem_roi[0]) / abs(lon_res)) + 1
289
+ # Latitude
290
+ lat_res = src_transform[4]
291
+ lat_shift = (self.dem_roi[3] - bounds.top) / lat_res
292
+ dst_height = int((self.dem_roi[3] - self.dem_roi[1]) / abs(lat_res)) + 1
293
+
294
+ shift = Affine.translation(lon_shift, lat_shift)
295
+ dst_transform = src_transform * shift
296
+ dst_dem = np.zeros((dst_height, dst_width))
297
+
298
+ reproject(
299
+ source=src_dem,
300
+ destination=dst_dem,
301
+ src_transform=src_transform,
302
+ src_crs=crs,
303
+ dst_transform=dst_transform,
304
+ dst_crs=crs,
305
+ resampling=Resampling.bilinear,
306
+ )
307
+ # Fill nodata
308
+ dst_dem = rio.fill.fillnodata(
309
+ dst_dem,
310
+ mask=~(dst_dem == 0),
311
+ )
312
+ metadata["transform"] = dst_transform
313
+ metadata["height"] = dst_height
314
+ metadata["width"] = dst_width
315
+ metadata["driver"] = "GTiff"
316
+
317
+ out_dem_path = os.path.join(output_dem_dir, "initial_elevation.tif")
318
+
319
+ with rio.open(out_dem_path, "w", **metadata) as dst:
320
+ dst.write(dst_dem, 1)
321
+
322
+ return out_dem_path
323
+
127
324
  @classmethod
128
325
  def register_subclass(cls, short_name: str):
129
326
  """
@@ -169,13 +366,13 @@ class AbstractGeometry(metaclass=ABCMeta):
169
366
  )
170
367
  overloaded_conf["interpolator"] = conf.get("interpolator", "cubic")
171
368
  overloaded_conf["dem_roi_margin"] = conf.get(
172
- "dem_roi_margin", float(self.scaling_coeff * 0.012)
369
+ "dem_roi_margin", [0.75, 0.02]
173
370
  )
174
371
 
175
372
  geometry_schema = {
176
373
  "plugin_name": str,
177
374
  "interpolator": And(str, lambda x: x in ["cubic", "linear"]),
178
- "dem_roi_margin": Or(float, int),
375
+ "dem_roi_margin": [float],
179
376
  }
180
377
 
181
378
  # Check conf
@@ -185,7 +382,7 @@ class AbstractGeometry(metaclass=ABCMeta):
185
382
  return overloaded_conf
186
383
 
187
384
  @abstractmethod
188
- def triangulate(
385
+ def triangulate( # pylint: disable=too-many-positional-arguments
189
386
  self,
190
387
  sensor1,
191
388
  sensor2,
@@ -196,6 +393,7 @@ class AbstractGeometry(metaclass=ABCMeta):
196
393
  grid1: str,
197
394
  grid2: str,
198
395
  roi_key: Union[None, str] = None,
396
+ interpolation_method=None,
199
397
  ) -> np.ndarray:
200
398
  """
201
399
  Performs triangulation from cars disparity or matches dataset
@@ -225,6 +423,7 @@ class AbstractGeometry(metaclass=ABCMeta):
225
423
  :return: True if the products are readable, False otherwise
226
424
  """
227
425
 
426
+ # pylint: disable=too-many-positional-arguments
228
427
  @abstractmethod
229
428
  def generate_epipolar_grids(
230
429
  self, sensor1, sensor2, geomodel1, geomodel2, epipolar_step: int = 30
@@ -259,6 +458,7 @@ class AbstractGeometry(metaclass=ABCMeta):
259
458
  """
260
459
  return geomodel
261
460
 
461
+ # pylint: disable=too-many-positional-arguments
262
462
  def matches_to_sensor_coords(
263
463
  self,
264
464
  grid1: Union[str, cars_dataset.CarsDataset, RectificationGrid],
@@ -267,6 +467,7 @@ class AbstractGeometry(metaclass=ABCMeta):
267
467
  matches_type: str,
268
468
  matches_msk: np.ndarray = None,
269
469
  ul_matches_shift: Tuple[int, int] = None,
470
+ interpolation_method=None,
270
471
  ) -> Tuple[np.ndarray, np.ndarray]:
271
472
  """
272
473
  Convert matches (sparse or dense matches) given in epipolar
@@ -340,10 +541,10 @@ class AbstractGeometry(metaclass=ABCMeta):
340
541
 
341
542
  # convert epipolar matches to sensor coordinates
342
543
  sensor_pos_left = self.sensor_position_from_grid(
343
- grid1, vec_epi_pos_left
544
+ grid1, vec_epi_pos_left, interpolation_method=interpolation_method
344
545
  )
345
546
  sensor_pos_right = self.sensor_position_from_grid(
346
- grid2, vec_epi_pos_right
547
+ grid2, vec_epi_pos_right, interpolation_method=interpolation_method
347
548
  )
348
549
 
349
550
  if matches_type == cst.DISP_MODE:
@@ -379,6 +580,7 @@ class AbstractGeometry(metaclass=ABCMeta):
379
580
  self,
380
581
  grid: Union[dict, RectificationGrid],
381
582
  positions: np.ndarray,
583
+ interpolation_method=None,
382
584
  ) -> np.ndarray:
383
585
  """
384
586
  Interpolate the positions given as inputs using the grid
@@ -451,6 +653,11 @@ class AbstractGeometry(metaclass=ABCMeta):
451
653
  min_row_idx : max_row_idx + 1, min_col_idx : max_col_idx + 1
452
654
  ]
453
655
 
656
+ if interpolation_method is not None:
657
+ method = interpolation_method
658
+ else:
659
+ method = self.interpolator
660
+
454
661
  # interpolate sensor positions
455
662
  interpolator = interpolate.RegularGridInterpolator(
456
663
  (cols_cropped, rows_cropped),
@@ -461,13 +668,35 @@ class AbstractGeometry(metaclass=ABCMeta):
461
668
  ),
462
669
  axis=2,
463
670
  ),
464
- method=self.interpolator,
671
+ method=method,
465
672
  bounds_error=False,
466
673
  fill_value=None,
467
674
  )
468
675
 
469
676
  sensor_positions = interpolator(positions)
470
677
 
678
+ min_row = np.min(sensor_row_positions_cropped)
679
+ max_row = np.max(sensor_row_positions_cropped)
680
+ min_col = np.min(sensor_col_positions_cropped)
681
+ max_col = np.max(sensor_col_positions_cropped)
682
+
683
+ valid_rows = np.logical_and(
684
+ sensor_positions[:, 0] > min_row,
685
+ sensor_positions[:, 0] < max_row,
686
+ )
687
+ valid_cols = np.logical_and(
688
+ sensor_positions[:, 1] > min_col,
689
+ sensor_positions[:, 1] < max_col,
690
+ )
691
+ valid = np.logical_and(valid_rows, valid_cols)
692
+
693
+ if np.sum(~valid) > 0:
694
+ logging.warning(
695
+ "{}/{} points are outside of epipolar grid".format(
696
+ np.sum(~valid), valid.size
697
+ )
698
+ )
699
+
471
700
  # swap
472
701
  sensor_positions[:, [0, 1]] = sensor_positions[:, [1, 0]]
473
702
 
@@ -527,6 +756,7 @@ class AbstractGeometry(metaclass=ABCMeta):
527
756
 
528
757
  return epipolar_positions
529
758
 
759
+ @cars_profile(name="Transform matches", interval=0.5)
530
760
  def transform_matches_from_grids(
531
761
  self,
532
762
  sensor_matches_left,
@@ -563,7 +793,8 @@ class AbstractGeometry(metaclass=ABCMeta):
563
793
 
564
794
  return new_matches_array
565
795
 
566
- def get_sensor_matches(
796
+ @cars_profile(name="Get sensor matches")
797
+ def get_sensor_matches( # pylint: disable=too-many-positional-arguments
567
798
  self,
568
799
  matches_array,
569
800
  grid_left,
@@ -572,7 +803,7 @@ class AbstractGeometry(metaclass=ABCMeta):
572
803
  save_matches,
573
804
  ):
574
805
  """
575
- get sensor matches
806
+ Get sensor matches
576
807
 
577
808
  :param grid_left: path to epipolar grid of image 1
578
809
  :param grid_left: path to epipolar grid of image 2
@@ -605,7 +836,7 @@ class AbstractGeometry(metaclass=ABCMeta):
605
836
  return sensor_matches_left, sensor_matches_right
606
837
 
607
838
  @abstractmethod
608
- def direct_loc(
839
+ def direct_loc( # pylint: disable=too-many-positional-arguments
609
840
  self,
610
841
  sensor,
611
842
  geomodel,
@@ -627,7 +858,7 @@ class AbstractGeometry(metaclass=ABCMeta):
627
858
  :return: Latitude, Longitude, Altitude coordinates list as a numpy array
628
859
  """
629
860
 
630
- def safe_direct_loc(
861
+ def safe_direct_loc( # pylint: disable=too-many-positional-arguments
631
862
  self,
632
863
  sensor,
633
864
  geomodel,
@@ -677,7 +908,7 @@ class AbstractGeometry(metaclass=ABCMeta):
677
908
  return ground_points
678
909
 
679
910
  @abstractmethod
680
- def inverse_loc(
911
+ def inverse_loc( # pylint: disable=too-many-positional-arguments
681
912
  self,
682
913
  sensor,
683
914
  geomodel,
@@ -699,7 +930,7 @@ class AbstractGeometry(metaclass=ABCMeta):
699
930
  :return: X / Y / Z Coordinates list in input image as a numpy array
700
931
  """
701
932
 
702
- def safe_inverse_loc(
933
+ def safe_inverse_loc( # pylint: disable=too-many-positional-arguments
703
934
  self,
704
935
  sensor,
705
936
  geomodel,
@@ -751,7 +982,7 @@ class AbstractGeometry(metaclass=ABCMeta):
751
982
  image_points[:, status] = image_points_retry
752
983
  return image_points[0], image_points[1], image_points[2]
753
984
 
754
- def image_envelope(
985
+ def image_envelope( # pylint: disable=too-many-positional-arguments
755
986
  self,
756
987
  sensor,
757
988
  geomodel,