cars 1.0.0rc3__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +40 -0
  3. cars/applications/application.py +117 -0
  4. cars/applications/application_constants.py +29 -0
  5. cars/applications/application_template.py +146 -0
  6. cars/applications/auxiliary_filling/__init__.py +29 -0
  7. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
  10. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
  11. cars/applications/dem_generation/__init__.py +30 -0
  12. cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
  13. cars/applications/dem_generation/bulldozer_config/base_config.yaml +46 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
  15. cars/applications/dem_generation/bulldozer_memory.py +55 -0
  16. cars/applications/dem_generation/dem_generation_algo.py +107 -0
  17. cars/applications/dem_generation/dem_generation_constants.py +32 -0
  18. cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
  19. cars/applications/dense_match_filling/__init__.py +30 -0
  20. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
  21. cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
  22. cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
  23. cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
  24. cars/applications/dense_match_filling/zero_padding_app.py +302 -0
  25. cars/applications/dense_matching/__init__.py +30 -0
  26. cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
  27. cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-313-x86_64-linux-gnu.so +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  31. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  32. cars/applications/dense_matching/cpp/meson.build +9 -0
  33. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  34. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  35. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  36. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  37. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  38. cars/applications/dense_matching/disparity_grid_algo.py +597 -0
  39. cars/applications/dense_matching/loaders/__init__.py +23 -0
  40. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  46. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  47. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  48. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  49. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  50. cars/applications/dsm_filling/__init__.py +32 -0
  51. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  52. cars/applications/dsm_filling/border_interpolation_app.py +278 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  56. cars/applications/dsm_merging/__init__.py +28 -0
  57. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  58. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  59. cars/applications/grid_correction/__init__.py +30 -0
  60. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  61. cars/applications/grid_correction/grid_correction_app.py +557 -0
  62. cars/applications/grid_generation/__init__.py +30 -0
  63. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  64. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  65. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  66. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  67. cars/applications/grid_generation/transform_grid.py +88 -0
  68. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  69. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  70. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  71. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  72. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  73. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  74. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  76. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  77. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  78. cars/applications/rasterization/__init__.py +30 -0
  79. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  80. cars/applications/rasterization/rasterization_algo.py +534 -0
  81. cars/applications/rasterization/rasterization_constants.py +38 -0
  82. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  83. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  84. cars/applications/resampling/__init__.py +28 -0
  85. cars/applications/resampling/abstract_resampling_app.py +187 -0
  86. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  87. cars/applications/resampling/resampling_algo.py +590 -0
  88. cars/applications/resampling/resampling_constants.py +36 -0
  89. cars/applications/resampling/resampling_wrappers.py +309 -0
  90. cars/applications/sensors_subsampling/__init__.py +32 -0
  91. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  92. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  93. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  94. cars/applications/sparse_matching/__init__.py +30 -0
  95. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  96. cars/applications/sparse_matching/sift_app.py +724 -0
  97. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  98. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  99. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  100. cars/applications/triangulation/__init__.py +32 -0
  101. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  102. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  103. cars/applications/triangulation/pc_transform.py +552 -0
  104. cars/applications/triangulation/triangulation_algo.py +371 -0
  105. cars/applications/triangulation/triangulation_constants.py +38 -0
  106. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  107. cars/bundleadjustment.py +750 -0
  108. cars/cars.py +179 -0
  109. cars/conf/__init__.py +23 -0
  110. cars/conf/geoid/egm96.grd +0 -0
  111. cars/conf/geoid/egm96.grd.hdr +15 -0
  112. cars/conf/input_parameters.py +156 -0
  113. cars/conf/mask_cst.py +35 -0
  114. cars/core/__init__.py +23 -0
  115. cars/core/cars_logging.py +402 -0
  116. cars/core/constants.py +191 -0
  117. cars/core/constants_disparity.py +50 -0
  118. cars/core/datasets.py +140 -0
  119. cars/core/geometry/__init__.py +27 -0
  120. cars/core/geometry/abstract_geometry.py +1130 -0
  121. cars/core/geometry/shareloc_geometry.py +604 -0
  122. cars/core/inputs.py +568 -0
  123. cars/core/outputs.py +176 -0
  124. cars/core/preprocessing.py +722 -0
  125. cars/core/projection.py +843 -0
  126. cars/core/roi_tools.py +215 -0
  127. cars/core/tiling.py +774 -0
  128. cars/core/utils.py +164 -0
  129. cars/data_structures/__init__.py +23 -0
  130. cars/data_structures/cars_dataset.py +1544 -0
  131. cars/data_structures/cars_dict.py +74 -0
  132. cars/data_structures/corresponding_tiles_tools.py +186 -0
  133. cars/data_structures/dataframe_converter.py +185 -0
  134. cars/data_structures/format_transformation.py +297 -0
  135. cars/devibrate.py +689 -0
  136. cars/extractroi.py +264 -0
  137. cars/orchestrator/__init__.py +23 -0
  138. cars/orchestrator/achievement_tracker.py +125 -0
  139. cars/orchestrator/cluster/__init__.py +37 -0
  140. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  141. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  142. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  143. cars/orchestrator/cluster/dask_config/README.md +94 -0
  144. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  145. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  146. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  147. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  152. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  153. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  154. cars/orchestrator/cluster/log_wrapper.py +728 -0
  155. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  156. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  160. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  162. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  163. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  164. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  165. cars/orchestrator/memory_tools.py +47 -0
  166. cars/orchestrator/orchestrator.py +755 -0
  167. cars/orchestrator/orchestrator_constants.py +29 -0
  168. cars/orchestrator/registry/__init__.py +23 -0
  169. cars/orchestrator/registry/abstract_registry.py +143 -0
  170. cars/orchestrator/registry/compute_registry.py +106 -0
  171. cars/orchestrator/registry/id_generator.py +116 -0
  172. cars/orchestrator/registry/replacer_registry.py +213 -0
  173. cars/orchestrator/registry/saver_registry.py +363 -0
  174. cars/orchestrator/registry/unseen_registry.py +118 -0
  175. cars/orchestrator/tiles_profiler.py +279 -0
  176. cars/pipelines/__init__.py +26 -0
  177. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  178. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  179. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  180. cars/pipelines/default/__init__.py +26 -0
  181. cars/pipelines/default/default_pipeline.py +1095 -0
  182. cars/pipelines/filling/__init__.py +26 -0
  183. cars/pipelines/filling/filling.py +981 -0
  184. cars/pipelines/formatting/__init__.py +26 -0
  185. cars/pipelines/formatting/formatting.py +190 -0
  186. cars/pipelines/merging/__init__.py +26 -0
  187. cars/pipelines/merging/merging.py +439 -0
  188. cars/pipelines/parameters/__init__.py +0 -0
  189. cars/pipelines/parameters/advanced_parameters.py +256 -0
  190. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  191. cars/pipelines/parameters/application_parameters.py +72 -0
  192. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  193. cars/pipelines/parameters/dsm_inputs.py +349 -0
  194. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  195. cars/pipelines/parameters/output_constants.py +52 -0
  196. cars/pipelines/parameters/output_parameters.py +435 -0
  197. cars/pipelines/parameters/sensor_inputs.py +859 -0
  198. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  199. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  200. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  202. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  204. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  206. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  207. cars/pipelines/pipeline.py +119 -0
  208. cars/pipelines/pipeline_constants.py +38 -0
  209. cars/pipelines/pipeline_template.py +135 -0
  210. cars/pipelines/subsampling/__init__.py +26 -0
  211. cars/pipelines/subsampling/subsampling.py +358 -0
  212. cars/pipelines/surface_modeling/__init__.py +26 -0
  213. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  214. cars/pipelines/tie_points/__init__.py +26 -0
  215. cars/pipelines/tie_points/tie_points.py +536 -0
  216. cars/starter.py +167 -0
  217. cars-1.0.0rc3.dist-info/METADATA +289 -0
  218. cars-1.0.0rc3.dist-info/RECORD +220 -0
  219. cars-1.0.0rc3.dist-info/WHEEL +6 -0
  220. cars-1.0.0rc3.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,1152 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ # pylint: disable=too-many-lines
