cars 1.0.0a2__cp313-cp313-win_amd64.whl → 1.0.0a4__cp313-cp313-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.cp313-win_amd64.dll.a +0 -0
  22. cars/applications/dense_matching/cpp/dense_matching_cpp.cp313-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.cp313-win_amd64.dll.a +0 -0
  121. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp313-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
cars/__init__.py CHANGED
@@ -24,14 +24,14 @@ Cars module init file
24
24
 
25
25
 
26
26
  # start delvewheel patch
27
- def _delvewheel_patch_1_11_1():
27
+ def _delvewheel_patch_1_11_2():
28
28
  import os
29
29
  if os.path.isdir(libs_dir := os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'cars.libs'))):
30
30
  os.add_dll_directory(libs_dir)
31
31
 
32
32
 
33
- _delvewheel_patch_1_11_1()
34
- del _delvewheel_patch_1_11_1
33
+ _delvewheel_patch_1_11_2()
34
+ del _delvewheel_patch_1_11_2
35
35
  # end delvewheel patch
36
36
 
37
37
  import os
@@ -30,9 +30,6 @@ from . import dense_matching # noqa: F401
30
30
  from . import dsm_filling # noqa: F401
31
31
  from . import grid_generation # noqa: F401
32
32
  from . import ground_truth_reprojection # noqa: F401
33
- from . import hole_detection # noqa: F401
34
- from . import point_cloud_denoising # noqa: F401
35
- from . import point_cloud_fusion # noqa: F401
36
33
  from . import point_cloud_outlier_removal # noqa: F401
37
34
  from . import rasterization # noqa: F401
38
35
  from . import resampling # noqa: F401
@@ -26,6 +26,8 @@ This module contains class application factory.
26
26
  # Standard imports
27
27
  import logging
28
28
 
29
+ from cars.applications.application_template import ScalingApplicationTemplate
30
+
29
31
  # CARS imports
30
32
  from cars.conf.input_parameters import ConfigType
31
33
 
@@ -46,6 +48,7 @@ class Application:
46
48
  cls,
47
49
  app_name: str,
48
50
  cfg: ConfigType = None,
51
+ scaling_coeff: float = 1,
49
52
  ):
50
53
  """
51
54
  Return the instance of application associated with the application
@@ -55,12 +58,14 @@ class Application:
55
58
  :type app_name: str
56
59
  :param cfg: configuration {'matching_cost_method': value}
57
60
  :type cfg: dictionary
61
+ :param scaling_coeff: scaling factor for resolution
62
+ :type scaling_coeff: float
58
63
  """
59
64
 
60
- return cls.create_app(app_name, cfg)
65
+ return cls.create_app(app_name, cfg, scaling_coeff)
61
66
 
62
67
  @classmethod
63
- def create_app(cls, name: str, cfg: ConfigType):
68
+ def create_app(cls, name: str, cfg: ConfigType, scaling_coeff: float = 1):
64
69
  """Factory command to create the application
65
70
  Return the instance of application associated with the application
66
71
  name given as parameter
@@ -69,16 +74,19 @@ class Application:
69
74
  :type app_name: str
70
75
  :param cfg: configuration {'matching_cost_method': value}
71
76
  :type cfg: dictionary
77
+ :param scaling_coeff: scaling factor for resolution
78
+ :type scaling_coeff: float
72
79
  """
73
- app = None
74
-
75
80
  try:
76
81
  app_class = cls.available_applications[name]
77
82
  except KeyError:
78
83
  logging.error("No application named {0} supported".format(name))
79
84
  return None
80
- app = app_class(conf=cfg)
81
- return app
85
+
86
+ if issubclass(app_class, ScalingApplicationTemplate):
87
+ return app_class(scaling_coeff=scaling_coeff, conf=cfg)
88
+
89
+ return app_class(conf=cfg)
82
90
 
83
91
  @classmethod
84
92
  def print_applications(cls):
@@ -29,6 +29,7 @@ in sub application classes
29
29
 
30
30
  # Standard imports
31
31
  import logging
32
+ import os
32
33
  import pprint
33
34
  from abc import ABCMeta, abstractmethod
