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
@@ -26,7 +26,6 @@ import logging
26
26
  import os
27
27
 
28
28
  import numpy as np
29
- import pyproj
30
29
  import rasterio as rio
31
30
  import xdem
32
31
 
@@ -37,8 +36,6 @@ from rasterio.enums import Resampling
37
36
  from rasterio.warp import calculate_default_transform, reproject
38
37
  from scipy.ndimage import median_filter
39
38
 
40
- from cars.core import preprocessing
41
-
42
39
 
43
40
  def fit_initial_elevation_on_dem_median(
44
41
  dem_to_fit_path: str, dem_ref_path: str, dem_out_path: str
@@ -136,7 +133,7 @@ def add_margin(bbox, ratio=1):
136
133
  return new_bbox
137
134
 
138
135
 
139
- def generate_grid(
136
+ def generate_grid( # pylint: disable=too-many-positional-arguments
140
137
  pd_pc, resolution, xmin=None, xmax=None, ymin=None, ymax=None
141
138
  ):
142
139
  """
@@ -244,7 +241,13 @@ def reverse_dem(input_dem):
244
241
  out_dem.nodata = -nodata
245
242
 
246
243
 
247
- def downsample_dem(input_dem, scale, median_filter_size=7):
244
+ def downsample_dem(
245
+ input_dem,
246
+ scale,
247
+ interpolator,
248
+ median_filter_size=None,
249
+ default_alt=0,
250
+ ):
248
251
  """
249
252
  Downsample median DEM with median resampling
250
253
 
@@ -266,85 +269,67 @@ def downsample_dem(input_dem, scale, median_filter_size=7):
266
269
  metadata["transform"] = dst_transform
267
270
  metadata["height"] = dst_height
268
271
  metadata["width"] = dst_width
269
- output = np.zeros((dst_height, dst_width))
272
+ dem_data = np.zeros((dst_height, dst_width))
273
+ interpolator_dict = {
274
+ "min": Resampling.min,
275
+ "median": Resampling.med,
276
+ "max": Resampling.max,
277
+ "nearest": Resampling.nearest,
278
+ }
279
+ interpolator = interpolator_dict[interpolator]
270
280
  reproject(
271
281
  data,
272
- output,
282
+ dem_data,
273
283
  src_transform=src_transform,
274
284
  src_crs=crs,
275
285
  dst_transform=dst_transform,
276
286
  dst_crs=crs,
277
287
  dst_nodata=nodata,
278
- resampling=Resampling.med,
288
+ resampling=interpolator,
289
+ )
290
+
291
+ # Post-processing
292
+
293
+ # Median filter
294
+ if median_filter_size is not None:
295
+ dem_data = median_filter(dem_data, size=median_filter_size)
296
+
297
+ # Fill nodata
298
+ dem_data = rio.fill.fillnodata(
299
+ dem_data,
300
+ mask=~(dem_data == nodata),
279
301
  )
280
302
 
281
- # Median filter as post-processing
282
- output = median_filter(output, size=median_filter_size)
303
+ dem_data[dem_data == nodata] = default_alt
283
304
 
284
305
  with rio.open(input_dem, "w", **metadata) as dst:
285
- dst.write(output, 1)
306
+ dst.write(dem_data, 1)
286
307
 
287
308
 
288
- def modify_terrain_bounds(dem_roi_to_use, epsg, margin):
309
+ def modify_terrain_bounds(terrain_bounds, linear_margin, constant_margin):
289
310
  """
290
311
  Modify the terrain bounds
291
312
 
292
- :param dem_roi_to_use: the dem roi
293
- :type dem_roi_to_use: polygon
294
- :param epsg: the epsg code
295
- :type epsg: int
296
- :param margin: the margin
313
+ :param terrain_bounds: Input region of interest for DEM
314
+ :type terrain_bounds: list
315
+ :param margin: Margin of the output ROI in meters
297
316
  :type margin: int
298
317
  """
299
- # Get bounds
300
- bounds_poly = dem_roi_to_use.bounds
301
- xmin = min(bounds_poly[0], bounds_poly[2])
302
- xmax = max(bounds_poly[0], bounds_poly[2])
303
- ymin = min(bounds_poly[1], bounds_poly[3])
304
- ymax = max(bounds_poly[1], bounds_poly[3])
305
-
306
- bounds_cloud = [xmin, ymin, xmax, ymax]
307
-
308
- # Convert resolution and margin to degrees
309
- utm_epsg = preprocessing.get_utm_zone_as_epsg_code(xmin, ymin)
310
- conversion_factor = preprocessing.get_conversion_factor(
311
- bounds_cloud, 4326, utm_epsg
312
- )
313
- margin_in_degrees = margin * conversion_factor
314
-
315
- # Get borders, adding margin
316
- xmin = xmin - margin_in_degrees
317
- ymin = ymin - margin_in_degrees
318
- xmax = xmax + margin_in_degrees
319
- ymax = ymax + margin_in_degrees
318
+ xsize = terrain_bounds[2] - terrain_bounds[0]
319
+ ysize = terrain_bounds[3] - terrain_bounds[1]
320
+ xmin = terrain_bounds[0] - linear_margin * xsize - constant_margin
321
+ ymin = terrain_bounds[1] - linear_margin * ysize - constant_margin
322
+ xmax = terrain_bounds[2] + linear_margin * xsize + constant_margin
323
+ ymax = terrain_bounds[3] + linear_margin * ysize + constant_margin
320
324
 
321
325
  terrain_bounds = [xmin, ymin, xmax, ymax]
322
326
 
323
- if epsg != 4326:
324
- crs_in = pyproj.CRS.from_epsg(4326)
325
- crs_out = pyproj.CRS.from_epsg(epsg)
326
-
327
- transformer = pyproj.Transformer.from_crs(
328
- crs_in, crs_out, always_xy=True
329
- )
330
-
331
- xymin = transformer.transform(terrain_bounds[0], terrain_bounds[1])
332
- xymax = transformer.transform(terrain_bounds[2], terrain_bounds[3])
333
-
334
- xmin, ymin = xymin if isinstance(xymin, tuple) else (None, None)
335
- xmax, ymax = xymax if isinstance(xymax, tuple) else (None, None)
336
-
337
- if None in (xmin, ymin, xmax, ymax):
338
- raise RuntimeError("An error occured during the projection")
339
-
340
- new_terrain_bounds = [xmin, ymin, xmax, ymax]
341
-
342
- return new_terrain_bounds
327
+ return terrain_bounds
343
328
 
344
329
 
345
330
  def reproject_dem(dsm_file_name, epsg_out, out_file_name):
346
331
  """
347
- Reproject the dem
332
+ Reproject the DEM
348
333
 
349
334
  :param dsm_file_name: the path to dsm
350
335
  :type dsm_file_name: str
@@ -64,14 +64,16 @@ class DichotomicGeneration(DemGeneration, short_name="dichotomic"):
64
64
 
65
65
  # pylint: disable=too-many-instance-attributes
66
66
 
67
- def __init__(self, conf=None):
67
+ def __init__(self, scaling_coeff, conf=None):
68
68
  """
69
69
  Init function of DichotomicGeneration
70
70
 
71
+ :param scaling_coeff: scaling factor for resolution
72
+ :type scaling_coeff: float
71
73
  :param conf: configuration for DichotomicGeneration
72
74
  :return: an application_to_use object
73
75
  """
74
- super().__init__(conf=conf)
76
+ super().__init__(scaling_coeff, conf=conf)
75
77
 
76
78
  # check conf
77
79
  self.used_method = self.used_config["method"]
@@ -127,7 +129,7 @@ class DichotomicGeneration(DemGeneration, short_name="dichotomic"):
127
129
  overloaded_conf["resolution"] = conf.get("resolution", 90)
128
130
  # default margin: (z max - zmin) * tan(teta)
129
131
  # with z max = 9000, z min = 0, teta = 30 degrees
130
- overloaded_conf["margin"] = conf.get("margin", 6000)
132
+ overloaded_conf["margin"] = conf.get("margin", [0, 6000])
131
133
  overloaded_conf["height_margin"] = conf.get("height_margin", 20)
132
134
  overloaded_conf["percentile"] = conf.get("percentile", 1)
133
135
  overloaded_conf["min_number_matches"] = conf.get(
@@ -152,7 +154,7 @@ class DichotomicGeneration(DemGeneration, short_name="dichotomic"):
152
154
  rectification_schema = {
153
155
  "method": str,
154
156
  "resolution": And(Or(float, int), lambda x: x > 0),
155
- "margin": And(Or(float, int), lambda x: x > 0),
157
+ "margin": [Or(float, int)],
156
158
  "height_margin": Or(list, int),
157
159
  "percentile": And(Or(int, float), lambda x: x >= 0),
158
160
  "min_number_matches": And(int, lambda x: x > 0),
@@ -171,7 +173,7 @@ class DichotomicGeneration(DemGeneration, short_name="dichotomic"):
171
173
  return overloaded_conf
172
174
 
173
175
  @cars_profile(name="DEM Generation")
174
- def run(
176
+ def run( # pylint: disable=too-many-positional-arguments
175
177
  self,
176
178
  triangulated_matches_list,
177
179
  output_dir,
@@ -179,8 +181,9 @@ class DichotomicGeneration(DemGeneration, short_name="dichotomic"):
179
181
  output_geoid,
180
182
  dem_roi_to_use=None,
181
183
  initial_elevation=None,
184
+ default_alt=0,
182
185
  cars_orchestrator=None,
183
- ):
186
+ ): # pylint: disable=W0613
184
187
  """
185
188
  Run dichotomic dem generation using matches
186
189
 
@@ -23,6 +23,7 @@ this module contains the dichotomic dem generation application class.
23
23
  """
24
24
  # Standard library
25
25
  import logging
26
+ import math
26
27
  import os
27
28
  import shutil
28
29
 
@@ -63,14 +64,16 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
63
64
 
64
65
  # pylint: disable=too-many-instance-attributes
65
66
 
66
- def __init__(self, conf=None):
67
+ def __init__(self, scaling_coeff, conf=None):
67
68
  """
68
69
  Init function of Rasterization
69
70
 
71
+ :param scaling_coeff: scaling factor for resolution
72
+ :type scaling_coeff: float
70
73
  :param conf: configuration for Rasterization
71
74
  :return: an application_to_use object
72
75
  """
73
- super().__init__(conf=conf)
76
+ super().__init__(scaling_coeff, conf=conf)
74
77
 
75
78
  # check conf
76
79
  self.used_method = self.used_config["method"]
@@ -92,9 +95,8 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
92
95
  self.postprocessing_median_filter_size = self.used_config[
93
96
  "postprocessing_median_filter_size"
94
97
  ]
95
- self.dem_median_output_resolution = self.used_config[
96
- "dem_median_output_resolution"
97
- ]
98
+ self.dem_median_downscale = self.used_config["dem_median_downscale"]
99
+ self.dem_min_max_downscale = self.used_config["dem_min_max_downscale"]
98
100
  self.fillnodata_max_search_distance = self.used_config[
99
101
  "fillnodata_max_search_distance"
100
102
  ]
@@ -103,6 +105,7 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
103
105
  self.bulldozer_max_object_size = self.used_config[
104
106
  "bulldozer_max_object_size"
105
107
  ]
108
+ self.disable_bulldozer = self.used_config["disable_bulldozer"]
106
109
  self.compute_stats = self.used_config["compute_stats"]
107
110
  self.coregistration = self.used_config["coregistration"]
108
111
  self.coregistration_max_shift = self.used_config[
@@ -134,8 +137,12 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
134
137
 
135
138
  # Overload conf
136
139
  overloaded_conf["method"] = conf.get("method", "bulldozer_on_raster")
137
- overloaded_conf["resolution"] = conf.get("resolution", 2)
138
- overloaded_conf["margin"] = conf.get("margin", 500)
140
+ overloaded_conf["resolution"] = conf.get(
141
+ "resolution", float(self.scaling_coeff * 0.5)
142
+ )
143
+ overloaded_conf["margin"] = conf.get(
144
+ "margin", [0.1, float(math.sqrt(self.scaling_coeff) * 500)]
145
+ )
139
146
  overloaded_conf["morphological_filters_size"] = conf.get(
140
147
  "morphological_filters_size", 30
141
148
  )
@@ -145,18 +152,26 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
145
152
  overloaded_conf["postprocessing_median_filter_size"] = conf.get(
146
153
  "postprocessing_median_filter_size", 7
147
154
  )
148
- overloaded_conf["dem_median_output_resolution"] = conf.get(
149
- "dem_median_output_resolution", 30
155
+ overloaded_conf["dem_median_downscale"] = conf.get(
156
+ "dem_median_downscale", 10
157
+ )
158
+ overloaded_conf["dem_min_max_downscale"] = conf.get(
159
+ "dem_min_max_downscale", 2
150
160
  )
151
161
  overloaded_conf["fillnodata_max_search_distance"] = conf.get(
152
162
  "fillnodata_max_search_distance", 50
153
163
  )
154
164
  overloaded_conf["min_dem"] = conf.get("min_dem", -500)
155
165
  overloaded_conf["max_dem"] = conf.get("max_dem", 1000)
156
- overloaded_conf["height_margin"] = conf.get("height_margin", 20)
166
+ overloaded_conf["height_margin"] = conf.get(
167
+ "height_margin", float(math.sqrt(self.scaling_coeff) * 20)
168
+ )
157
169
  overloaded_conf["bulldozer_max_object_size"] = conf.get(
158
170
  "bulldozer_max_object_size", 8
159
171
  )
172
+ overloaded_conf["disable_bulldozer"] = conf.get(
173
+ "disable_bulldozer", False
174
+ )
160
175
  overloaded_conf["compute_stats"] = conf.get("compute_stats", True)
161
176
  overloaded_conf["coregistration"] = conf.get("coregistration", True)
162
177
  overloaded_conf["coregistration_max_shift"] = conf.get(
@@ -170,16 +185,18 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
170
185
  "method": str,
171
186
  "resolution": And(Or(float, int), lambda x: x > 0),
172
187
  application_constants.SAVE_INTERMEDIATE_DATA: bool,
173
- "margin": And(Or(float, int), lambda x: x > 0),
188
+ "margin": [Or(float, int)],
174
189
  "morphological_filters_size": And(int, lambda x: x > 0),
175
190
  "preprocessing_median_filter_size": And(int, lambda x: x > 0),
176
191
  "postprocessing_median_filter_size": And(int, lambda x: x > 0),
177
- "dem_median_output_resolution": And(int, lambda x: x > 0),
192
+ "dem_median_downscale": And(int, lambda x: x > 0),
193
+ "dem_min_max_downscale": And(int, lambda x: x > 0),
178
194
  "fillnodata_max_search_distance": And(int, lambda x: x > 0),
179
195
  "min_dem": And(Or(int, float), lambda x: x < 0),
180
196
  "max_dem": And(Or(int, float), lambda x: x > 0),
181
197
  "height_margin": Or(list, float, int),
182
198
  "bulldozer_max_object_size": And(int, lambda x: x > 0),
199
+ "disable_bulldozer": bool,
183
200
  "compute_stats": bool,
184
201
  "coregistration": bool,
185
202
  "coregistration_max_shift": And(Or(int, float), lambda x: x > 0),
@@ -193,7 +210,7 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
193
210
  return overloaded_conf
194
211
 
195
212
  @cars_profile(name="DEM Generation")
196
- def run(
213
+ def run( # pylint: disable=too-many-positional-arguments # noqa: C901
197
214
  self,
198
215
  dsm_file_name,
199
216
  output_dir,
@@ -203,6 +220,7 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
203
220
  input_geoid,
204
221
  output_geoid,
205
222
  initial_elevation=None,
223
+ default_alt=0,
206
224
  cars_orchestrator=None,
207
225
  ):
208
226
  """
@@ -389,14 +407,17 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
389
407
  out_dem.write(dem_median, 1)
390
408
  with rio.open(dem_max_path, "w", **profile) as out_dem:
391
409
  out_dem.write(dem_max, 1)
410
+ dem_filled_path = os.path.join(output_dir, "dem_filled.tif")
411
+ with rio.open(dem_filled_path, "w", **profile) as out_dem:
412
+ out_dem.write(dem_data, 1)
392
413
 
393
414
  if self.save_intermediate_data:
394
415
  intermediate_dem_min_path = os.path.join(
395
- output_dir, "dem_min_before_bulldozer.tif"
416
+ output_dir, "dem_min_before_downsampling.tif"
396
417
  )
397
418
  shutil.copy2(dem_min_path, intermediate_dem_min_path)
398
419
  intermediate_dem_max_path = os.path.join(
399
- output_dir, "dem_max_before_bulldozer.tif"
420
+ output_dir, "dem_max_before_downsampling.tif"
400
421
  )
401
422
  shutil.copy2(dem_max_path, intermediate_dem_max_path)
402
423
 
@@ -405,44 +426,79 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
405
426
  )
406
427
  shutil.copy2(dem_median_path_out, intermediate_dem_median_path)
407
428
 
408
- # Downsample median dem
429
+ # Downsample dems
409
430
  downsample_dem(
410
431
  dem_median_path_out,
411
- scale=self.dem_median_output_resolution / resolution_in_meters,
432
+ scale=self.dem_median_downscale,
433
+ interpolator="median",
412
434
  median_filter_size=self.postprocessing_median_filter_size,
435
+ default_alt=default_alt,
413
436
  )
414
437
 
415
- # Launch Bulldozer on dem min
416
- saved_transform = edit_transform(
417
- dem_min_path, resolution=resolution_in_meters
418
- )
419
- logging.info("Launch Bulldozer on DEM min")
420
- temp_output_path = launch_bulldozer(
438
+ downsample_dem(
421
439
  dem_min_path,
422
- os.path.join(output_dir, "dem_min_bulldozer"),
423
- cars_orchestrator,
424
- self.bulldozer_max_object_size,
440
+ scale=self.dem_min_max_downscale,
441
+ interpolator="min",
442
+ default_alt=default_alt,
425
443
  )
426
- if temp_output_path is not None:
427
- shutil.copy2(temp_output_path, dem_min_path)
428
- edit_transform(dem_min_path, transform=saved_transform)
429
444
 
430
- # Inverse dem max and launch bulldozer
431
- saved_transform = edit_transform(
432
- dem_max_path, resolution=resolution_in_meters
433
- )
434
- reverse_dem(dem_max_path)
435
- logging.info("Launch Bulldozer on DEM max")
436
- temp_output_path = launch_bulldozer(
445
+ downsample_dem(
437
446
  dem_max_path,
438
- os.path.join(output_dir, "dem_max_bulldozer"),
439
- cars_orchestrator,
440
- self.bulldozer_max_object_size,
447
+ scale=self.dem_min_max_downscale,
448
+ interpolator="max",
449
+ default_alt=default_alt,
441
450
  )
442
- if temp_output_path is not None:
443
- shutil.copy2(temp_output_path, dem_max_path)
444
- reverse_dem(dem_max_path)
445
- edit_transform(dem_max_path, transform=saved_transform)
451
+
452
+ downsample_dem(
453
+ dem_filled_path,
454
+ scale=self.dem_min_max_downscale,
455
+ interpolator="nearest",
456
+ default_alt=default_alt,
457
+ )
458
+
459
+ if self.save_intermediate_data:
460
+ intermediate_dem_min_path = os.path.join(
461
+ output_dir, "dem_min_before_bulldozer.tif"
462
+ )
463
+ shutil.copy2(dem_min_path, intermediate_dem_min_path)
464
+ intermediate_dem_max_path = os.path.join(
465
+ output_dir, "dem_max_before_bulldozer.tif"
466
+ )
467
+ shutil.copy2(dem_max_path, intermediate_dem_max_path)
468
+
469
+ if not self.disable_bulldozer:
470
+ dem_min_max_res = resolution_in_meters * self.dem_min_max_downscale
471
+ # Launch Bulldozer on dem min
472
+ saved_transform = edit_transform(
473
+ dem_min_path, resolution=dem_min_max_res
474
+ )
475
+ logging.info("Launch Bulldozer on DEM min")
476
+ temp_output_path = launch_bulldozer(
477
+ dem_min_path,
478
+ os.path.join(output_dir, "dem_min_bulldozer"),
479
+ cars_orchestrator,
480
+ self.bulldozer_max_object_size,
481
+ )
482
+ if temp_output_path is not None:
483
+ shutil.copy2(temp_output_path, dem_min_path)
484
+ edit_transform(dem_min_path, transform=saved_transform)
485
+
486
+ # Inverse dem max and launch bulldozer
487
+ saved_transform = edit_transform(
488
+ dem_max_path, resolution=dem_min_max_res
489
+ )
490
+ reverse_dem(dem_max_path)
491
+ logging.info("Launch Bulldozer on DEM max")
492
+ temp_output_path = launch_bulldozer(
493
+ dem_max_path,
494
+ os.path.join(output_dir, "dem_max_bulldozer"),
495
+ cars_orchestrator,
496
+ self.bulldozer_max_object_size,
497
+ )
498
+ if temp_output_path is not None:
499
+ shutil.copy2(temp_output_path, dem_max_path)
500
+ reverse_dem(dem_max_path)
501
+ edit_transform(dem_max_path, transform=saved_transform)
446
502
 
447
503
  # Check DEM min and max
448
504
  with rio.open(dem_min_path, "r") as in_dem:
@@ -452,11 +508,14 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
452
508
  with rio.open(dem_max_path, "r") as in_dem:
453
509
  dem_max = in_dem.read()
454
510
  dem_max_metadata = in_dem.meta
511
+ with rio.open(dem_filled_path, "r") as in_dem:
512
+ dem_data = in_dem.read()
455
513
  dem_data[dem_data == nodata] = np.nan
456
514
  dem_min[dem_min == nodata] = np.nan
457
515
  dem_max[dem_max == nodata] = np.nan
458
516
  if self.compute_stats:
459
517
  diff = dem_data - dem_min
518
+ diff = diff[dem_data != 0]
460
519
  logging.info(
461
520
  "Statistics of difference between subsampled "
462
521
  "DSM and DEM min (in meters)"
@@ -464,6 +523,7 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
464
523
  compute_stats(diff)
465
524
 
466
525
  diff = dem_max - dem_data
526
+ diff = diff[dem_data != 0]
467
527
  logging.info(
468
528
  "Statistics of difference between DEM max "
469
529
  "and subsampled DSM (in meters)"
@@ -471,6 +531,7 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
471
531
  compute_stats(diff)
472
532
 
473
533
  diff = dem_max - dem_min
534
+ diff = diff[dem_data != 0]
474
535
  logging.info(
475
536
  "Statistics of difference between DEM max "
476
537
  "and DEM min (in meters)"
@@ -490,6 +551,14 @@ class Rasterization(DemGeneration, short_name="bulldozer_on_raster"):
490
551
  dem_max,
491
552
  )
492
553
 
554
+ # Rectify pixels where DEM min > DEM max - margin, to ensure that
555
+ # DEM min < DEM max even on filled pixels
556
+ dem_min = np.where(
557
+ dem_min > dem_max - self.min_height_margin,
558
+ dem_max - self.min_height_margin,
559
+ dem_min,
560
+ )
561
+
493
562
  with rio.open(dem_min_path, "w", **dem_min_metadata) as out_dem:
494
563
  out_dem.write(dem_min)
495
564
  with rio.open(dem_max_path, "w", **dem_max_metadata) as out_dem:
@@ -27,4 +27,4 @@ from cars.applications.dense_match_filling.abstract_dense_match_filling_app impo
27
27
  DenseMatchFilling,
28
28
  )
29
29
 
30
- from . import plane_app, zero_padding_app
30
+ from . import zero_padding_app
@@ -123,23 +123,10 @@ class DenseMatchFilling(ApplicationTemplate, metaclass=ABCMeta):
123
123
  **kwargs,
124
124
  ):
125
125
  """
126
- Run Refill application using plane method.
126
+ Run filling application.
127
127
 
128
128
  :param epipolar_disparity_map: left disparity
129
129
  :type epipolar_disparity_map: CarsDataset
130
- :param holes_bbox_left: left holes
131
- :type holes_bbox_left: CarsDataset
132
- :param holes_bbox_right: right holes
133
- :type holes_bbox_right: CarsDataset
134
- :param disp_min: minimum disparity
135
- :type disp_min: int
136
- :param disp_max: maximum disparity
137
- :type disp_max: int
138
- :param orchestrator: orchestrator used
139
- :param pair_folder: folder used for current pair
140
- :type pair_folder: str
141
- :param pair_key: pair id
142
- :type pair_key: str
143
130
 
144
131
  :return: filled disparity map: \
145
132
  The CarsDataset contains:
@@ -156,7 +143,7 @@ class DenseMatchFilling(ApplicationTemplate, metaclass=ABCMeta):
156
143
 
157
144
  """
158
145
 
159
- def __register_dataset__(
146
+ def __register_dataset__( # pylint: disable=too-many-positional-arguments
160
147
  self,
161
148
  epipolar_disparity_map,
162
149
  save_intermediate_data,