cars 1.0.0rc1__cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.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 (200) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +37 -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 +104 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -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 +42 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +655 -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 +1460 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-312-i386-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 +588 -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 +270 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
  56. cars/applications/grid_generation/__init__.py +30 -0
  57. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  58. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  59. cars/applications/grid_generation/grid_correction_app.py +496 -0
  60. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  61. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  62. cars/applications/grid_generation/transform_grid.py +88 -0
  63. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  64. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  65. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  66. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  67. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  68. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  69. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  70. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  71. cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
  72. cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
  73. cars/applications/rasterization/__init__.py +30 -0
  74. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  75. cars/applications/rasterization/rasterization_algo.py +534 -0
  76. cars/applications/rasterization/rasterization_constants.py +38 -0
  77. cars/applications/rasterization/rasterization_wrappers.py +634 -0
  78. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  79. cars/applications/resampling/__init__.py +28 -0
  80. cars/applications/resampling/abstract_resampling_app.py +187 -0
  81. cars/applications/resampling/bicubic_resampling_app.py +762 -0
  82. cars/applications/resampling/resampling_algo.py +614 -0
  83. cars/applications/resampling/resampling_constants.py +36 -0
  84. cars/applications/resampling/resampling_wrappers.py +309 -0
  85. cars/applications/sparse_matching/__init__.py +30 -0
  86. cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
  87. cars/applications/sparse_matching/sift_app.py +735 -0
  88. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  89. cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
  90. cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
  91. cars/applications/triangulation/__init__.py +32 -0
  92. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  93. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  94. cars/applications/triangulation/pc_transform.py +552 -0
  95. cars/applications/triangulation/triangulation_algo.py +371 -0
  96. cars/applications/triangulation/triangulation_constants.py +38 -0
  97. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  98. cars/bundleadjustment.py +757 -0
  99. cars/cars.py +177 -0
  100. cars/conf/__init__.py +23 -0
  101. cars/conf/geoid/egm96.grd +0 -0
  102. cars/conf/geoid/egm96.grd.hdr +15 -0
  103. cars/conf/input_parameters.py +156 -0
  104. cars/conf/mask_cst.py +35 -0
  105. cars/core/__init__.py +23 -0
  106. cars/core/cars_logging.py +402 -0
  107. cars/core/constants.py +191 -0
  108. cars/core/constants_disparity.py +50 -0
  109. cars/core/datasets.py +140 -0
  110. cars/core/geometry/__init__.py +27 -0
  111. cars/core/geometry/abstract_geometry.py +1119 -0
  112. cars/core/geometry/shareloc_geometry.py +598 -0
  113. cars/core/inputs.py +568 -0
  114. cars/core/outputs.py +176 -0
  115. cars/core/preprocessing.py +722 -0
  116. cars/core/projection.py +843 -0
  117. cars/core/roi_tools.py +215 -0
  118. cars/core/tiling.py +774 -0
  119. cars/core/utils.py +164 -0
  120. cars/data_structures/__init__.py +23 -0
  121. cars/data_structures/cars_dataset.py +1541 -0
  122. cars/data_structures/cars_dict.py +74 -0
  123. cars/data_structures/corresponding_tiles_tools.py +186 -0
  124. cars/data_structures/dataframe_converter.py +185 -0
  125. cars/data_structures/format_transformation.py +297 -0
  126. cars/devibrate.py +689 -0
  127. cars/extractroi.py +264 -0
  128. cars/orchestrator/__init__.py +23 -0
  129. cars/orchestrator/achievement_tracker.py +125 -0
  130. cars/orchestrator/cluster/__init__.py +37 -0
  131. cars/orchestrator/cluster/abstract_cluster.py +244 -0
  132. cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
  133. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  134. cars/orchestrator/cluster/dask_config/README.md +94 -0
  135. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  136. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  137. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  138. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  139. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  140. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  141. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  142. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  143. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  144. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  145. cars/orchestrator/cluster/log_wrapper.py +1075 -0
  146. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  147. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  148. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  149. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  150. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  151. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
  152. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  153. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  154. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  155. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  156. cars/orchestrator/orchestrator.py +905 -0
  157. cars/orchestrator/orchestrator_constants.py +29 -0
  158. cars/orchestrator/registry/__init__.py +23 -0
  159. cars/orchestrator/registry/abstract_registry.py +143 -0
  160. cars/orchestrator/registry/compute_registry.py +106 -0
  161. cars/orchestrator/registry/id_generator.py +116 -0
  162. cars/orchestrator/registry/replacer_registry.py +213 -0
  163. cars/orchestrator/registry/saver_registry.py +363 -0
  164. cars/orchestrator/registry/unseen_registry.py +118 -0
  165. cars/orchestrator/tiles_profiler.py +279 -0
  166. cars/pipelines/__init__.py +26 -0
  167. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  168. cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
  169. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  170. cars/pipelines/default/__init__.py +26 -0
  171. cars/pipelines/default/default_pipeline.py +786 -0
  172. cars/pipelines/parameters/__init__.py +0 -0
  173. cars/pipelines/parameters/advanced_parameters.py +417 -0
  174. cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
  175. cars/pipelines/parameters/application_parameters.py +71 -0
  176. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  177. cars/pipelines/parameters/dsm_inputs.py +918 -0
  178. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  179. cars/pipelines/parameters/output_constants.py +52 -0
  180. cars/pipelines/parameters/output_parameters.py +454 -0
  181. cars/pipelines/parameters/sensor_inputs.py +842 -0
  182. cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
  183. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  184. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  185. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  186. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  187. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  188. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  189. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  190. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  191. cars/pipelines/pipeline.py +119 -0
  192. cars/pipelines/pipeline_constants.py +31 -0
  193. cars/pipelines/pipeline_template.py +139 -0
  194. cars/pipelines/unit/__init__.py +26 -0
  195. cars/pipelines/unit/unit_pipeline.py +2850 -0
  196. cars/starter.py +167 -0
  197. cars-1.0.0rc1.dist-info/METADATA +292 -0
  198. cars-1.0.0rc1.dist-info/RECORD +200 -0
  199. cars-1.0.0rc1.dist-info/WHEEL +6 -0
  200. cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,371 @@
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
+ """
22
+ Preprocessing module:
23
+ contains functions used for triangulation
24
+ """
25
+
26
+ # Standard imports
27
+ from typing import Dict
28
+
29
+ import numpy as np
30
+ import pandas
31
+ import xarray as xr
32
+
33
+ from cars.applications.triangulation import (
34
+ triangulation_wrappers as triang_wrap,
35
+ )
36
+ from cars.core import constants as cst
37
+ from cars.core import constants_disparity as cst_disp
38
+ from cars.core import projection
39
+
40
+
41
+ def triangulate( # pylint: disable=too-many-positional-arguments
42
+ geometry_plugin,
43
+ sensor1,
44
+ sensor2,
45
+ geomodel1,
46
+ geomodel2,
47
+ grid1,
48
+ grid2,
49
+ disp_ref: xr.Dataset,
50
+ disp_key: str = cst_disp.MAP,
51
+ ) -> Dict[str, xr.Dataset]:
52
+ """
53
+ This function will perform triangulation from a disparity map
54
+
55
+ :param geometry_plugin: geometry plugin to use
56
+ :type geometry_plugin: AbstractGeometry
57
+ :param sensor1: path to left sensor image
58
+ :type sensor1: str
59
+ :param sensor2: path to right sensor image
60
+ :type sensor2: str
61
+ :param geomodel1: path and attributes for left geomodel
62
+ :type geomodel1: dict
63
+ :param geomodel2: path and attributes for right geomodel
64
+ :type geomodel2: dict
65
+ :param grid1: dataset of the reference image grid file
66
+ :type grid1: CarsDataset
67
+ :param grid2: dataset of the secondary image grid file
68
+ :type grid2: CarsDataset
69
+ :param disp_ref: left to right disparity map dataset
70
+ :param im_ref_msk_ds: reference image dataset (image and
71
+ mask (if indicated by the user) in epipolar geometry)
72
+ :param disp_key: disparity key in the dataset\
73
+ usually set to cst_disp.MAP, but can be a disparity interval bound
74
+ :returns: point_cloud as a dictionary of dataset containing:
75
+
76
+ - Array with shape (roi_size_x,roi_size_y,3), with last dimension \
77
+ corresponding to longitude, latitude and elevation
78
+ - Array with shape (roi_size_x,roi_size_y) with output mask
79
+ - Array for color (optional): only if color1 is not None
80
+
81
+ The dictionary keys are :
82
+
83
+ - 'ref' to retrieve the dataset built from the left to \
84
+ right disparity map
85
+ - 'sec' to retrieve the dataset built from the right to \
86
+ left disparity map (if provided in input)
87
+ """
88
+
89
+ if disp_key != cst_disp.MAP:
90
+ # Switching the variable names so the desired disparity is named 'disp'
91
+ # It does not modifies the dataset outside of this function
92
+ disp_ref = disp_ref.rename_vars(
93
+ {disp_key: cst_disp.MAP, cst_disp.MAP: disp_key}
94
+ )
95
+
96
+ point_clouds = {}
97
+ point_clouds[cst.STEREO_REF] = compute_point_cloud(
98
+ geometry_plugin,
99
+ sensor1,
100
+ sensor2,
101
+ geomodel1,
102
+ geomodel2,
103
+ grid1,
104
+ grid2,
105
+ disp_ref,
106
+ roi_key=cst.ROI_WITH_MARGINS,
107
+ )
108
+
109
+ return point_clouds
110
+
111
+
112
+ def triangulate_matches( # pylint: disable=too-many-positional-arguments
113
+ geometry_plugin,
114
+ sensor1,
115
+ sensor2,
116
+ geomodel1,
117
+ geomodel2,
118
+ grid1,
119
+ grid2,
120
+ matches,
121
+ interpolation_method=None,
122
+ ):
123
+ """
124
+ This function will perform triangulation from sift matches
125
+
126
+ :param geometry_plugin: geometry plugin to use
127
+ :type geometry_plugin: AbstractGeometry
128
+ :param sensor1: path to left sensor image
129
+ :type sensor1: str
130
+ :param sensor2: path to right sensor image
131
+ :type sensor2: str
132
+ :param geomodel1: path and attributes for left geomodel
133
+ :type geomodel1: dict
134
+ :param geomodel2: path and attributes for right geomodel
135
+ :type geomodel2: dict
136
+ :param grid1: dataset of the reference image grid file
137
+ :type grid1: CarsDataset
138
+ :param grid2: dataset of the secondary image grid file
139
+ :type grid2: CarsDataset
140
+ :param matches: numpy.array of matches of shape (nb_matches, 4)
141
+ :type data: numpy.ndarray
142
+ :returns: point_cloud as a panda DataFrame containing:
143
+
144
+ - Array with shape (nb_matches,1,3), with last dimension \
145
+ corresponding to longitude, latitude and elevation
146
+ - Array with shape (nb_matches,1) with output mask
147
+ - cst.X
148
+ - cst.Y
149
+ - cst.Z
150
+ - corr_mask
151
+ - lon
152
+ - lat
153
+
154
+
155
+ :rtype: pandas.DataFrame
156
+ """
157
+ llh = geometry_plugin.triangulate(
158
+ sensor1,
159
+ sensor2,
160
+ geomodel1,
161
+ geomodel2,
162
+ cst.MATCHES_MODE,
163
+ matches,
164
+ grid1,
165
+ grid2,
166
+ interpolation_method=interpolation_method,
167
+ )
168
+
169
+ disparity = np.array([matches[:, 2] - matches[:, 0]])
170
+ disparity = np.transpose(disparity)
171
+
172
+ msk = np.full(llh.shape[0:2], 255, dtype=np.uint8)
173
+
174
+ point_cloud_index = [
175
+ cst.X,
176
+ cst.Y,
177
+ cst.Z,
178
+ cst.DISPARITY,
179
+ cst.POINT_CLOUD_CORR_MSK,
180
+ ]
181
+ point_cloud_array = np.zeros(
182
+ (np.ravel(llh[:, :, 0]).size, len(point_cloud_index)), dtype=np.float64
183
+ )
184
+ point_cloud_array[:, 0] = np.ravel(llh[:, :, 0])
185
+ point_cloud_array[:, 1] = np.ravel(llh[:, :, 1])
186
+ point_cloud_array[:, 2] = np.ravel(llh[:, :, 2])
187
+ point_cloud_array[:, 3] = np.ravel(disparity)
188
+ point_cloud_array[:, 4] = np.ravel(msk)
189
+ point_cloud = pandas.DataFrame(point_cloud_array, columns=point_cloud_index)
190
+ point_cloud.attrs[cst.EPSG] = int(cst.EPSG_WSG84)
191
+ return point_cloud
192
+
193
+
194
+ def triangulate_sparse_matches( # pylint: disable=too-many-positional-arguments
195
+ sensor1,
196
+ sensor2,
197
+ geomodel1,
198
+ geomodel2,
199
+ interpolated_grid_left,
200
+ interpolated_grid_right,
201
+ matches,
202
+ geometry_plugin,
203
+ epsg,
204
+ ):
205
+ """
206
+ Triangulate matches in a metric system
207
+
208
+ :param sensor_image_right: sensor image right
209
+ :type sensor_image_right: CarsDataset
210
+ :param sensor_image_left: sensor image left
211
+ :type sensor_image_left: CarsDataset
212
+ :param grid_left: grid left
213
+ :type grid_left: CarsDataset CarsDataset
214
+ :param grid_right: corrected grid right
215
+ :type grid_right: CarsDataset
216
+ :param interpolated_grid_left: rectification grid left
217
+ :type interpolated_grid_left: shareloc.rectificationGrid
218
+ :param interpolated_grid_right: rectification grid right
219
+ :type interpolated_grid_right: shareloc.rectificationGrid
220
+ :param matches: matches
221
+ :type matches: np.ndarray
222
+ :param geometry_plugin: geometry plugin to use
223
+ :type geometry_plugin: AbstractGeometry
224
+ :param srtm_dir: srtm directory
225
+ :type srtm_dir: str
226
+ :param default_alt: default altitude
227
+ :type default_alt: float
228
+ :param pair_folder: folder used for current pair
229
+ :type pair_folder: str
230
+ :param epsg: ground epsg
231
+ :type epsg: int
232
+
233
+ :return: disp min and disp max
234
+ :rtype: float, float
235
+ """
236
+
237
+ point_cloud = triangulate_matches(
238
+ geometry_plugin,
239
+ sensor1,
240
+ sensor2,
241
+ geomodel1,
242
+ geomodel2,
243
+ interpolated_grid_left,
244
+ interpolated_grid_right,
245
+ np.ascontiguousarray(matches),
246
+ )
247
+
248
+ # Project point cloud to UTM
249
+ projection.point_cloud_conversion_dataset(point_cloud, epsg)
250
+
251
+ # Convert point cloud to pandas format to allow statistical filtering
252
+ labels = [cst.X, cst.Y, cst.Z, cst.DISPARITY, cst.POINT_CLOUD_CORR_MSK]
253
+ cloud_array = []
254
+ cloud_array.append(point_cloud[cst.X].values)
255
+ cloud_array.append(point_cloud[cst.Y].values)
256
+ cloud_array.append(point_cloud[cst.Z].values)
257
+ cloud_array.append(point_cloud[cst.DISPARITY].values)
258
+ cloud_array.append(point_cloud[cst.POINT_CLOUD_CORR_MSK].values)
259
+ pd_cloud = pandas.DataFrame(
260
+ np.transpose(np.array(cloud_array)), columns=labels
261
+ )
262
+
263
+ pd_cloud.attrs["epsg"] = epsg
264
+
265
+ return pd_cloud
266
+
267
+
268
+ def compute_point_cloud( # pylint: disable=too-many-positional-arguments
269
+ geometry_plugin,
270
+ sensor1,
271
+ sensor2,
272
+ geomodel1,
273
+ geomodel2,
274
+ grid1,
275
+ grid2,
276
+ data: xr.Dataset,
277
+ roi_key: str,
278
+ ) -> xr.Dataset:
279
+ # TODO detail a bit more what this method do
280
+ """
281
+ Compute point cloud
282
+
283
+ :param geometry_plugin: geometry plugin to use
284
+ :param sensor1: path to left sensor image
285
+ :param sensor2: path to right sensor image
286
+ :param geomodel1: path and attributes for left geomodel
287
+ :param geomodel2: path and attributes for right geomodel
288
+ :param grid1: dataset of the reference image grid file
289
+ :param grid2: dataset of the secondary image grid file
290
+ :param data: The reference to disparity map dataset
291
+ :param roi_key: roi of the disparity map key
292
+ ('roi' if cropped while calling create_disp_dataset,
293
+ otherwise 'roi_with_margins')
294
+ :return: the point cloud dataset
295
+ """
296
+ # Extract input paths from configuration
297
+ llh = geometry_plugin.triangulate(
298
+ sensor1,
299
+ sensor2,
300
+ geomodel1,
301
+ geomodel2,
302
+ cst.DISP_MODE,
303
+ data,
304
+ grid1,
305
+ grid2,
306
+ roi_key,
307
+ )
308
+
309
+ row = np.array(range(data.attrs[roi_key][1], data.attrs[roi_key][3]))
310
+ col = np.array(range(data.attrs[roi_key][0], data.attrs[roi_key][2]))
311
+
312
+ # apply no_data to X,Y and Z point cloud
313
+ nodata_index = np.where(data[cst_disp.VALID].values == 0)
314
+ llh[:, :, 0][nodata_index] = np.nan
315
+ llh[:, :, 1][nodata_index] = np.nan
316
+ llh[:, :, 2][nodata_index] = np.nan
317
+
318
+ values = {
319
+ cst.X: ([cst.ROW, cst.COL], llh[:, :, 0]), # longitudes
320
+ cst.Y: ([cst.ROW, cst.COL], llh[:, :, 1]), # latitudes
321
+ cst.Z: ([cst.ROW, cst.COL], llh[:, :, 2]),
322
+ cst.POINT_CLOUD_CORR_MSK: (
323
+ [cst.ROW, cst.COL],
324
+ data[cst_disp.VALID].values,
325
+ ),
326
+ }
327
+
328
+ # Copy all 2D attributes from disparity dataset to point cloud
329
+ # except color and pandora validity mask (already copied in corr_msk)
330
+ for key, val in data.items():
331
+ if len(val.values.shape) == 2:
332
+ if key not in (cst.EPI_TEXTURE, cst_disp.VALID):
333
+ values[key] = ([cst.ROW, cst.COL], val.values)
334
+
335
+ point_cloud = xr.Dataset(values, coords={cst.ROW: row, cst.COL: col})
336
+
337
+ # add color and data type of image
338
+ color_type = None
339
+ if cst.EPI_TEXTURE in data:
340
+ triang_wrap.add_layer(data, cst.EPI_TEXTURE, cst.BAND_IM, point_cloud)
341
+ color_type = data[cst.EPI_TEXTURE].attrs["color_type"]
342
+ elif cst.EPI_IMAGE in data:
343
+ color_type = data[cst.EPI_IMAGE].attrs["color_type"]
344
+ if color_type:
345
+ point_cloud.attrs["color_type"] = color_type
346
+
347
+ # add classif
348
+ if cst.EPI_CLASSIFICATION in data:
349
+ triang_wrap.add_layer(
350
+ data,
351
+ cst.EPI_CLASSIFICATION,
352
+ cst.BAND_CLASSIF,
353
+ point_cloud,
354
+ )
355
+
356
+ # add filling in data:
357
+ if cst.EPI_FILLING in data:
358
+ triang_wrap.add_layer(
359
+ data,
360
+ cst.EPI_FILLING,
361
+ cst.BAND_FILLING,
362
+ point_cloud,
363
+ )
364
+
365
+ point_cloud.attrs[cst.ROI] = data.attrs[cst.ROI]
366
+ point_cloud.attrs[cst.ROI_WITH_MARGINS] = data.attrs[cst.ROI_WITH_MARGINS]
367
+ point_cloud.attrs[cst.EPI_MARGINS] = data.attrs[cst.EPI_MARGINS]
368
+ point_cloud.attrs[cst.EPI_FULL_SIZE] = data.attrs[cst.EPI_FULL_SIZE]
369
+ point_cloud.attrs[cst.EPSG] = int(4326)
370
+
371
+ return point_cloud
@@ -0,0 +1,38 @@
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
+ """
22
+ this module contains the constants of triangulation.
23
+ """
24
+
25
+
26
+ # USED VARIABLES
27
+
28
+
29
+ TRIANGULATION_RUN_TAG = "triangulation"
30
+
31
+
32
+ # PARAMS
33
+ METHOD = "method"
34
+ SNAP_TO_IMG1 = "snap_to_img1"
35
+ GEOMETRY_PLUGIN = "geometry_plugin"
36
+
37
+ # INFOS
38
+ ALT_REFERENCE_TAG = "alt_reference"
@@ -0,0 +1,259 @@
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
+ """
22
+ Preprocessing module:
23
+ contains functions used for triangulation
24
+ """
25
+
26
+ import copy
27
+
28
+ # Third party imports
29
+ import logging
30
+ import os
31
+
32
+ import numpy as np
33
+ import pandas
34
+ import xarray as xr
35
+ from scipy import interpolate
36
+ from shareloc.image import Image
37
+ from shareloc.proj_utils import transform_physical_point_to_index
38
+
39
+ from cars.core import constants as cst
40
+
41
+
42
+ def add_layer(dataset, layer_name, layer_coords, point_cloud):
43
+ """
44
+ Add layer point cloud to point cloud dataset
45
+
46
+ :param dataset: input disparity map dataset
47
+ :param layer_name: layer key in disparity dataset
48
+ :param layer_coords: layer axis name in disparity dataset
49
+ :param point_cloud: output point cloud dataset
50
+ """
51
+ layers = dataset[layer_name].values
52
+ band_layer = dataset.coords[layer_coords]
53
+
54
+ if layer_coords not in point_cloud.dims:
55
+ point_cloud.coords[layer_coords] = band_layer
56
+
57
+ point_cloud[layer_name] = xr.DataArray(
58
+ layers,
59
+ dims=[layer_coords, cst.ROW, cst.COL],
60
+ )
61
+
62
+
63
+ def interpolate_geoid_height(
64
+ geoid_filename, positions, interpolation_method="linear"
65
+ ):
66
+ """
67
+ terrain to index conversion
68
+ retrieve geoid height above ellispoid
69
+ This is a modified version of the Shareloc interpolate_geoid_height
70
+ function that supports Nan positions (return Nan)
71
+
72
+ :param geoid_filename: geoid_filename
73
+ :type geoid_filename: str
74
+ :param positions: geodetic coordinates
75
+ :type positions: 2D numpy array: (number of points,[long coord, lat coord])
76
+ :param interpolation_method: default is 'linear' (interpn parameter)
77
+ :type interpolation_method: str
78
+ :return: geoid height
79
+ :rtype: 1 numpy array (number of points)
80
+ """
81
+
82
+ geoid_image = Image(geoid_filename, read_data=True)
83
+
84
+ # Check longitude overlap is not present, rounding to handle egm2008 with
85
+ # rounded pixel size
86
+ if geoid_image.nb_columns * geoid_image.pixel_size_col - 360 < 10**-8:
87
+ logging.debug("add one pixel overlap on longitudes")
88
+ geoid_image.nb_columns += 1
89
+ # Check if we can add a column
90
+ geoid_image.data = np.column_stack(
91
+ (geoid_image.data[:, :], geoid_image.data[:, 0])
92
+ )
93
+
94
+ # Prepare grid for interpolation
95
+ row_indexes = np.arange(0, geoid_image.nb_rows, 1)
96
+ col_indexes = np.arange(0, geoid_image.nb_columns, 1)
97
+ points = (row_indexes, col_indexes)
98
+
99
+ # add modulo lon/lat
100
+ min_lon = geoid_image.origin_col + geoid_image.pixel_size_col / 2
101
+ max_lon = (
102
+ geoid_image.origin_col
103
+ + geoid_image.nb_columns * geoid_image.pixel_size_col
104
+ - geoid_image.pixel_size_col / 2
105
+ )
106
+ positions[:, 0] += ((positions[:, 0] + min_lon) < 0) * 360.0
107
+ positions[:, 0] -= ((positions[:, 0] - max_lon) > 0) * 360.0
108
+ if np.any(np.abs(positions[:, 1]) > 90.0):
109
+ raise RuntimeError("Geoid cannot handle latitudes greater than 90 deg.")
110
+ indexes_geoid = transform_physical_point_to_index(
111
+ geoid_image.trans_inv, positions[:, 1], positions[:, 0]
112
+ )
113
+ return interpolate.interpn(
114
+ points,
115
+ geoid_image.data[:, :],
116
+ indexes_geoid,
117
+ bounds_error=False,
118
+ method=interpolation_method,
119
+ )
120
+
121
+
122
+ def geoid_offset(points, geoid_path):
123
+ """
124
+ Compute the point cloud height offset from geoid.
125
+
126
+ :param points: point cloud data in lat/lon/alt WGS84 (EPSG 4326)
127
+ coordinates.
128
+ :type points: xarray.Dataset or pandas.DataFrame
129
+ :param geoid_path: path to input geoid file on disk
130
+ :type geoid_path: string
131
+ :return: the same point cloud but using geoid as altimetric reference.
132
+ :rtype: xarray.Dataset or pandas.DataFrame
133
+ """
134
+
135
+ # deep copy the given point cloud that will be used as output
136
+ out_pc = points.copy(deep=True)
137
+
138
+ # interpolate data
139
+ if isinstance(out_pc, xr.Dataset):
140
+ # Convert the dataset to a np array as expected by Shareloc
141
+ pc_array = (
142
+ out_pc[[cst.X, cst.Y]]
143
+ .to_array()
144
+ .to_numpy()
145
+ .transpose((1, 2, 0))
146
+ .reshape((out_pc.sizes["row"] * out_pc.sizes["col"], 2))
147
+ )
148
+ geoid_height_array = interpolate_geoid_height(
149
+ geoid_path, pc_array
150
+ ).reshape((out_pc.sizes["row"], out_pc.sizes["col"]))
151
+ elif isinstance(out_pc, pandas.DataFrame):
152
+ geoid_height_array = interpolate_geoid_height(
153
+ geoid_path, out_pc[[cst.X, cst.Y]].to_numpy()
154
+ )
155
+ else:
156
+ raise RuntimeError("Invalid point cloud type")
157
+
158
+ # offset using geoid height
159
+ out_pc[cst.Z] -= geoid_height_array
160
+
161
+ return out_pc
162
+
163
+
164
+ # pylint: disable=too-many-positional-arguments
165
+ def generate_point_cloud_file_names(
166
+ csv_dir: str,
167
+ laz_dir: str,
168
+ row: int,
169
+ col: int,
170
+ index: dict = None,
171
+ pair_key: str = "PAIR_0",
172
+ ):
173
+ """
174
+ generate the point cloud CSV and LAZ filenames of a given tile from its
175
+ corresponding row and col. Optionally update the index, if provided.
176
+
177
+ :param csv_dir: target directory for csv files, If None no csv filenames
178
+ will be generated
179
+ :type csv_dir: str
180
+ :param laz_dir: target directory for laz files, If None no laz filenames
181
+ will be generated
182
+ :type laz_dir: str
183
+ :param row: row index of the tile
184
+ :type row: int
185
+ :param col: col index of the tile
186
+ :type col: int
187
+ :param index: product index to update with the filename
188
+ :type index: dict
189
+ :param pair_key: current product key (used in index), if a list is given
190
+ a filename will be added to the index for each element of the list
191
+ :type pair_key: str
192
+ """
193
+
194
+ file_name_root = str(col) + "_" + str(row)
195
+ csv_pc_file_name = None
196
+ if csv_dir is not None:
197
+ csv_pc_file_name = os.path.join(csv_dir, file_name_root + ".csv")
198
+
199
+ laz_pc_file_name = None
200
+ if laz_dir is not None:
201
+ laz_name = file_name_root + ".laz"
202
+ laz_pc_file_name = os.path.join(laz_dir, laz_name)
203
+ # add to index if the laz is saved to output product
204
+ if index is not None:
205
+ # index initialization, if it has not been done yet
206
+ if "point_cloud" not in index:
207
+ index["point_cloud"] = {}
208
+ # case where merging=True and save_by_pair=False
209
+ if pair_key is None:
210
+ index["point_cloud"][file_name_root] = laz_name
211
+ else:
212
+ if isinstance(pair_key, str):
213
+ pair_key = [pair_key]
214
+ for elem in pair_key:
215
+ if elem not in index["point_cloud"]:
216
+ index["point_cloud"][elem] = {}
217
+ index["point_cloud"][elem][file_name_root] = os.path.join(
218
+ elem, laz_name
219
+ )
220
+
221
+ return csv_pc_file_name, laz_pc_file_name
222
+
223
+
224
+ def compute_performance_map(
225
+ alti_ref, z_inf, z_sup, ambiguity_map=None, perf_ambiguity_threshold=None
226
+ ):
227
+ """
228
+ Compute performance map
229
+
230
+ :param alti_ref: z
231
+ :type alti_ref: xarray Dataarray
232
+ :param z_inf: z inf map
233
+ :type z_inf: xarray Dataarray
234
+ :param z_sup: z sup map
235
+ :type z_sup: xarray Dataarray
236
+ :param ambiguity_map: None or ambiguity map
237
+ :type ambiguity_map: xarray Dataarray
238
+ :param perf_ambiguity_threshold: ambiguity threshold to use
239
+ :type perf_ambiguity_threshold: None or float
240
+
241
+ """
242
+ performance_map = copy.copy(alti_ref)
243
+
244
+ performance_map_values = np.maximum(
245
+ np.abs(alti_ref.values - z_inf.values),
246
+ np.abs(z_sup.values - alti_ref.values),
247
+ )
248
+
249
+ if ambiguity_map is not None:
250
+ # ambiguity is already ambiguity, not confidence from ambiguity
251
+ ambiguity_map = ambiguity_map.values
252
+ mask_ambi = ambiguity_map > perf_ambiguity_threshold
253
+ w_ambi = ambiguity_map / perf_ambiguity_threshold
254
+ w_ambi[mask_ambi] = 1
255
+ performance_map_values *= w_ambi
256
+
257
+ performance_map.values = performance_map_values
258
+
259
+ return performance_map