22
+
23
+ """
24
+ this module contains the dense_matching application class.
25
+ """
26
+
27
+ import collections
28
+
29
+ # Third party imports
30
+ import copy
31
+
32
+ # Standard imports
33
+ import logging
34
+ import os
35
+ from typing import List
36
+
37
+ import numpy as np
38
+ import rasterio as rio
39
+ import xarray
40
+ from affine import Affine
41
+ from json_checker import Checker, Or
42
+
43
+ import cars.orchestrator.orchestrator as ocht
44
+ from cars.applications import application_constants
45
+
46
+ # CARS imports
47
+ from cars.applications.rasterization import (
48
+ rasterization_algo,
49
+ )
50
+ from cars.applications.rasterization import (
51
+ rasterization_constants as raster_cst,
52
+ )
53
+ from cars.applications.rasterization import (
54
+ rasterization_wrappers,
55
+ )
56
+ from cars.applications.rasterization.abstract_pc_rasterization_app import (
57
+ PointCloudRasterization,
58
+ )
59
+ from cars.applications.triangulation import pc_transform
60
+ from cars.core import constants as cst
61
+ from cars.core import projection, tiling
62
+ from cars.core.utils import safe_makedirs
63
+ from cars.data_structures import cars_dataset
64
+
65
+ # R0903 temporary disabled for error "Too few public methods"
66
+ # œgoing to be corrected by adding new methods as check_conf
67
+
68
+
69
+ class SimpleGaussian(
70
+ PointCloudRasterization, short_name="simple_gaussian"
71
+ ): # pylint: disable=R0903
72
+ """
73
+ PointCloudRasterisation
74
+ """
75
+
76
+ # pylint: disable=too-many-instance-attributes
77
+
78
+ def __init__(self, conf=None):
79
+ """
80
+ Init function of PointCloudRasterisation
81
+
82
+ :param conf: configuration for rasterization
83
+ :return: a application_to_use object
84
+ """
85
+
86
+ super().__init__(conf=conf)
87
+
88
+ # check conf
89
+
90
+ # get rasterization parameter
91
+ self.used_method = self.used_config["method"]
92
+ self.dsm_radius = self.used_config["dsm_radius"]
93
+ self.sigma = self.used_config["sigma"]
94
+ self.grid_points_division_factor = self.used_config[
95
+ "grid_points_division_factor"
96
+ ]
97
+ # get nodata values
98
+ self.dsm_no_data = self.used_config["dsm_no_data"]
99
+ self.texture_no_data = self.used_config["texture_no_data"]
100
+ self.color_dtype = self.used_config["texture_dtype"]
101
+ self.msk_no_data = self.used_config["msk_no_data"]
102
+
103
+ # Init orchestrator
104
+ self.orchestrator = None
105
+
106
+ def check_conf(self, conf):
107
+ """
108
+ Check configuration
109
+
110
+ :param conf: configuration to check
111
+ :type conf: dict
112
+
113
+ :return: overloaded configuration
114
+ :rtype: dict
115
+
116
+ """
117
+
118
+ # init conf
119
+ if conf is not None:
120
+ overloaded_conf = conf.copy()
121
+ else:
122
+ conf = {}
123
+ overloaded_conf = {}
124
+
125
+ # Overload conf
126
+
127
+ # get rasterization parameter
128
+ overloaded_conf["method"] = conf.get("method", "simple_gaussian")
129
+ overloaded_conf["dsm_radius"] = conf.get("dsm_radius", 1)
130
+ overloaded_conf["sigma"] = conf.get("sigma", None)
131
+ overloaded_conf["grid_points_division_factor"] = conf.get(
132
+ "grid_points_division_factor", None
133
+ )
134
+
135
+ # get nodata values
136
+ overloaded_conf["dsm_no_data"] = conf.get("dsm_no_data", -32768)
137
+ overloaded_conf["texture_no_data"] = conf.get("texture_no_data", None)
138
+ overloaded_conf["texture_dtype"] = conf.get("texture_dtype", None)
139
+ overloaded_conf["msk_no_data"] = conf.get("msk_no_data", 255)
140
+
141
+ overloaded_conf["save_intermediate_data"] = conf.get(
142
+ "save_intermediate_data", False
143
+ )
144
+
145
+ rasterization_schema = {
146
+ "method": str,
147
+ "dsm_radius": Or(float, int),
148
+ "sigma": Or(float, None),
149
+ "grid_points_division_factor": Or(None, int),
150
+ "dsm_no_data": int,
151
+ "msk_no_data": int,
152
+ "texture_no_data": Or(None, int),
153
+ "texture_dtype": Or(None, str),
154
+ "save_intermediate_data": bool,
155
+ }
156
+
157
+ # Check conf
158
+ checker = Checker(rasterization_schema)
159
+ checker.validate(overloaded_conf)
160
+
161
+ return overloaded_conf
162
+
163
+ def get_margins(self, resolution):
164
+ """
165
+ Get the margin to use for terrain tiles
166
+
167
+ :param resolution: resolution of raster data (in target CRS unit)
168
+ :type resolution: float
169
+
170
+ :return: margin in meters or degrees
171
+ """
172
+
173
+ margins = self.dsm_radius * resolution
174
+ return margins
175
+
176
+ def get_optimal_tile_size(
177
+ self,
178
+ max_ram_per_worker,
179
+ superposing_point_clouds=1,
180
+ point_cloud_resolution=0.5,
181
+ ):
182
+ """
183
+ Get the optimal tile size to use, depending on memory available
184
+
185
+ :param max_ram_per_worker: maximum ram available
186
+ :type max_ram_per_worker: int
187
+ :param superposing_point_clouds: number of point clouds superposing
188
+ :type superposing_point_clouds: int
189
+ :param point_cloud_resolution: resolution of point cloud
190
+ :type point_cloud_resolution: float
191
+
192
+ :return: optimal tile size in meter
193
+ :rtype: float
194
+
195
+ """
196
+
197
+ tot = 7000 * superposing_point_clouds / point_cloud_resolution
198
+
199
+ import_ = 200 # MiB
200
+ tile_size = int(
201
+ np.sqrt(float(((max_ram_per_worker - import_) * 2**23)) / tot)
202
+ )
203
+
204
+ logging.info(
205
+ "Estimated optimal tile size for rasterization: {} meters".format(
206
+ tile_size
207
+ )
208
+ )
209
+ return tile_size
210
+
211
+ # pylint: disable=too-many-positional-arguments
212
+ def run( # noqa: C901 function is too complex
213
+ self,
214
+ point_clouds,
215
+ epsg,
216
+ output_crs,
217
+ resolution,
218
+ orchestrator=None,
219
+ dsm_file_name=None,
220
+ weights_file_name=None,
221
+ color_file_name=None,
222
+ classif_file_name=None,
223
+ performance_map_file_name=None,
224
+ ambiguity_file_name=None,
225
+ contributing_pair_file_name=None,
226
+ filling_file_name=None,
227
+ color_dtype=None,
228
+ dump_dir=None,
229
+ performance_map_classes=None,
230
+ phasing=None,
231
+ ):
232
+ """
233
+ Run PointCloudRasterisation application.
234
+
235
+ Creates a CarsDataset filled with dsm tiles.
236
+
237
+ :param point_clouds: merged point cloud or list of array point clouds
238
+
239
+ . CarsDataset contains:
240
+
241
+ - Z x W Delayed tiles. \
242
+ Each tile will be a future pandas DataFrame containing:
243
+
244
+ - data with keys "x", "y", "z", "corr_msk" \
245
+ optional: "texture", "mask", "data_valid", "z_inf", "z_sup"\
246
+ "coord_epi_geom_i", "coord_epi_geom_j", "idx_im_epi"
247
+ - attrs with keys "epsg", "ysize", "xsize", "xstart", "ystart"
248
+
249
+ - attributes containing "bounds", "ysize", "xsize", "epsg"
250
+
251
+ OR
252
+
253
+
254
+ Tuple(list of CarsDataset Arrays, bounds). With list of point
255
+ clouds:
256
+ list of CarsDataset of type array, with:
257
+ - data with keys x", "y", "z", "corr_msk", "z_inf", "z_sup"\
258
+ optional: "texture", "mask", "data_valid",\
259
+ "coord_epi_geom_i", "coord_epi_geom_j", "idx_im_epi"
260
+
261
+ :type point_clouds: CarsDataset filled with pandas.DataFrame
262
+ :param epsg: epsg of raster data
263
+ :type epsg: str
264
+ :param output_crs: output_crs of raster data
265
+ :type output_crs: str
266
+ :param resolution: resolution of raster data (in target CRS unit)
267
+ :type resolution: float
268
+ :param orchestrator: orchestrator used
269
+ :param dsm_file_name: path of dsm
270
+ :type dsm_file_name: str
271
+ :param weights_file_name: path of dsm weights
272
+ :type weights_file_name: str
273
+ :param color_file_name: path of color
274
+ :type color_file_name: str
275
+ :param classif_file_name: path of classification
276
+ :type classif_file_name: str
277
+ :param performance_map_file_name: path of performance map file
278
+ :type performance_map_file_name: str
279
+ :param ambiguity_file_name: path of ambiguity file
280
+ :type ambiguity_file_name: str
281
+ :param contributing_pair_file_name: path of contributing pair file
282
+ :type contributing_pair_file_name: str
283
+ :param filling_file_name: path of filling file
284
+ :type filling_file_name: str
285
+ :param color_dtype: output color image type
286
+ :type color_dtype: str (numpy type)
287
+ :param dump_dir: directory used for outputs with no associated filename
288
+ :type dump_dir: str
289
+ :param performance_map_classes: list for step defining border of class
290
+ :type performance_map_classes: list or None
291
+ :param phasing: if activated, we phase the dsm on this point
292
+ :type phasing: dict
293
+
294
+ :return: raster DSM. CarsDataset contains:
295
+
296
+ - Z x W Delayed tiles. \
297
+ Each tile will be a future xarray Dataset containing:
298
+
299
+ - data : with keys : "hgt", "img", "raster_msk",optional : \
300
+ "n_pts", "pts_in_cell", "hgt_mean", "hgt_stdev",\
301
+ "hgt_inf", "hgt_sup"
302
+ - attrs with keys: "epsg"
303
+ - attributes containing: None
304
+
305
+ :rtype : CarsDataset filled with xr.Dataset
306
+ """
307
+ # only the saved layers will be saved
308
+ list_computed_layers = []
309
+
310
+ # Default orchestrator
311
+ if orchestrator is None:
312
+ # Create default sequential orchestrator for current application
313
+ # be awere, no out_json will be shared between orchestrators
314
+ # No files saved
315
+ self.orchestrator = ocht.Orchestrator(
316
+ orchestrator_conf={"mode": "sequential"}
317
+ )
318
+ else:
319
+ self.orchestrator = orchestrator
320
+
321
+ # Get if color and stats are saved
322
+ save_intermediate_data = self.used_config["save_intermediate_data"]
323
+
324
+ keep_dir = (
325
+ len(
326
+ list(
327
+ filter(
328
+ lambda x: x is not None,
329
+ [
330
+ weights_file_name,
331
+ color_file_name,
332
+ classif_file_name,
333
+ performance_map_file_name,
334
+ ambiguity_file_name,
335
+ contributing_pair_file_name,
336
+ filling_file_name,
337
+ ],
338
+ )
339
+ )
340
+ )
341
+ > 0
342
+ )
343
+
344
+ if not self.color_dtype:
345
+ self.color_dtype = color_dtype
346
+
347
+ if self.texture_no_data is None:
348
+ if self.color_dtype is not None:
349
+ if "float" in self.color_dtype:
350
+ self.texture_no_data = np.finfo(self.color_dtype).max
351
+ else:
352
+ self.texture_no_data = np.iinfo(self.color_dtype).max
353
+ else:
354
+ self.texture_no_data = np.finfo("float32").max
355
+
356
+ # Setup dump directory
357
+ if dump_dir is not None:
358
+ out_dump_dir = dump_dir
359
+ safe_makedirs(dump_dir)
360
+ if not save_intermediate_data and not keep_dir:
361
+ self.orchestrator.add_to_clean(dump_dir)
362
+ else:
363
+ out_dump_dir = self.orchestrator.out_dir
364
+
365
+ # Check if input data is supported
366
+ if not (
367
+ isinstance(point_clouds, tuple)
368
+ and isinstance(point_clouds[0][0], cars_dataset.CarsDataset)
369
+ and point_clouds[0][0].dataset_type == "arrays"
370
+ ):
371
+ message = (
372
+ "PointCloudRasterization application doesn't support "
373
+ "this input data "
374
+ "format : type : {}".format(type(point_clouds))
375
+ )
376
+ logging.error(message)
377
+ raise RuntimeError(message)
378
+
379
+ # Create CarsDataset
380
+ terrain_raster = cars_dataset.CarsDataset(
381
+ "arrays", name="rasterization"
382
+ )
383
+
384
+ paths_data = {}
385
+
386
+ bounds = point_clouds[1]
387
+ # tiling grid: all tiles from sources -> not replaceable.
388
+ # CarsDataset is only used for processing
389
+ nb_tiles = 0
390
+ for point_cld in point_clouds[0]:
391
+ nb_tiles += point_cld.shape[0] * point_cld.shape[1]
392
+ terrain_raster.tiling_grid = tiling.generate_tiling_grid(
393
+ 0, 0, 1, nb_tiles, 1, 1
394
+ )
395
+
396
+ terrain_raster.generate_none_tiles()
397
+
398
+ if phasing is not None:
399
+ res = resolution
400
+ x_phase = phasing["point"][0]
401
+ y_phase = phasing["point"][1]
402
+
403
+ for index, value in enumerate(bounds):
404
+ if index in (0, 2):
405
+ bounds[index] = rasterization_wrappers.phased_dsm(
406
+ value, x_phase, res
407
+ )
408
+ else:
409
+ bounds[index] = rasterization_wrappers.phased_dsm(
410
+ value, y_phase, res
411
+ )
412
+
413
+ # Derive output image files parameters to pass to rasterio
414
+ _, _, xsize, ysize = tiling.roi_to_start_and_size(bounds, resolution)
415
+ logging.info("DSM output image size: {}x{} pixels".format(xsize, ysize))
416
+
417
+ try:
418
+ if isinstance(point_clouds, tuple):
419
+ source_pc_names = point_clouds[0][0].attributes[
420
+ "source_pc_names"
421
+ ]
422
+ else:
423
+ source_pc_names = point_clouds.attributes["source_pc_names"]
424
+ except KeyError:
425
+ source_pc_names = None
426
+
427
+ # Save objects
428
+
429
+ if dsm_file_name is not None:
430
+ safe_makedirs(os.path.dirname(dsm_file_name))
431
+
432
+ out_dsm_file_name = dsm_file_name
433
+
434
+ if out_dsm_file_name is not None:
435
+ self.orchestrator.update_index(
436
+ {
437
+ "dsm": {
438
+ cst.INDEX_DSM_ALT: os.path.basename(out_dsm_file_name)
439
+ }
440
+ }
441
+ )
442
+ elif save_intermediate_data:
443
+ # File is not part of the official product, write it in dump_dir
444
+ out_dsm_file_name = os.path.join(out_dump_dir, "dsm.tif")
445
+ if out_dsm_file_name is not None:
446
+ list_computed_layers += ["dsm"]
447
+ self.orchestrator.add_to_save_lists(
448
+ out_dsm_file_name,
449
+ cst.RASTER_HGT,
450
+ terrain_raster,
451
+ dtype=np.float32,
452
+ nodata=self.dsm_no_data,
453
+ cars_ds_name="dsm",
454
+ )
455
+ paths_data[cst.RASTER_HGT] = out_dsm_file_name
456
+
457
+ out_weights_file_name = weights_file_name
458
+ if out_weights_file_name is not None:
459
+ # add contributing pair filename to index
460
+ self.orchestrator.update_index(
461
+ {
462
+ "dsm": {
463
+ cst.INDEX_DSM_WEIGHTS: os.path.basename(
464
+ out_weights_file_name
465
+ )
466
+ }
467
+ }
468
+ )
469
+ else:
470
+ # Always write weights.tif, but dump_dir is in the orchestrator
471
+ # clean list if save_intermediate_data is not activated
472
+ out_weights_file_name = os.path.join(out_dump_dir, "weights.tif")
473
+ if out_weights_file_name is not None:
474
+ list_computed_layers += ["weights"]
475
+ self.orchestrator.add_to_save_lists(
476
+ out_weights_file_name,
477
+ cst.RASTER_WEIGHTS_SUM,
478
+ terrain_raster,
479
+ dtype=np.float32,
480
+ nodata=0,
481
+ cars_ds_name="dsm_weights",
482
+ )
483
+ paths_data[cst.RASTER_WEIGHTS_SUM] = out_weights_file_name
484
+
485
+ out_clr_file_name = color_file_name
486
+ if out_clr_file_name is not None:
487
+ # add contributing pair filename to index
488
+ self.orchestrator.update_index(
489
+ {
490
+ "dsm": {
491
+ cst.INDEX_DSM_COLOR: os.path.basename(out_clr_file_name)
492
+ }
493
+ }
494
+ )
495
+ elif save_intermediate_data:
496
+ # File is not part of the official product, write it in dump_dir
497
+ out_clr_file_name = os.path.join(out_dump_dir, "image.tif")
498
+ if out_clr_file_name is not None:
499
+ list_computed_layers += ["texture"]
500
+
501
+ self.orchestrator.add_to_save_lists(
502
+ out_clr_file_name,
503
+ cst.RASTER_COLOR_IMG,
504
+ terrain_raster,
505
+ dtype=self.color_dtype,
506
+ nodata=self.texture_no_data,
507
+ cars_ds_name="texture",
508
+ )
509
+ paths_data[cst.RASTER_COLOR_IMG] = out_clr_file_name
510
+
511
+ out_classif_file_name = classif_file_name
512
+ if out_classif_file_name is not None:
513
+ # add contributing pair filename to index
514
+ self.orchestrator.update_index(
515
+ {
516
+ "dsm": {
517
+ cst.INDEX_DSM_CLASSIFICATION: os.path.basename(
518
+ out_classif_file_name
519
+ )
520
+ }
521
+ }
522
+ )
523
+ elif save_intermediate_data:
524
+ # File is not part of the official product, write it in dump_dir
525
+ out_classif_file_name = os.path.join(
526
+ out_dump_dir, "classification.tif"
527
+ )
528
+
529
+ if out_classif_file_name is not None:
530
+ list_computed_layers += ["classif"]
531
+ self.orchestrator.add_to_save_lists(
532
+ out_classif_file_name,
533
+ cst.RASTER_CLASSIF,
534
+ terrain_raster,
535
+ dtype=np.uint8,
536
+ nodata=self.msk_no_data,
537
+ cars_ds_name="dsm_classif",
538
+ optional_data=True,
539
+ )
540
+ paths_data[cst.RASTER_CLASSIF] = out_classif_file_name
541
+
542
+ out_performance_map = performance_map_file_name
543
+
544
+ # save raw as performance map if performance_map_classes is None
545
+ # save classified performance map if performance_map_classes is not None
546
+ out_performance_map_raw = None
547
+ if out_performance_map is not None:
548
+ # add contributing pair filename to index
549
+ self.orchestrator.update_index(
550
+ {
551
+ "dsm": {
552
+ cst.INDEX_DSM_PERFORMANCE_MAP: os.path.basename(
553
+ out_performance_map
554
+ )
555
+ }
556
+ }
557
+ )
558
+ if performance_map_classes is False:
559
+ # No classes, we return raw data
560
+ out_performance_map_raw = out_performance_map
561
+ out_performance_map = None
562
+ elif save_intermediate_data:
563
+ # File is not part of the official product, write it in dump_dir
564
+ out_performance_map = os.path.join(
565
+ out_dump_dir, "performance_map.tif"
566
+ )
567
+ out_performance_map_raw = os.path.join(
568
+ out_dump_dir, "performance_map_raw.tif"
569
+ )
570
+
571
+ if out_performance_map_raw is not None:
572
+ list_computed_layers += ["performance_map_raw"]
573
+ self.orchestrator.add_to_save_lists(
574
+ out_performance_map_raw,
575
+ cst.RASTER_PERFORMANCE_MAP_RAW,
576
+ terrain_raster,
577
+ dtype=np.float32,
578
+ nodata=self.msk_no_data,
579
+ cars_ds_name="performance_map_raw",
580
+ optional_data=True,
581
+ )
582
+ paths_data[cst.RASTER_PERFORMANCE_MAP_RAW] = out_performance_map_raw
583
+
584
+ if out_performance_map is not None:
585
+ # classified performance map exists
586
+ list_computed_layers += ["performance_map"]
587
+ self.orchestrator.add_to_save_lists(
588
+ out_performance_map,
589
+ cst.RASTER_PERFORMANCE_MAP,
590
+ terrain_raster,
591
+ dtype=np.uint8,
592
+ nodata=self.msk_no_data,
593
+ cars_ds_name="performance_map",
594
+ optional_data=True,
595
+ )
596
+ paths_data[cst.RASTER_PERFORMANCE_MAP] = out_performance_map
597
+
598
+ out_ambiguity = ambiguity_file_name
599
+ if out_ambiguity is not None:
600
+ # add contributing pair filename to index
601
+ self.orchestrator.update_index(
602
+ {
603
+ "dsm": {
604
+ cst.INDEX_DSM_AMBIGUITY: os.path.basename(out_ambiguity)
605
+ }
606
+ }
607
+ )
608
+ elif save_intermediate_data:
609
+ # File is not part of the official product, write it in dump_dir
610
+ out_ambiguity = os.path.join(out_dump_dir, "ambiguity.tif")
611
+ if out_ambiguity:
612
+ list_computed_layers += ["ambiguity"]
613
+ self.orchestrator.add_to_save_lists(
614
+ out_ambiguity,
615
+ cst.RASTER_AMBIGUITY,
616
+ terrain_raster,
617
+ dtype=np.float32,
618
+ nodata=self.msk_no_data,
619
+ cars_ds_name="ambiguity",
620
+ optional_data=True,
621
+ )
622
+ paths_data[cst.RASTER_AMBIGUITY] = out_ambiguity
623
+
624
+ out_source_pc = contributing_pair_file_name
625
+ if out_source_pc is not None:
626
+ # add contributing pair filename to index
627
+ self.orchestrator.update_index(
628
+ {
629
+ "dsm": {
630
+ cst.INDEX_DSM_CONTRIBUTING_PAIR: os.path.basename(
631
+ out_source_pc
632
+ )
633
+ }
634
+ }
635
+ )
636
+ elif save_intermediate_data:
637
+ # File is not part of the official product, write it in dump_dir
638
+ out_source_pc = os.path.join(out_dump_dir, "contributing_pair.tif")
639
+ if out_source_pc:
640
+ list_computed_layers += ["source_pc"]
641
+ self.orchestrator.add_to_save_lists(
642
+ out_source_pc,
643
+ cst.RASTER_SOURCE_PC,
644
+ terrain_raster,
645
+ dtype=np.uint8,
646
+ nodata=self.msk_no_data,
647
+ cars_ds_name="contributing_pair",
648
+ optional_data=True,
649
+ )
650
+ paths_data[cst.RASTER_SOURCE_PC] = out_source_pc
651
+
652
+ out_filling = filling_file_name
653
+ if out_filling is not None:
654
+ # add filling filename to index
655
+ self.orchestrator.update_index(
656
+ {"dsm": {cst.INDEX_DSM_FILLING: os.path.basename(out_filling)}}
657
+ )
658
+ elif save_intermediate_data:
659
+ # File is not part of the official product, write it in dump_dir
660
+ out_filling = os.path.join(out_dump_dir, "filling.tif")
661
+ if out_filling:
662
+ list_computed_layers += ["filling"]
663
+ self.orchestrator.add_to_save_lists(
664
+ out_filling,
665
+ cst.RASTER_FILLING,
666
+ terrain_raster,
667
+ dtype=np.uint8,
668
+ nodata=self.msk_no_data,
669
+ cars_ds_name="filling",
670
+ optional_data=True,
671
+ )
672
+ paths_data[cst.RASTER_FILLING] = out_filling
673
+
674
+ # TODO Check that intervals indeed exist!
675
+ if save_intermediate_data:
676
+ list_computed_layers += [cst.POINT_CLOUD_LAYER_SUP_OR_INF_ROOT]
677
+ out_dsm_inf_file_name = os.path.join(out_dump_dir, "dsm_inf.tif")
678
+ self.orchestrator.add_to_save_lists(
679
+ out_dsm_inf_file_name,
680
+ cst.RASTER_HGT_INF,
681
+ terrain_raster,
682
+ dtype=np.float32,
683
+ nodata=self.dsm_no_data,
684
+ cars_ds_name="dsm_inf",
685
+ optional_data=True,
686
+ )
687
+ out_dsm_sup_file_name = os.path.join(out_dump_dir, "dsm_sup.tif")
688
+ self.orchestrator.add_to_save_lists(
689
+ out_dsm_sup_file_name,
690
+ cst.RASTER_HGT_SUP,
691
+ terrain_raster,
692
+ dtype=np.float32,
693
+ nodata=self.dsm_no_data,
694
+ cars_ds_name="dsm_sup",
695
+ optional_data=True,
696
+ )
697
+
698
+ out_dsm_mean_file_name = os.path.join(out_dump_dir, "dsm_mean.tif")
699
+ out_dsm_std_file_name = os.path.join(out_dump_dir, "dsm_std.tif")
700
+ out_dsm_n_pts_file_name = os.path.join(
701
+ out_dump_dir, "dsm_n_pts.tif"
702
+ )
703
+ out_dsm_points_in_cell_file_name = os.path.join(
704
+ out_dump_dir, "dsm_pts_in_cell.tif"
705
+ )
706
+ self.orchestrator.add_to_save_lists(
707
+ out_dsm_mean_file_name,
708
+ cst.RASTER_HGT_MEAN,
709
+ terrain_raster,
710
+ dtype=np.float32,
711
+ nodata=self.dsm_no_data,
712
+ cars_ds_name="dsm_mean",
713
+ )
714
+ self.orchestrator.add_to_save_lists(
715
+ out_dsm_std_file_name,
716
+ cst.RASTER_HGT_STD_DEV,
717
+ terrain_raster,
718
+ dtype=np.float32,
719
+ nodata=self.dsm_no_data,
720
+ cars_ds_name="dsm_std",
721
+ )
722
+ self.orchestrator.add_to_save_lists(
723
+ out_dsm_n_pts_file_name,
724
+ cst.RASTER_NB_PTS,
725
+ terrain_raster,
726
+ dtype=np.uint16,
727
+ nodata=0,
728
+ cars_ds_name="dsm_n_pts",
729
+ )
730
+ self.orchestrator.add_to_save_lists(
731
+ out_dsm_points_in_cell_file_name,
732
+ cst.RASTER_NB_PTS_IN_CELL,
733
+ terrain_raster,
734
+ dtype=np.uint16,
735
+ nodata=0,
736
+ cars_ds_name="dsm_pts_in_cells",
737
+ )
738
+
739
+ out_dsm_inf_mean_file_name = os.path.join(
740
+ out_dump_dir, "dsm_inf_mean.tif"
741
+ )
742
+ out_dsm_inf_std_file_name = os.path.join(
743
+ out_dump_dir, "dsm_inf_std.tif"
744
+ )
745
+
746
+ self.orchestrator.add_to_save_lists(
747
+ out_dsm_inf_mean_file_name,
748
+ cst.RASTER_HGT_INF_MEAN,
749
+ terrain_raster,
750
+ dtype=np.float32,
751
+ nodata=self.dsm_no_data,
752
+ cars_ds_name="dsm_inf_mean",
753
+ optional_data=True,
754
+ )
755
+
756
+ self.orchestrator.add_to_save_lists(
757
+ out_dsm_inf_std_file_name,
758
+ cst.RASTER_HGT_INF_STD_DEV,
759
+ terrain_raster,
760
+ dtype=np.float32,
761
+ nodata=self.dsm_no_data,
762
+ cars_ds_name="dsm_inf_std",
763
+ optional_data=True,
764
+ )
765
+
766
+ out_dsm_sup_mean_file_name = os.path.join(
767
+ out_dump_dir, "dsm_sup_mean.tif"
768
+ )
769
+ out_dsm_sup_std_file_name = os.path.join(
770
+ out_dump_dir, "dsm_sup_std.tif"
771
+ )
772
+
773
+ self.orchestrator.add_to_save_lists(
774
+ out_dsm_sup_mean_file_name,
775
+ cst.RASTER_HGT_SUP_MEAN,
776
+ terrain_raster,
777
+ dtype=np.float32,
778
+ nodata=self.dsm_no_data,
779
+ cars_ds_name="dsm_sup_mean",
780
+ optional_data=True,
781
+ )
782
+ self.orchestrator.add_to_save_lists(
783
+ out_dsm_sup_std_file_name,
784
+ cst.RASTER_HGT_SUP_STD_DEV,
785
+ terrain_raster,
786
+ dtype=np.float32,
787
+ nodata=self.dsm_no_data,
788
+ cars_ds_name="dsm_sup_std",
789
+ optional_data=True,
790
+ )
791
+
792
+ # Get saving infos in order to save tiles when they are computed
793
+ [saving_info] = self.orchestrator.get_saving_infos([terrain_raster])
794
+
795
+ # Generate profile
796
+ geotransform = (
797
+ bounds[0],
798
+ resolution,
799
+ 0.0,
800
+ bounds[3],
801
+ 0.0,
802
+ -resolution,
803
+ )
804
+
805
+ transform = Affine.from_gdal(*geotransform)
806
+ raster_profile = collections.OrderedDict(
807
+ {
808
+ "height": ysize,
809
+ "width": xsize,
810
+ "driver": "GTiff",
811
+ "dtype": "float32",
812
+ "transform": transform,
813
+ "crs": output_crs.to_wkt(),
814
+ "tiled": True,
815
+ }
816
+ )
817
+
818
+ # Get number of tiles
819
+ logging.info(
820
+ "Number of tiles in cloud rasterization: "
821
+ "row: {} "
822
+ "col: {}".format(
823
+ terrain_raster.tiling_grid.shape[0],
824
+ terrain_raster.tiling_grid.shape[1],
825
+ )
826
+ )
827
+
828
+ # Add infos to orchestrator.out_json
829
+ updating_dict = {
830
+ application_constants.APPLICATION_TAG: {
831
+ raster_cst.RASTERIZATION_RUN_TAG: {
832
+ raster_cst.EPSG_TAG: epsg,
833
+ raster_cst.DSM_NO_DATA_TAG: float(self.dsm_no_data),
834
+ },
835
+ }
836
+ }
837
+ if self.texture_no_data is not None:
838
+ updating_dict[application_constants.APPLICATION_TAG][
839
+ raster_cst.RASTERIZATION_RUN_TAG
840
+ ][raster_cst.TEXTURE_NO_DATA_TAG] = float(self.texture_no_data)
841
+
842
+ self.orchestrator.update_out_info(updating_dict)
843
+
844
+ # Add attributrs
845
+ terrain_raster.attributes["paths"] = paths_data
846
+
847
+ # Add final function to apply
848
+ terrain_raster.final_function = raster_final_function
849
+ ind_tile = 0
850
+ for point_cloud in point_clouds[0]:
851
+ for row_pc in range(point_cloud.shape[0]):
852
+ for col_pc in range(point_cloud.shape[1]):
853
+ # update saving infos for potential replacement
854
+ full_saving_info = ocht.update_saving_infos(
855
+ saving_info, row=0, col=ind_tile
856
+ )
857
+ if point_cloud[row_pc, col_pc] is not None:
858
+ # Delayed call to rasterization operations using all
859
+ # required point clouds
860
+ terrain_raster[
861
+ 0, ind_tile
862
+ ] = self.orchestrator.cluster.create_task(
863
+ rasterization_wrapper
864
+ )(
865
+ point_cloud[row_pc, col_pc],
866
+ resolution,
867
+ epsg,
868
+ raster_profile,
869
+ window=None,
870
+ terrain_region=None,
871
+ terrain_full_roi=bounds,
872
+ list_computed_layers=list_computed_layers,
873
+ saving_info=full_saving_info,
874
+ radius=self.dsm_radius,
875
+ sigma=self.sigma,
876
+ dsm_no_data=self.dsm_no_data,
877
+ texture_no_data=self.texture_no_data,
878
+ color_dtype=color_dtype,
879
+ msk_no_data=self.msk_no_data,
880
+ source_pc_names=source_pc_names,
881
+ performance_map_classes=performance_map_classes,
882
+ )
883
+ ind_tile += 1
884
+
885
+ # Sort tiles according to rank TODO remove or implement it ?
886
+
887
+ return terrain_raster
888
+
889
+
890
+ # pylint: disable=too-many-positional-arguments
891
+ def rasterization_wrapper( # noqa: C901
892
+ cloud,
893
+ resolution,
894
+ epsg,
895
+ profile,
896
+ window=None,
897
+ terrain_region=None,
898
+ terrain_full_roi=None,
899
+ list_computed_layers: List[str] = None,
900
+ saving_info=None,
901
+ sigma: float = None,
902
+ radius: int = 1,
903
+ dsm_no_data: int = np.nan,
904
+ texture_no_data: int = np.nan,
905
+ color_dtype: str = "float32",
906
+ msk_no_data: int = 255,
907
+ source_pc_names=None,
908
+ performance_map_classes=None,
909
+ ):
910
+ """
911
+ Wrapper for rasterization step :
912
+ - Convert a list of clouds to correct epsg
913
+ - Rasterize it with associated colors
914
+
915
+ if terrain_region is not provided: region is computed from point cloud,
916
+ with margin to use
917
+
918
+ :param cloud: combined cloud
919
+ :type cloud: pandas.DataFrame
920
+ :param terrain_region: terrain bounds
921
+ :param resolution: Produced DSM resolution (meter, degree [EPSG dependent])
922
+ :type resolution: float
923
+ :param epsg_code: epsg code for the CRS of the output DSM
924
+ :type epsg_code: int
925
+ :param window: Window considered
926
+ :type window: int
927
+ :param margin: margin in pixel to use
928
+ :type margin: int
929
+ :param profile: rasterio profile
930
+ :param list_computed_layers: list of computed output data
931
+ :type profile: dict
932
+ :param saving_info: information about CarsDataset ID.
933
+ :type saving_info: dict
934
+ :param sigma: sigma for gaussian interpolation.
935
+ (If None, set to resolution)
936
+ :param radius: Radius for hole filling.
937
+ :param dsm_no_data: no data value to use in the final raster
938
+ :param texture_no_data: no data value to use in the final colored raster
939
+ :param msk_no_data: no data value to use in the final mask image
940
+ :param source_pc_names: list of names of point cloud before merging :
941
+ name of sensors pair or name of point cloud file
942
+ :param performance_map_classes: list for step defining border of class
943
+ :type performance_map_classes: list or None
944
+
945
+ :return: digital surface model + projected colors
946
+ :rtype: xr.Dataset
947
+ """
948
+ # update attributes
949
+ attributes = copy.deepcopy(cloud.attrs)
950
+ attributes.update(attributes.get("attributes", {}))
951
+ if "attributes" in attributes:
952
+ del attributes["attributes"]
953
+ if "saving_info" in attributes:
954
+ del attributes["saving_info"]
955
+
956
+ # convert back to correct epsg
957
+ # If the point cloud is not in the right epsg referential, it is converted
958
+ if isinstance(cloud, xarray.Dataset):
959
+ # Transform Dataset to Dataframe
960
+ cloud, cloud_epsg = pc_transform.depth_map_dataset_to_dataframe(
961
+ cloud, epsg
962
+ )
963
+ elif cloud is None:
964
+ logging.warning("Input cloud is None")
965
+ return None
966
+ else:
967
+ cloud_epsg = attributes.get("epsg")
968
+
969
+ if "number_of_pc" not in attributes:
970
+ if source_pc_names is not None:
971
+ attributes["number_of_pc"] = len(source_pc_names)
972
+ else:
973
+ attributes["number_of_pc"] = None
974
+
975
+ # update attributes
976
+ cloud.attrs = {}
977
+ cars_dataset.fill_dataframe(cloud, attributes=attributes)
978
+
979
+ if epsg != cloud_epsg:
980
+ projection.point_cloud_conversion_dataframe(cloud, cloud_epsg, epsg)
981
+
982
+ # filter cloud
983
+ if "mask" in cloud:
984
+ cloud = cloud[cloud["mask"] == 0]
985
+
986
+ if cloud.dropna(subset=["x", "y", "z"]).empty:
987
+ return None
988
+
989
+ # Compute start and size
990
+ if terrain_region is None:
991
+ # compute region from cloud
992
+ xmin = np.nanmin(cloud["x"])
993
+ xmax = np.nanmax(cloud["x"])
994
+ ymin = np.nanmin(cloud["y"])
995
+ ymax = np.nanmax(cloud["y"])
996
+ # Add margin to be sure every point is rasterized
997
+ terrain_region = [
998
+ xmin - radius * resolution,
999
+ ymin - radius * resolution,
1000
+ xmax + radius * resolution,
1001
+ ymax + radius * resolution,
1002
+ ]
1003
+
1004
+ if terrain_full_roi is not None:
1005
+ # Modify start (used in tiling.roi_to_start_and_size) [0, 3]
1006
+ # to share the same global grid
1007
+ terrain_region[0] = (
1008
+ terrain_full_roi[0]
1009
+ + np.round(
1010
+ (terrain_region[0] - terrain_full_roi[0]) / resolution
1011
+ )
1012
+ * resolution
1013
+ )
1014
+ terrain_region[3] = (
1015
+ terrain_full_roi[3]
1016
+ + np.round(
1017
+ (terrain_region[3] - terrain_full_roi[3]) / resolution
1018
+ )
1019
+ * resolution
1020
+ )
1021
+ # Crop
1022
+ terrain_region = [
1023
+ max(terrain_full_roi[0], terrain_region[0]),
1024
+ max(terrain_full_roi[1], terrain_region[1]),
1025
+ min(terrain_full_roi[2], terrain_region[2]),
1026
+ min(terrain_full_roi[3], terrain_region[3]),
1027
+ ]
1028
+
1029
+ if (
1030
+ terrain_region[0] > terrain_region[2]
1031
+ or terrain_region[1] > terrain_region[3]
1032
+ ):
1033
+ return None
1034
+
1035
+ xstart, ystart, xsize, ysize = tiling.roi_to_start_and_size(
1036
+ terrain_region, resolution
1037
+ )
1038
+
1039
+ if xsize == 0 or ysize == 0:
1040
+ logging.warning("Tile is empty")
1041
+ return None
1042
+
1043
+ if window is None:
1044
+ transform = rio.Affine(*profile["transform"][0:6])
1045
+ row_pix_pos, col_pix_pos = rio.transform.AffineTransformer(
1046
+ transform
1047
+ ).rowcol(xstart, ystart)
1048
+ window = [
1049
+ row_pix_pos,
1050
+ row_pix_pos + ysize,
1051
+ col_pix_pos,
1052
+ col_pix_pos + xsize,
1053
+ ]
1054
+
1055
+ window = cars_dataset.window_array_to_dict(window)
1056
+
1057
+ # Call simple_rasterization
1058
+ raster = rasterization_algo.simple_rasterization_dataset_wrapper(
1059
+ cloud,
1060
+ resolution,
1061
+ epsg,
1062
+ xstart=xstart,
1063
+ ystart=ystart,
1064
+ xsize=xsize,
1065
+ ysize=ysize,
1066
+ sigma=sigma,
1067
+ radius=radius,
1068
+ dsm_no_data=dsm_no_data,
1069
+ texture_no_data=texture_no_data,
1070
+ msk_no_data=msk_no_data,
1071
+ list_computed_layers=list_computed_layers,
1072
+ source_pc_names=source_pc_names,
1073
+ performance_map_classes=performance_map_classes,
1074
+ cloud_global_id=attributes["cloud_id"],
1075
+ )
1076
+
1077
+ # Fill raster
1078
+ attributes = {
1079
+ "color_type": color_dtype,
1080
+ cst.CROPPED_DISPARITY_RANGE: (ocht.get_disparity_range_cropped(cloud)),
1081
+ }
1082
+ if raster is not None:
1083
+ cars_dataset.fill_dataset(
1084
+ raster,
1085
+ saving_info=saving_info,
1086
+ window=window,
1087
+ profile=profile,
1088
+ attributes=attributes,
1089
+ overlaps=None,
1090
+ )
1091
+
1092
+ return raster
1093
+
1094
+
1095
+ def raster_final_function(orchestrator, future_object):
1096
+ """
1097
+ Apply function to current object, reading already rasterized data
1098
+
1099
+ :param orchestrator: orchestrator
1100
+ :param future_object: Dataset
1101
+
1102
+ :return: update object
1103
+ """
1104
+ # Get data weights
1105
+ old_weights, _ = orchestrator.get_data(
1106
+ cst.RASTER_WEIGHTS_SUM, future_object
1107
+ )
1108
+ weights = future_object[cst.RASTER_WEIGHTS_SUM].values
1109
+
1110
+ future_object[cst.RASTER_WEIGHTS_SUM].values = np.reshape(
1111
+ rasterization_wrappers.update_weights(old_weights, weights),
1112
+ weights.shape,
1113
+ )
1114
+
1115
+ # Get color type
1116
+ color_type = future_object.attrs["attributes"]["color_type"]
1117
+
1118
+ # Get data dsm
1119
+ for tag in future_object.keys():
1120
+
1121
+ if tag != cst.RASTER_WEIGHTS_SUM:
1122
+
1123
+ if tag in [cst.RASTER_NB_PTS, cst.RASTER_NB_PTS_IN_CELL]:
1124
+ method = "sum"
1125
+ elif tag in [
1126
+ cst.RASTER_FILLING,
1127
+ cst.RASTER_CLASSIF,
1128
+ cst.RASTER_SOURCE_PC,
1129
+ ]:
1130
+ method = "bool"
1131
+ else:
1132
+ method = "basic"
1133
+
1134
+ old_data, nodata_raster = orchestrator.get_data(tag, future_object)
1135
+ current_data = future_object[tag].values
1136
+ if tag == cst.RASTER_COLOR_IMG and np.issubdtype(
1137
+ color_type, np.integer
1138
+ ):
1139
+ current_data = np.round(current_data).astype(color_type)
1140
+ future_object[tag].values = np.reshape(
1141
+ rasterization_wrappers.update_data(
1142
+ old_data,
1143
+ current_data,
1144
+ weights,
1145
+ old_weights,
1146
+ nodata_raster,
1147
+ method=method,
1148
+ ),
1149
+ current_data.shape,
1150
+ )
1151
+
1152
+ return future_object