34
35
 
@@ -102,3 +103,44 @@ class ApplicationTemplate(metaclass=ABCMeta):
102
103
  """
103
104
 
104
105
  return self.used_config
106
+
107
+ def generate_unknown_dump_dir(self, orchestrator):
108
+ """
109
+ Generate dump dir from orchestrator
110
+
111
+ :param orchestrator: orchestrator
112
+
113
+ :return: dump dir
114
+ """
115
+
116
+ dump_dir = None
117
+ if orchestrator is not None:
118
+ orch_out_dir = orchestrator.out_dir
119
+ dump_dir = os.path.join(
120
+ orch_out_dir,
121
+ "unknown_dump",
122
+ self.__class__.__bases__[0].__name__,
123
+ )
124
+ return dump_dir
125
+
126
+
127
+ class ScalingApplicationTemplate(ApplicationTemplate, metaclass=ABCMeta):
128
+ """
129
+ Template for applications requiring resolution scaling.
130
+
131
+ Inherits from ApplicationTemplate and adds the scaling coefficient
132
+ as a required argument.
133
+ """
134
+
135
+ def __init__(self, scaling_coeff, conf=None):
136
+ """
137
+ Init function of ScalingApplicationTemplate
138
+
139
+ :param scaling_coeff: scaling factor for resolution
140
+ :type scaling_coeff: float
141
+
142
+ :param conf: configuration for application
143
+ :type conf: dict
144
+ """
145
+ self.scaling_coeff = scaling_coeff
146
+ super().__init__(conf=conf)
@@ -86,8 +86,18 @@ class AuxiliaryFilling(ApplicationTemplate, metaclass=ABCMeta):
86
86
  cls.available_applications[short_name] = cls
87
87
 
88
88
  @abstractmethod
89
- def run(
90
- self, dsm_file, color_file, classif_file, dump_dir, orchestrator=None
89
+ def run( # pylint: disable=too-many-positional-arguments
90
+ self,
91
+ dsm_file,
92
+ color_file,
93
+ classif_file,
94
+ dump_dir,
95
+ sensor_inputs,
96
+ pairing,
97
+ geom_plugin,
98
+ texture_bands,
99
+ output_geoid,
100
+ orchestrator=None,
91
101
  ):
92
102
  """
93
103
  Run Auxiliary filling
@@ -28,7 +28,7 @@ import rasterio as rio
28
28
  from scipy import interpolate
29
29
 
30
30
 
