cars 1.0.0a2__cp310-cp310-win_amd64.whl → 1.0.0a4__cp310-cp310-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 (144) hide show
  1. cars/__init__.py +3 -3
  2. cars/applications/__init__.py +0 -3
  3. cars/applications/application.py +14 -6
  4. cars/applications/application_template.py +42 -0
  5. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +12 -2
  6. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +2 -2
  7. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +95 -46
  8. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +7 -6
  9. cars/applications/dem_generation/abstract_dem_generation_app.py +9 -5
  10. cars/applications/dem_generation/dem_generation_algo.py +1 -1
  11. cars/applications/dem_generation/dem_generation_wrappers.py +44 -59
  12. cars/applications/dem_generation/dichotomic_generation_app.py +9 -6
  13. cars/applications/dem_generation/rasterization_app.py +112 -43
  14. cars/applications/dense_match_filling/__init__.py +1 -1
  15. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +2 -15
  16. cars/applications/dense_match_filling/fill_disp_algo.py +32 -373
  17. cars/applications/dense_match_filling/fill_disp_wrappers.py +0 -343
  18. cars/applications/dense_match_filling/zero_padding_app.py +10 -5
  19. cars/applications/dense_matching/abstract_dense_matching_app.py +2 -1
  20. cars/applications/dense_matching/census_mccnn_sgm_app.py +48 -60
  21. cars/applications/dense_matching/cpp/dense_matching_cpp.cp310-win_amd64.dll.a +0 -0
  22. cars/applications/dense_matching/cpp/dense_matching_cpp.cp310-win_amd64.pyd +0 -0
  23. cars/applications/dense_matching/dense_matching_algo.py +48 -14
  24. cars/applications/dense_matching/dense_matching_wrappers.py +11 -3
  25. cars/applications/dense_matching/disparity_grid_algo.py +95 -79
  26. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  27. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  28. cars/applications/dense_matching/loaders/pandora_loader.py +169 -34
  29. cars/applications/dsm_filling/border_interpolation_app.py +11 -12
  30. cars/applications/dsm_filling/bulldozer_filling_app.py +16 -15
  31. cars/applications/dsm_filling/exogenous_filling_app.py +14 -14
  32. cars/applications/grid_generation/abstract_grid_generation_app.py +1 -1
  33. cars/applications/grid_generation/epipolar_grid_generation_app.py +4 -2
  34. cars/applications/grid_generation/grid_correction_app.py +4 -1
  35. cars/applications/grid_generation/grid_generation_algo.py +7 -2
  36. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +1 -1
  37. cars/applications/ground_truth_reprojection/direct_localization_app.py +2 -2
  38. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +2 -1
  39. cars/applications/point_cloud_fusion/abstract_pc_fusion_app.py +0 -155
  40. cars/applications/point_cloud_fusion/mapping_to_terrain_tiles_app.py +0 -658
  41. cars/applications/point_cloud_fusion/pc_fusion_algo.py +0 -1339
  42. cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +0 -869
  43. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +11 -6
  44. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +9 -8
  45. cars/applications/point_cloud_outlier_removal/small_components_app.py +101 -270
  46. cars/applications/point_cloud_outlier_removal/statistical_app.py +120 -277
  47. cars/applications/rasterization/abstract_pc_rasterization_app.py +2 -1
  48. cars/applications/rasterization/rasterization_algo.py +18 -6
  49. cars/applications/rasterization/rasterization_wrappers.py +2 -1
  50. cars/applications/rasterization/simple_gaussian_app.py +88 -116
  51. cars/applications/resampling/abstract_resampling_app.py +1 -1
  52. cars/applications/resampling/bicubic_resampling_app.py +3 -1
  53. cars/applications/resampling/resampling_algo.py +60 -53
  54. cars/applications/resampling/resampling_wrappers.py +3 -1
  55. cars/applications/sparse_matching/abstract_sparse_matching_app.py +1 -1
  56. cars/applications/sparse_matching/sift_app.py +5 -25
  57. cars/applications/sparse_matching/sparse_matching_algo.py +3 -2
  58. cars/applications/sparse_matching/sparse_matching_wrappers.py +1 -1
  59. cars/applications/triangulation/abstract_triangulation_app.py +1 -1
  60. cars/applications/triangulation/line_of_sight_intersection_app.py +13 -11
  61. cars/applications/triangulation/pc_transform.py +552 -0
  62. cars/applications/triangulation/triangulation_algo.py +6 -4
  63. cars/applications/triangulation/triangulation_wrappers.py +1 -0
  64. cars/bundleadjustment.py +6 -6
  65. cars/cars.py +11 -9
  66. cars/core/cars_logging.py +80 -49
  67. cars/core/constants.py +0 -1
  68. cars/core/datasets.py +5 -2
  69. cars/core/geometry/abstract_geometry.py +364 -22
  70. cars/core/geometry/shareloc_geometry.py +112 -82
  71. cars/core/inputs.py +72 -19
  72. cars/core/outputs.py +1 -1
  73. cars/core/preprocessing.py +17 -3
  74. cars/core/projection.py +126 -6
  75. cars/core/tiling.py +10 -3
  76. cars/data_structures/cars_dataset.py +12 -10
  77. cars/data_structures/corresponding_tiles_tools.py +0 -103
  78. cars/data_structures/format_transformation.py +4 -1
  79. cars/devibrate.py +6 -3
  80. cars/extractroi.py +20 -21
  81. cars/orchestrator/cluster/abstract_cluster.py +15 -5
  82. cars/orchestrator/cluster/abstract_dask_cluster.py +6 -2
  83. cars/orchestrator/cluster/dask_jobqueue_utils.py +1 -1
  84. cars/orchestrator/cluster/log_wrapper.py +149 -22
  85. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +12 -4
  86. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +2 -2
  87. cars/orchestrator/cluster/pbs_dask_cluster.py +1 -1
  88. cars/orchestrator/cluster/sequential_cluster.py +5 -4
  89. cars/orchestrator/cluster/slurm_dask_cluster.py +1 -1
  90. cars/orchestrator/orchestrator.py +15 -4
  91. cars/orchestrator/registry/id_generator.py +1 -0
  92. cars/orchestrator/registry/saver_registry.py +2 -2
  93. cars/pipelines/conf_resolution/conf_final_resolution.json +5 -3
  94. cars/pipelines/default/default_pipeline.py +461 -1052
  95. cars/pipelines/parameters/advanced_parameters.py +91 -64
  96. cars/pipelines/parameters/advanced_parameters_constants.py +6 -5
  97. cars/pipelines/parameters/application_parameters.py +71 -0
  98. cars/pipelines/parameters/depth_map_inputs.py +0 -314
  99. cars/pipelines/parameters/dsm_inputs.py +40 -4
  100. cars/pipelines/parameters/output_parameters.py +44 -8
  101. cars/pipelines/parameters/sensor_inputs.py +122 -73
  102. cars/pipelines/parameters/sensor_inputs_constants.py +0 -2
  103. cars/pipelines/parameters/sensor_loaders/__init__.py +4 -3
  104. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +106 -0
  105. cars/pipelines/parameters/sensor_loaders/{basic_sensor_loader.py → basic_image_loader.py} +16 -22
  106. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +121 -0
  107. cars/pipelines/parameters/sensor_loaders/{pivot_sensor_loader.py → pivot_image_loader.py} +10 -21
  108. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
  109. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +1 -3
  110. cars/pipelines/pipeline_template.py +1 -3
  111. cars/pipelines/unit/unit_pipeline.py +676 -1070
  112. cars/starter.py +4 -3
  113. cars-1.0.0a4.dist-info/DELVEWHEEL +2 -0
  114. {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/METADATA +135 -53
  115. {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/RECORD +120 -134
  116. cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
  117. cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
  118. cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
  119. cars/applications/dense_match_filling/cpp/__init__.py +0 -0
  120. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp310-win_amd64.dll.a +0 -0
  121. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp310-win_amd64.pyd +0 -0
  122. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.py +0 -72
  123. cars/applications/dense_match_filling/cpp/includes/dense_match_filling.hpp +0 -46
  124. cars/applications/dense_match_filling/cpp/meson.build +0 -9
  125. cars/applications/dense_match_filling/cpp/src/bindings.cpp +0 -11
  126. cars/applications/dense_match_filling/cpp/src/dense_match_filling.cpp +0 -142
  127. cars/applications/dense_match_filling/plane_app.py +0 -556
  128. cars/applications/hole_detection/__init__.py +0 -30
  129. cars/applications/hole_detection/abstract_hole_detection_app.py +0 -125
  130. cars/applications/hole_detection/cloud_to_bbox_app.py +0 -346
  131. cars/applications/hole_detection/hole_detection_algo.py +0 -144
  132. cars/applications/hole_detection/hole_detection_wrappers.py +0 -53
  133. cars/applications/point_cloud_denoising/__init__.py +0 -29
  134. cars/applications/point_cloud_denoising/abstract_pc_denoising_app.py +0 -273
  135. cars/applications/point_cloud_fusion/__init__.py +0 -30
  136. cars/applications/point_cloud_fusion/cloud_fusion_constants.py +0 -39
  137. cars/applications/sparse_matching/pandora_sparse_matching_app.py +0 -0
  138. cars/pipelines/parameters/depth_map_inputs_constants.py +0 -25
  139. cars-1.0.0a2.dist-info/DELVEWHEEL +0 -2
  140. cars.libs/libgcc_s_seh-1-f2b6825d483bdf14050493af93b5997d.dll +0 -0
  141. cars.libs/libstdc++-6-6b0059df6bc601df5a0f18a5805eea05.dll +0 -0
  142. cars.libs/libwinpthread-1-e01b8e85fd67c2b861f64d4ccc7df607.dll +0 -0
  143. {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/WHEEL +0 -0
  144. {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/entry_points.txt +0 -0
@@ -30,7 +30,7 @@ import numpy as np
30
30
  import rasterio as rio
31
31
  import shareloc.geofunctions.rectification as rectif
32
32
  import xarray as xr
33
- from json_checker import Checker
33
+ from json_checker import And, Checker
34
34
  from shareloc.dtm_reader import dtm_reader
35
35
  from shareloc.geofunctions import localization
36
36
  from shareloc.geofunctions.rectification_grid import RectificationGrid
@@ -41,7 +41,7 @@ from shareloc.geomodels.rpc import RPC
41
41
  from shareloc.image import Image
42
42
 
43
43
  from cars.core import constants as cst
44
- from cars.core import inputs, projection
44
+ from cars.core import projection
45
45
  from cars.core.geometry.abstract_geometry import AbstractGeometry
46
46
 
47
47
  GRID_TYPE = "GRID"
@@ -56,13 +56,15 @@ class SharelocGeometry(AbstractGeometry):
56
56
  Shareloc geometry class
57
57
  """
58
58
 
59
- def __init__(
59
+ def __init__( # pylint: disable=too-many-positional-arguments
60
60
  self,
61
61
  geometry_plugin_conf,
62
62
  dem=None,
63
63
  geoid=None,
64
64
  default_alt=None,
65
65
  pairs_for_roi=None,
66
+ scaling_coeff=1,
67
+ output_dem_dir=None,
66
68
  ):
67
69
 
68
70
  super().__init__(
@@ -71,50 +73,28 @@ class SharelocGeometry(AbstractGeometry):
71
73
  geoid=geoid,
72
74
  default_alt=default_alt,
73
75
  pairs_for_roi=pairs_for_roi,
76
+ scaling_coeff=scaling_coeff,
77
+ output_dem_dir=output_dem_dir,
74
78
  )
75
79
 
76
- self.dem_roi = None
77
- self.roi_shareloc = None
78
- self.elevation = None
79
-
80
- # a margin is needed for cubic interpolation
81
- self.rectification_grid_margin = 0
82
- if self.interpolator == "cubic":
83
- self.rectification_grid_margin = 5
84
-
85
- # compute roi only when generating geometry object with dem
86
- # even if dem is None
87
- if geoid is not None and pairs_for_roi is not None:
88
- self.dem_roi_epsg = 4326
89
- if dem is not None:
90
- # Get dem epsg
91
- self.dem_roi_epsg = inputs.rasterio_get_epsg(dem)
92
-
93
- self.roi_shareloc = self.get_roi(
94
- pairs_for_roi,
95
- self.dem_roi_epsg,
96
- z_min=0,
97
- z_max=0,
98
- margin=self.dem_roi_margin,
99
- )
100
- # change convention
101
- self.dem_roi = [
102
- self.roi_shareloc[1],
103
- self.roi_shareloc[0],
104
- self.roi_shareloc[3],
105
- self.roi_shareloc[2],
106
- ]
107
-
108
80
  if dem is not None:
109
-
110
81
  # fill_nodata option should be set when dealing with void in DTM
111
- # see shareloc DTM limitations in sphinx doc for further details
112
-
82
+ # see shareloc DTM limitations in sphinx doc for further detailsd
113
83
  try:
84
+ if self.dem_roi is None:
85
+ roi_shareloc = None
86
+ else:
87
+ # From (x, y) to (y, x)
88
+ roi_shareloc = [
89
+ self.dem_roi[1],
90
+ self.dem_roi[0],
91
+ self.dem_roi[3],
92
+ self.dem_roi[2],
93
+ ]
114
94
  dtm_image = dtm_reader(
115
- dem,
116
- geoid,
117
- roi=self.roi_shareloc,
95
+ self.dem,
96
+ self.geoid,
97
+ roi=roi_shareloc,
118
98
  roi_is_in_physical_space=True,
119
99
  fill_nodata="mean",
120
100
  fill_value=0.0,
@@ -141,7 +121,56 @@ class SharelocGeometry(AbstractGeometry):
141
121
  else:
142
122
  self.elevation = default_alt
143
123
 
144
- def get_roi(self, pairs_for_roi, epsg, z_min=0, z_max=0, margin=0.012):
124
+ def check_conf(self, conf):
125
+ """
126
+ Check configuration
127
+
128
+ :param conf: configuration to check
129
+ :type conf: str or dict
130
+
131
+ :return: full dict
132
+ :rtype: dict
133
+
134
+ """
135
+
136
+ if conf is None:
137
+ raise RuntimeError("Geometry plugin configuration is None")
138
+
139
+ overloaded_conf = {}
140
+
141
+ if isinstance(conf, str):
142
+ conf = {"plugin_name": conf}
143
+
144
+ # overload conf
145
+ overloaded_conf["plugin_name"] = conf.get(
146
+ "plugin_name", "SharelocGeometry"
147
+ )
148
+ overloaded_conf["interpolator"] = conf.get("interpolator", "cubic")
149
+ overloaded_conf["dem_roi_margin"] = conf.get(
150
+ "dem_roi_margin", [0.25, 0.02]
151
+ )
152
+
153
+ geometry_schema = {
154
+ "plugin_name": str,
155
+ "interpolator": And(str, lambda x: x in ["cubic", "linear"]),
156
+ "dem_roi_margin": [float],
157
+ }
158
+
159
+ # Check conf
160
+ checker = Checker(geometry_schema)
161
+ checker.validate(overloaded_conf)
162
+
163
+ return overloaded_conf
164
+
165
+ def get_roi( # pylint: disable=too-many-positional-arguments
166
+ self,
167
+ pairs_for_roi,
168
+ epsg,
169
+ z_min=0,
170
+ z_max=0,
171
+ linear_margin=0,
172
+ constant_margin=0.012,
173
+ ):
145
174
  """
146
175
  Compute region of interest for intersection of DEM
147
176
 
@@ -149,35 +178,17 @@ class SharelocGeometry(AbstractGeometry):
149
178
  :type pairs_for_roi: List[(str, dict, str, dict)]
150
179
  :param dem_epsg: output EPSG code for ROI
151
180
  :type dem_epsg: int
152
- :param margin: margin for ROI in degrees
153
- :type margin: float
181
+ :param linear_margin: margin for ROI (factor of initial ROI size)
182
+ :type linear_margin: float
183
+ :param constant_margin: margin for ROI in degrees
184
+ :type constant_margin: float
154
185
  """
186
+ base_roi = super().get_roi(
187
+ pairs_for_roi, epsg, z_min, z_max, linear_margin, constant_margin
188
+ )
189
+
155
190
  coords_list = []
156
- for image1, geomodel1, image2, geomodel2 in pairs_for_roi:
157
- # Footprint of left image with altitude z_min
158
- coords_list.extend(
159
- self.image_envelope(
160
- image1["main_file"], geomodel1, elevation=z_min
161
- )
162
- )
163
- # Footprint of left image with altitude z_max
164
- coords_list.extend(
165
- self.image_envelope(
166
- image1["main_file"], geomodel1, elevation=z_max
167
- )
168
- )
169
- # Footprint of right image with altitude z_min
170
- coords_list.extend(
171
- self.image_envelope(
172
- image2["main_file"], geomodel2, elevation=z_min
173
- )
174
- )
175
- # Footprint of right image with altitude z_max
176
- coords_list.extend(
177
- self.image_envelope(
178
- image2["main_file"], geomodel2, elevation=z_max
179
- )
180
- )
191
+ for image1, geomodel1, _, geomodel2 in pairs_for_roi:
181
192
  # Footprint of rectification grid (with margins)
182
193
  image1 = SharelocGeometry.load_image(image1["main_file"])
183
194
  geomodel1 = self.load_geom_model(geomodel1)
@@ -204,28 +215,45 @@ class SharelocGeometry(AbstractGeometry):
204
215
  )
205
216
  lat_min, lon_min, lat_max, lon_max = list(epipolar_extent)
206
217
  coords_list.extend([(lon_min, lat_min), (lon_max, lat_max)])
218
+
207
219
  lon_list, lat_list = list(zip(*coords_list)) # noqa: B905
208
220
  roi = [
209
- min(lat_list) - margin,
210
- min(lon_list) - margin,
211
- max(lat_list) + margin,
212
- max(lon_list) + margin,
221
+ min(lon_list) - constant_margin,
222
+ min(lat_list) - constant_margin,
223
+ max(lon_list) + constant_margin,
224
+ max(lat_list) + constant_margin,
213
225
  ]
214
226
  points = np.array(
215
227
  [
216
- (roi[1], roi[0], 0),
217
- (roi[3], roi[2], 0),
218
- (roi[1], roi[0], 0),
219
- (roi[3], roi[2], 0),
228
+ (roi[0], roi[1], 0),
229
+ (roi[2], roi[3], 0),
230
+ (roi[0], roi[1], 0),
231
+ (roi[2], roi[3], 0),
220
232
  ]
221
233
  )
222
234
  new_points = projection.point_cloud_conversion(points, 4326, epsg)
223
235
  roi = [
224
- min(new_points[:, 1]),
225
236
  min(new_points[:, 0]),
226
- max(new_points[:, 1]),
237
+ min(new_points[:, 1]),
227
238
  max(new_points[:, 0]),
239
+ max(new_points[:, 1]),
240
+ ]
241
+
242
+ lon_size = roi[2] - roi[0]
243
+ lat_size = roi[3] - roi[1]
244
+
245
+ roi[0] -= linear_margin * lon_size
246
+ roi[1] -= linear_margin * lat_size
247
+ roi[2] += linear_margin * lon_size
248
+ roi[3] += linear_margin * lat_size
249
+
250
+ roi = [
251
+ min(roi[0], base_roi[0]),
252
+ min(roi[1], base_roi[1]),
253
+ max(roi[2], base_roi[2]),
254
+ max(roi[3], base_roi[3]),
228
255
  ]
256
+
229
257
  return roi
230
258
 
231
259
  @staticmethod
@@ -304,7 +332,7 @@ class SharelocGeometry(AbstractGeometry):
304
332
 
305
333
  return sensor, overloaded_geomodel
306
334
 
307
- def triangulate(
335
+ def triangulate( # pylint: disable=too-many-positional-arguments
308
336
  self,
309
337
  sensor1,
310
338
  sensor2,
@@ -315,6 +343,7 @@ class SharelocGeometry(AbstractGeometry):
315
343
  grid1: Union[dict, RectificationGrid],
316
344
  grid2: Union[dict, RectificationGrid],
317
345
  roi_key: Union[None, str] = None,
346
+ interpolation_method=None,
318
347
  ) -> np.ndarray:
319
348
  """
320
349
  Performs triangulation from cars disparity or matches dataset
@@ -396,6 +425,7 @@ class SharelocGeometry(AbstractGeometry):
396
425
 
397
426
  return llh
398
427
 
428
+ # pylint: disable=too-many-positional-arguments
399
429
  def generate_epipolar_grids(
400
430
  self,
401
431
  sensor1,
@@ -479,7 +509,7 @@ class SharelocGeometry(AbstractGeometry):
479
509
  disp_to_alt_ratio,
480
510
  )
481
511
 
482
- def direct_loc(
512
+ def direct_loc( # pylint: disable=too-many-positional-arguments
483
513
  self,
484
514
  sensor,
485
515
  geomodel,
@@ -524,7 +554,7 @@ class SharelocGeometry(AbstractGeometry):
524
554
  )
525
555
  return latlonalt
526
556
 
527
- def inverse_loc(
557
+ def inverse_loc( # pylint: disable=too-many-positional-arguments
528
558
  self,
529
559
  sensor,
530
560
  geomodel,
cars/core/inputs.py CHANGED
@@ -35,7 +35,9 @@ import fiona
35
35
  import numpy as np
36
36
  import rasterio as rio
37
37
  import xarray as xr
38
+ from affine import Affine
38
39
  from json_checker import Checker
40
+ from pyproj import CRS
39
41
  from rasterio.warp import Resampling, calculate_default_transform, reproject
40
42
  from rasterio.windows import Window
41
43
  from shapely.geometry import shape
@@ -106,7 +108,7 @@ def rasterio_get_values(raster_file: str, x_list, y_list, proj_function):
106
108
  cloud_out = proj_function(cloud_in, 4326, file_espg)
107
109
 
108
110
  # get the transform and inverse
109
- aff_tr = descriptor.transform
111
+ aff_tr = rasterio_get_transform(raster_file)
110
112
  np_tr = np.array(
111
113
  [
112
114
  [aff_tr[0], aff_tr[1], aff_tr[2]],
@@ -119,17 +121,28 @@ def rasterio_get_values(raster_file: str, x_list, y_list, proj_function):
119
121
  # convert sensor to pixel coordinates
120
122
  pix_pos = np.hstack([cloud_out, np.ones((len(cloud_out), 1))])
121
123
  pix_pos = inv_tr @ pix_pos.T
122
- pix_pos = pix_pos.T[:, [1, 0]].astype(int)
124
+ pix_pos = pix_pos.T[:, [1, 0]].astype(
125
+ int
126
+ ) # convention (row, col) i.e. (y, x)
127
+
128
+ # crop to dem bounds
129
+ ul_corner = np.array([0, 0])
130
+ lr_corner = np.array([descriptor.height, descriptor.width])
131
+ pix_pos_clipped = np.clip(pix_pos, ul_corner, lr_corner)
132
+ out_of_bounds_pix = np.any(pix_pos != pix_pos_clipped, axis=1)
133
+ pix_pos = pix_pos_clipped
123
134
 
124
135
  # get the data needed
125
136
  min_pt = pix_pos.min(axis=0)
126
137
  max_pt = pix_pos.max(axis=0)
127
138
 
128
- width = max_pt[0] - min_pt[0] + 1
129
- height = max_pt[1] - min_pt[1] + 1
130
- window = Window(min_pt[1], min_pt[0], height, width)
139
+ height = max_pt[0] - min_pt[0] + 1
140
+ width = max_pt[1] - min_pt[1] + 1
141
+ window = Window(min_pt[1], min_pt[0], width, height)
131
142
 
132
143
  data = descriptor.read(1, window=window)
144
+ if data.size == 0:
145
+ return None
133
146
 
134
147
  # read the data for all points
135
148
  max_sampled_pos = np.array(data.shape)[:2] - 1
@@ -141,6 +154,7 @@ def rasterio_get_values(raster_file: str, x_list, y_list, proj_function):
141
154
 
142
155
  if nodata_value is not None:
143
156
  z_list[z_list == nodata_value] = np.nan
157
+ z_list[out_of_bounds_pix] = np.nan
144
158
 
145
159
  return z_list
146
160
 
@@ -252,19 +266,32 @@ def rasterio_get_pixel_points(raster_file: str, terrain_points) -> list:
252
266
 
253
267
  pixel_points = []
254
268
 
255
- with rio.open(raster_file, "r") as descriptor:
256
- for row in range(terrain_points.shape[0]):
257
- pixel_points.append(
258
- rio.transform.rowcol(
259
- descriptor.transform,
260
- terrain_points[row, 0],
261
- terrain_points[row, 1],
262
- )
269
+ for row in range(terrain_points.shape[0]):
270
+ pixel_points.append(
271
+ rio.transform.rowcol(
272
+ rasterio_get_transform(raster_file),
273
+ terrain_points[row, 0],
274
+ terrain_points[row, 1],
263
275
  )
276
+ )
264
277
 
265
278
  return np.array(pixel_points)
266
279
 
267
280
 
281
+ def rasterio_get_resolution(raster_file: str) -> Tuple[float, float]:
282
+ """
283
+ Get the resolution of raster_file
284
+
285
+ :param raster_file: Image file
286
+ :return: The resolution (res_x, res_y)
287
+ :rtype: tuple
288
+ """
289
+ transform = list(rasterio_get_transform(raster_file))
290
+ res_x = transform[0]
291
+ res_y = transform[4]
292
+ return (abs(res_x), abs(res_y))
293
+
294
+
268
295
  def rasterio_get_bounds(
269
296
  raster_file: str, apply_resolution_sign=False
270
297
  ) -> Tuple[int, int]:
@@ -277,8 +304,7 @@ def rasterio_get_bounds(
277
304
 
278
305
  # get sign of resolution
279
306
  if apply_resolution_sign:
280
- profile = rasterio_get_profile(raster_file)
281
- transform = list(profile["transform"])
307
+ transform = list(rasterio_get_transform(raster_file))
282
308
  res_x = transform[0]
283
309
  res_y = transform[4]
284
310
  res_x /= abs(res_x)
@@ -353,15 +379,28 @@ def rasterio_get_profile(raster_file: str) -> Dict:
353
379
  return descriptor.profile
354
380
 
355
381
 
356
- def rasterio_get_transform(raster_file: str) -> Dict:
382
+ def rasterio_get_transform(raster_file: str, convention: str = None) -> Dict:
357
383
  """
358
384
  Get the transform of an image file
359
385
 
360
386
  :param raster_file: Image file
387
+ :param convention: The convention to follow: None, "north" or "south"
361
388
  :return: The transform of the given image
362
389
  """
363
- with rio.open(raster_file, "r") as descriptor:
364
- return descriptor.transform
390
+ with rio.open(raster_file, "r") as dsc:
391
+ src_tr = dsc.transform
392
+
393
+ if convention == "north" and src_tr.e < 0:
394
+ src_tr = Affine(
395
+ src_tr.a, src_tr.b, src_tr.c, -src_tr.d, -src_tr.e, -src_tr.f
396
+ )
397
+
398
+ elif convention == "south" and src_tr.e > 0:
399
+ src_tr = Affine(
400
+ src_tr.a, src_tr.b, src_tr.c, -src_tr.d, -src_tr.e, -src_tr.f
401
+ )
402
+
403
+ return src_tr
365
404
 
366
405
 
367
406
  def rasterio_get_epsg(raster_file: str) -> int:
@@ -378,6 +417,20 @@ def rasterio_get_epsg(raster_file: str) -> int:
378
417
  return epsg
379
418
 
380
419
 
420
+ def rasterio_get_crs(raster_file: str) -> CRS:
421
+ """
422
+ Get the crs of an image file
423
+
424
+ :param raster_file: Image file
425
+ :return: The crs of the given image
426
+ """
427
+ crs = None
428
+ with rio.open(raster_file, "r") as descriptor:
429
+ crs = descriptor.crs
430
+
431
+ return crs
432
+
433
+
381
434
  def rasterio_transform_epsg(file_name, new_epsg):
382
435
  """
383
436
  Modify epsg of raster file
@@ -408,7 +461,7 @@ def rasterio_transform_epsg(file_name, new_epsg):
408
461
  reproject(
409
462
  source=rio.band(src, i),
410
463
  destination=rio.band(dst, i),
411
- src_transform=src.transform,
464
+ src_transform=rasterio_get_transform(file_name),
412
465
  src_crs=src.crs,
413
466
  dst_transform=transform,
414
467
  dst_crs=new_epsg,
cars/core/outputs.py CHANGED
@@ -110,7 +110,7 @@ def write_vector(polys, path_to_file, epsg, driver="GPKG"):
110
110
  vector_file.write(poly_dict)
111
111
 
112
112
 
113
- def rasterio_write_georaster(
113
+ def rasterio_write_georaster( # pylint: disable=too-many-positional-arguments
114
114
  raster_file: str,
115
115
  data: np.ndarray,
116
116
  profile: dict = None,
@@ -72,13 +72,26 @@ def get_utm_zone_as_epsg_code(lon, lat):
72
72
  )
73
73
  return 32632
74
74
 
75
+ if lat > 84:
76
+ logging.warning(
77
+ "Since the latitude is above 84°, the EPSG 32661 will be used."
78
+ )
79
+ return 32661
80
+
81
+ if lat < -80:
82
+ logging.warning(
83
+ "Since the latitude is under -80°, the EPSG 32761 will be used."
84
+ )
85
+ return 32761
86
+
75
87
  zone = utm.from_latlon(lat, lon)[2]
76
88
 
77
89
  north_south = 600 if lat >= 0 else 700
78
90
  return 32000 + north_south + zone
79
91
 
80
92
 
81
- def compute_terrain_bbox( # noqa: 751
93
+ @cars_profile(name="Compute terrain bbox")
94
+ def compute_terrain_bbox( # pylint: disable=too-many-positional-arguments # noqa: 751
82
95
  sensor_image_left,
83
96
  sensor_image_right,
84
97
  epipolar_image_left,
@@ -375,7 +388,7 @@ def compute_roi_poly(input_roi_poly, input_roi_epsg, epsg):
375
388
 
376
389
 
377
390
  @cars_profile(name="Compute epsg")
378
- def compute_epsg(
391
+ def compute_epsg( # pylint: disable=too-many-positional-arguments
379
392
  sensor_image_left,
380
393
  sensor_image_right,
381
394
  grid_left,
@@ -518,6 +531,7 @@ def crop_terrain_bounds_with_roi(roi_poly, xmin, ymin, xmax, ymax):
518
531
  return new_xmin, new_ymin, new_xmax, new_ymax
519
532
 
520
533
 
534
+ @cars_profile(name="Compute terrain bounds")
521
535
  def compute_terrain_bounds(list_of_terrain_roi, roi_poly=None, resolution=0.5):
522
536
  """
523
537
  Compute Terrain bounds of merged pairs
@@ -650,7 +664,7 @@ def convert_optimal_tile_size_with_epsg(
650
664
 
651
665
 
652
666
  @cars_profile(name="Compute epipolar roi")
653
- def compute_epipolar_roi(
667
+ def compute_epipolar_roi( # pylint: disable=too-many-positional-arguments
654
668
  terrain_roi_poly,
655
669
  terrain_roi_epsg,
656
670
  geometry_plugin,