31
- def fill_auxiliary(
31
+ def fill_auxiliary( # pylint: disable=too-many-positional-arguments
32
32
  sensor_inputs,
33
33
  pairing,
34
34
  longitudes,
@@ -156,7 +156,7 @@ def fill_auxiliary(
156
156
  return filled_color, filled_classif
157
157
 
158
158
 
159
- def fill_from_one_sensor( # noqa C901
159
+ def fill_from_one_sensor( # pylint: disable=too-many-positional-arguments # noqa C901
160
160
  sensor,
161
161
  filled_color,
162
162
  filled_classif,
@@ -30,6 +30,9 @@ import numpy as np
30
30
  import rasterio as rio
31
31
  import xarray as xr
32
32
  from json_checker import Checker
33
+ from pyproj import CRS
34
+ from rasterio.enums import Resampling
35
+ from rasterio.warp import reproject
33
36
  from shapely.geometry import Polygon
34
37
 
35
38
  import cars.orchestrator.orchestrator as ocht
@@ -93,10 +96,11 @@ class AuxiliaryFillingFromSensors(
93
96
  overloaded_conf["mode"] = conf.get("mode", "fill_nan")
94
97
 
95
98
  if overloaded_conf["mode"] not in ["fill_nan", "full"]:
99
+ # pylint: disable=inconsistent-quotes
96
100
  raise RuntimeError(
97
101
  f"Invalid mode {overloaded_conf['mode']} for "
98
- "AuxiliaryFilling, supported modes are fill_nan "
99
- "and full"
102
+ f"AuxiliaryFilling, supported modes are fill_nan "
103
+ f"and full"
100
104
  )
101
105
 
102
106
  overloaded_conf["texture_interpolator"] = conf.get(
@@ -125,7 +129,8 @@ class AuxiliaryFillingFromSensors(
125
129
 
126
130
  return overloaded_conf
127
131
 
128
- def run(
132
+ # pylint: disable=too-many-positional-arguments
133
+ def run( # noqa: C901
129
134
  self,
130
135
  dsm_file,
131
136
  color_file,
@@ -135,6 +140,7 @@ class AuxiliaryFillingFromSensors(
135
140
  pairing,
136
141
  geom_plugin,
137
142
  texture_bands,
143
+ output_geoid,
138
144
  orchestrator=None,
139
145
  ):
140
146
  """
@@ -157,6 +163,10 @@ class AuxiliaryFillingFromSensors(
157
163
  :type geom_plugin: AbstractGeometry
158
164
  :param texture_bands: list of band names used for output texture
159
165
  :type texture_bands: list
166
+ :param output_geoid: output geoid filename as vertical reference for the
167
+ input DSM. If a boolean is provided instead of a filename True means
168
+ defined relative to cars internal geoid, and false on ellipsoid
169
+ :type output_geoid: OR(bool, str)
160
170
  :param orchestrator: orchestrator used
161
171
  :type orchestrator: Orchestrator
162
172
  """
@@ -187,16 +197,19 @@ class AuxiliaryFillingFromSensors(
187
197
  os.makedirs(dump_dir)
188
198
 
189
199
  color_not_filled_file = os.path.join(dump_dir, "texture_not_filled.tif")
190
- if os.path.exists(color_file):
200
+ if color_file is not None and os.path.exists(color_file):
191
201
  shutil.move(color_file, color_not_filled_file)
192
202
 
193
203
  classification_not_filled_file = None
204
+ # classif_file could be defined without data attached
205
+ if classif_file is not None and not os.path.exists(classif_file):
206
+ classif_file = None
207
+
194
208
  if classif_file is not None:
195
209
  classification_not_filled_file = os.path.join(
196
210
  dump_dir, "classification_not_filled.tif"
197
211
  )
198
- if os.path.exists(classif_file):
199
- shutil.move(classif_file, classification_not_filled_file)
212
+ shutil.move(classif_file, classification_not_filled_file)
200
213
 
201
214
  # Clean dump_dir at the end of processing if required
202
215
  if not self.used_config["save_intermediate_data"]:
@@ -229,19 +242,20 @@ class AuxiliaryFillingFromSensors(
229
242
  color_dtype = np.float32
230
243
  classif_dtype = np.uint8
231
244
 
232
- if os.path.exists(color_not_filled_file):
233
- with rio.open(color_not_filled_file, "r") as descriptor:
234
- texture_no_data_value = descriptor.nodata
235
- color_dtype = descriptor.profile.get("dtype", np.float32)
236
-
237
- self.orchestrator.add_to_save_lists(
238
- os.path.join(dump_dir, color_file),
239
- cst.RASTER_COLOR_IMG,
240
- aux_filled_image,
241
- nodata=texture_no_data_value,
242
- dtype=color_dtype,
243
- cars_ds_name="filled_texture",
244
- )
245
+ if color_file is not None:
246
+ if os.path.exists(color_not_filled_file):
247
+ with rio.open(color_not_filled_file, "r") as descriptor:
248
+ texture_no_data_value = descriptor.nodata
249
+ color_dtype = descriptor.profile.get("dtype", np.float32)
250
+
251
+ self.orchestrator.add_to_save_lists(
252
+ os.path.join(dump_dir, color_file),
253
+ cst.RASTER_COLOR_IMG,
254
+ aux_filled_image,
255
+ nodata=texture_no_data_value,
256
+ dtype=color_dtype,
257
+ cars_ds_name="filled_texture",
258
+ )
245
259
 
246
260
  if classif_file is not None:
247
261
  if os.path.exists(classification_not_filled_file):
@@ -264,12 +278,12 @@ class AuxiliaryFillingFromSensors(
264
278
  [saving_info] = self.orchestrator.get_saving_infos([aux_filled_image])
265
279
 
266
280
  reference_transform = inputs.rasterio_get_transform(dsm_file)
267
- reference_epsg = inputs.rasterio_get_epsg(dsm_file)
281
+ reference_crs = inputs.rasterio_get_crs(dsm_file)
268
282
 
269
283
  # Pre-compute sensor bounds of all sensors to filter sensors that do
270
284
  # not intersect with tile in tasks
271
285
  sensor_bounds = auxiliary_filling_wrappers.compute_sensor_bounds(
272
- sensor_inputs, geom_plugin, reference_epsg
286
+ sensor_inputs, geom_plugin, reference_crs
273
287
  )
274
288
 
275
289
  for row in range(aux_filled_image.shape[0]):
@@ -296,10 +310,11 @@ class AuxiliaryFillingFromSensors(
296
310
  pairing,
297
311
  window,
298
312
  reference_transform,
299
- reference_epsg,
313
+ reference_crs,
300
314
  full_saving_info,
301
315
  geom_plugin,
302
316
  texture_bands,
317
+ output_geoid,
303
318
  mode=self.used_config["mode"],
304
319
  texture_interpolator=self.used_config[
305
320
  "texture_interpolator"
@@ -315,6 +330,7 @@ class AuxiliaryFillingFromSensors(
315
330
  return aux_filled_image
316
331
 
317
332
 
333
+ # pylint: disable=too-many-positional-arguments
318
334
  def filling_from_sensor_wrapper(
319
335
  dsm_file,
320
336
  color_file,
@@ -324,10 +340,11 @@ def filling_from_sensor_wrapper(
324
340
  pairing,
325
341
  window,
326
342
  transform,
327
- epsg,
343
+ crs,
328
344
  saving_info,
329
345
  geom_plugin,
330
346
  texture_bands,
347
+ output_geoid,
331
348
  mode,
332
349
  texture_interpolator,
333
350
  use_mask,
@@ -351,14 +368,18 @@ def filling_from_sensor_wrapper(
351
368
  :type window: dict
352
369
  :param transform: input geo transform
353
370
  :type transform: tuple
354
- :param epsg: input epsg
355
- :type epsg: int
371
+ :param crs: input crs
372
+ :type crs: CRS
356
373
  :param saving_info: saving info for cars orchestrator
357
374
  :type saving_info: dict
358
375
  :param geom_plugin: geometry plugin used for inverse locations
359
376
  :type geom_plugin: AbstractGeometry
360
377
  :param texture_bands: list of band names used for output texture
361
378
  :type texture_bands: list
379
+ :param output_geoid: output geoid filename as vertical reference for the
380
+ input DSM. If a boolean is provided instead of a filename True means
381
+ defined relative to cars internal geoid, and false on ellipsoid
382
+ :type output_geoid: OR(bool, str)
362
383
  :param mode: geometry plugin used for inverse locations
363
384
  :type mode: str
364
385
  :param texture_interpolator: scipy interpolator use to interpolate color
@@ -366,13 +387,17 @@ def filling_from_sensor_wrapper(
366
387
  :type texture_interpolator: str
367
388
  :param use_mask: use mask information from sensors in color computation
368
389
  :type use_mask: bool
369
-
370
390
  """
371
391
 
372
- col_min_ground = window["col_min"] * transform[0] + transform[2]
373
- col_max_ground = window["col_max"] * transform[0] + transform[2]
374
- row_min_ground = window["row_min"] * transform[4] + transform[5]
375
- row_max_ground = window["row_max"] * transform[4] + transform[5]
392
+ col_min = window["col_min"]
393
+ col_max = window["col_max"]
394
+ row_min = window["row_min"]
395
+ row_max = window["row_max"]
396
+
397
+ col_min_ground = col_min * transform[0] + transform[2]
398
+ col_max_ground = col_max * transform[0] + transform[2]
399
+ row_min_ground = row_min * transform[4] + transform[5]
400
+ row_max_ground = row_max * transform[4] + transform[5]
376
401
 
377
402
  ground_polygon = Polygon(
378
403
  [
@@ -384,33 +409,31 @@ def filling_from_sensor_wrapper(
384
409
  ]
385
410
  )
386
411
 
387
- cols = np.arange(
388
- col_min_ground,
389
- col_max_ground,
390
- transform[0],
412
+ cols = (
413
+ np.linspace(col_min, col_max, col_max - col_min) * transform[0]
414
+ + transform[2]
391
415
  )
392
- rows = np.arange(
393
- row_min_ground,
394
- row_max_ground,
395
- transform[4],
416
+ rows = (
417
+ np.linspace(row_min, row_max, row_max - row_min) * transform[4]
418
+ + transform[5]
396
419
  )
397
420
 
398
421
  cols_values_2d, rows_values_2d = np.meshgrid(cols, rows)
399
422
 
400
423
  stacked_values = np.vstack([cols_values_2d.ravel(), rows_values_2d.ravel()])
401
424
 
402
- lon_lat = projection.point_cloud_conversion(
403
- stacked_values.transpose(), epsg, 4326
425
+ lon_lat = projection.point_cloud_conversion_crs(
426
+ stacked_values.transpose(), crs, CRS(4326)
404
427
  )
405
428
 
406
429
  rio_window = rio.windows.Window.from_slices(
407
430
  (
408
- window["row_min"],
409
- window["row_max"],
431
+ row_min,
432
+ row_max,
410
433
  ),
411
434
  (
412
- window["col_min"],
413
- window["col_max"],
435
+ col_min,
436
+ col_max,
414
437
  ),
415
438
  )
416
439
 
@@ -424,6 +447,28 @@ def filling_from_sensor_wrapper(
424
447
  target_mask = dsm_image.read_masks(1, window=rio_window)
425
448
  dsm_profile = dsm_image.profile
426
449
 
450
+ if output_geoid:
451
+ if output_geoid is True:
452
+ geoid_file = geom_plugin.geoid
453
+ else:
454
+ geoid_file = output_geoid
455
+ with rio.open(geoid_file) as in_geoid:
456
+ # Reproject the geoid data to match the DSM
457
+ output_geoid_data = np.empty(
458
+ alt_values.shape, dtype=in_geoid.dtypes[0]
459
+ )
460
+
461
+ reproject(
462
+ source=rio.band(in_geoid, 1),
463
+ destination=output_geoid_data,
464
+ src_transform=in_geoid.transform,
465
+ src_crs=in_geoid.crs,
466
+ dst_transform=transform,
467
+ dst_crs=crs,
468
+ resampling=Resampling.bilinear,
469
+ )
470
+ alt_values += output_geoid_data
471
+
427
472
  nodata_color = None
428
473
  nodata_classif = None
429
474
 
@@ -458,6 +503,7 @@ def filling_from_sensor_wrapper(
458
503
  number_of_classification_bands = 0
459
504
  classification_values = None
460
505
  classification_band_names = None
506
+
461
507
  if classification_file is not None:
462
508
  if os.path.exists(classification_file):
463
509
  with rio.open(classification_file) as classification_image:
@@ -538,8 +584,8 @@ def filling_from_sensor_wrapper(
538
584
  classification_values_filled[band_index, :],
539
585
  )
540
586
 
541
- row_arr = np.array(range(window["row_min"], window["row_max"]))
542
- col_arr = np.array(range(window["col_min"], window["col_max"]))
587
+ row_arr = np.array(range(row_min, row_max))
588
+ col_arr = np.array(range(col_min, col_max))
543
589
 
544
590
  values = {}
545
591
  coords = {cst.ROW: row_arr, cst.COL: col_arr}
@@ -568,6 +614,9 @@ def filling_from_sensor_wrapper(
568
614
  values,
569
615
  coords=coords,
570
616
  )
617
+
618
+ profile.update(crs=crs.to_wkt())
619
+
571
620
  cars_dataset.fill_dataset(
572
621
  dataset,
573
622
  saving_info=saving_info,
@@ -22,12 +22,13 @@
22
22
  this module contains the AuxiliaryFillingFromSensors application class.
23
23
  """
24
24
 
25
+ from pyproj import CRS
25
26
  from shapely.geometry import Polygon
26
27
 
27
- from cars.core.projection import polygon_projection
28
+ from cars.core.projection import polygon_projection_crs
28
29
 
29
30
 
30
- def compute_sensor_bounds(sensor_inputs, geom_plugin, output_epsg):
31
+ def compute_sensor_bounds(sensor_inputs, geom_plugin, output_crs):
31
32
  """
32
33
  Compute bounds of each input sensor that have an associated color or
33
34
  classification image
@@ -38,8 +39,8 @@ def compute_sensor_bounds(sensor_inputs, geom_plugin, output_epsg):
38
39
  :type geom_plugin: AbstractGeometry
39
40
  :param geom_plugin: geometry plugin used for inverse locations
40
41
  :type geom_plugin: AbstractGeometry
41
- :param output_epsg: epsg of the output polygons
42
- :type output_epsg: int
42
+ :param output_crs: crs of the output polygons
43
+ :type output_crs: CRS
43
44
 
44
45
  :return: a dictionary containing a Polygon in output geometry for each
45
46
  valid input sensor
@@ -59,8 +60,8 @@ def compute_sensor_bounds(sensor_inputs, geom_plugin, output_epsg):
59
60
 
60
61
  poly_geo = Polygon([u_l, u_r, l_r, l_l, u_l])
61
62
 
62
- sensor_bounds[sensor_name] = polygon_projection(
63
- poly_geo, 4326, output_epsg
63
+ sensor_bounds[sensor_name] = polygon_projection_crs(
64
+ poly_geo, CRS(4326), output_crs
64
65
  )
65
66
 
66
67
  return sensor_bounds
@@ -26,11 +26,11 @@ from abc import ABCMeta, abstractmethod
26
26
  from typing import Dict
27
27
 
28
28
  from cars.applications.application import Application
29
- from cars.applications.application_template import ApplicationTemplate
29
+ from cars.applications.application_template import ScalingApplicationTemplate
30
30
 
31
31
 
32
32
  @Application.register("dem_generation")
33
- class DemGeneration(ApplicationTemplate, metaclass=ABCMeta):
33
+ class DemGeneration(ScalingApplicationTemplate, metaclass=ABCMeta):
34
34
  """
35
35
  DemGeneration
36
36
  """
@@ -38,13 +38,15 @@ class DemGeneration(ApplicationTemplate, metaclass=ABCMeta):
38
38
  available_applications: Dict = {}
39
39
  default_application = "bulldozer_on_raster"
40
40
 
41
- def __new__(cls, conf=None): # pylint: disable=W0613
41
+ def __new__(cls, scaling_coeff, conf=None): # pylint: disable=W0613
42
42
  """
43
43
  Return the required application
44
44
  :raises:
45
45
  - KeyError when the required application is not registered
46
46
 
47
47
  :param orchestrator: orchestrator used
48
+ :param scaling_coeff: scaling factor for resolution
49
+ :type scaling_coeff: float
48
50
  :param conf: configuration for resampling
49
51
  :return: an application_to_use object
50
52
  """
@@ -84,15 +86,17 @@ class DemGeneration(ApplicationTemplate, metaclass=ABCMeta):
84
86
  super().__init_subclass__(**kwargs)
85
87
  cls.available_applications[short_name] = cls
86
88
 
87
- def __init__(self, conf=None):
89
+ def __init__(self, scaling_coeff, conf=None):
88
90
  """
89
91
  Init function of MntGeneration
90
92
 
93
+ :param scaling_coeff: scaling factor for resolution
94
+ :type scaling_coeff: float
91
95
  :param conf: configuration
92
96
  :return: an application_to_use object
93
97
  """
94
98
 
95
- super().__init__(conf=conf)
99
+ super().__init__(scaling_coeff, conf=conf)
96
100
 
97
101
  @abstractmethod
98
102
  def run(self, triangulated_matches_list, output_dir):
@@ -108,7 +108,7 @@ def launch_bulldozer(
108
108
  return output_dem
109
109
 
110
110
 
111
- def multi_res_rec(
111
+ def multi_res_rec( # pylint: disable=too-many-positional-arguments
112
112
  pd_pc,
113
113
  list_fun,
114
114
  x_grid,