cars 1.0.0rc2__cp312-cp312-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 (225) hide show
  1. cars/__init__.py +86 -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 +42 -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.cp312-win_amd64.dll.a +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
  31. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  32. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  33. cars/applications/dense_matching/cpp/meson.build +9 -0
  34. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  35. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  36. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  37. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  38. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  39. cars/applications/dense_matching/disparity_grid_algo.py +597 -0
  40. cars/applications/dense_matching/loaders/__init__.py +23 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  46. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  47. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  48. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  49. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  50. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  51. cars/applications/dsm_filling/__init__.py +32 -0
  52. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  53. cars/applications/dsm_filling/border_interpolation_app.py +278 -0
  54. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  55. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  56. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  57. cars/applications/dsm_merging/__init__.py +28 -0
  58. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  59. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  60. cars/applications/grid_correction/__init__.py +30 -0
  61. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  62. cars/applications/grid_correction/grid_correction_app.py +557 -0
  63. cars/applications/grid_generation/__init__.py +30 -0
  64. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  65. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  66. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  67. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  68. cars/applications/grid_generation/transform_grid.py +88 -0
  69. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  70. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  71. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  72. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  73. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  74. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  76. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  77. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  78. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  79. cars/applications/rasterization/__init__.py +30 -0
  80. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  81. cars/applications/rasterization/rasterization_algo.py +534 -0
  82. cars/applications/rasterization/rasterization_constants.py +38 -0
  83. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  84. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  85. cars/applications/resampling/__init__.py +28 -0
  86. cars/applications/resampling/abstract_resampling_app.py +187 -0
  87. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  88. cars/applications/resampling/resampling_algo.py +590 -0
  89. cars/applications/resampling/resampling_constants.py +36 -0
  90. cars/applications/resampling/resampling_wrappers.py +309 -0
  91. cars/applications/sensors_subsampling/__init__.py +32 -0
  92. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  93. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  94. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  95. cars/applications/sparse_matching/__init__.py +30 -0
  96. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  97. cars/applications/sparse_matching/sift_app.py +724 -0
  98. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  99. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  100. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  101. cars/applications/triangulation/__init__.py +32 -0
  102. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  103. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  104. cars/applications/triangulation/pc_transform.py +552 -0
  105. cars/applications/triangulation/triangulation_algo.py +371 -0
  106. cars/applications/triangulation/triangulation_constants.py +38 -0
  107. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  108. cars/bundleadjustment.py +750 -0
  109. cars/cars.py +179 -0
  110. cars/conf/__init__.py +23 -0
  111. cars/conf/geoid/egm96.grd +0 -0
  112. cars/conf/geoid/egm96.grd.hdr +15 -0
  113. cars/conf/input_parameters.py +156 -0
  114. cars/conf/mask_cst.py +35 -0
  115. cars/core/__init__.py +23 -0
  116. cars/core/cars_logging.py +402 -0
  117. cars/core/constants.py +191 -0
  118. cars/core/constants_disparity.py +50 -0
  119. cars/core/datasets.py +140 -0
  120. cars/core/geometry/__init__.py +27 -0
  121. cars/core/geometry/abstract_geometry.py +1119 -0
  122. cars/core/geometry/shareloc_geometry.py +598 -0
  123. cars/core/inputs.py +568 -0
  124. cars/core/outputs.py +176 -0
  125. cars/core/preprocessing.py +722 -0
  126. cars/core/projection.py +843 -0
  127. cars/core/roi_tools.py +215 -0
  128. cars/core/tiling.py +774 -0
  129. cars/core/utils.py +164 -0
  130. cars/data_structures/__init__.py +23 -0
  131. cars/data_structures/cars_dataset.py +1544 -0
  132. cars/data_structures/cars_dict.py +74 -0
  133. cars/data_structures/corresponding_tiles_tools.py +186 -0
  134. cars/data_structures/dataframe_converter.py +185 -0
  135. cars/data_structures/format_transformation.py +297 -0
  136. cars/devibrate.py +689 -0
  137. cars/extractroi.py +264 -0
  138. cars/orchestrator/__init__.py +23 -0
  139. cars/orchestrator/achievement_tracker.py +125 -0
  140. cars/orchestrator/cluster/__init__.py +37 -0
  141. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  142. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  143. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  144. cars/orchestrator/cluster/dask_config/README.md +94 -0
  145. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  146. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  147. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  152. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  153. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  154. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  155. cars/orchestrator/cluster/log_wrapper.py +728 -0
  156. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  160. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  162. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  163. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  164. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  165. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  166. cars/orchestrator/memory_tools.py +47 -0
  167. cars/orchestrator/orchestrator.py +755 -0
  168. cars/orchestrator/orchestrator_constants.py +29 -0
  169. cars/orchestrator/registry/__init__.py +23 -0
  170. cars/orchestrator/registry/abstract_registry.py +143 -0
  171. cars/orchestrator/registry/compute_registry.py +106 -0
  172. cars/orchestrator/registry/id_generator.py +116 -0
  173. cars/orchestrator/registry/replacer_registry.py +213 -0
  174. cars/orchestrator/registry/saver_registry.py +363 -0
  175. cars/orchestrator/registry/unseen_registry.py +118 -0
  176. cars/orchestrator/tiles_profiler.py +279 -0
  177. cars/pipelines/__init__.py +26 -0
  178. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  179. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  180. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  181. cars/pipelines/default/__init__.py +26 -0
  182. cars/pipelines/default/default_pipeline.py +1088 -0
  183. cars/pipelines/filling/__init__.py +26 -0
  184. cars/pipelines/filling/filling.py +981 -0
  185. cars/pipelines/formatting/__init__.py +26 -0
  186. cars/pipelines/formatting/formatting.py +186 -0
  187. cars/pipelines/merging/__init__.py +26 -0
  188. cars/pipelines/merging/merging.py +439 -0
  189. cars/pipelines/parameters/__init__.py +0 -0
  190. cars/pipelines/parameters/advanced_parameters.py +256 -0
  191. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  192. cars/pipelines/parameters/application_parameters.py +72 -0
  193. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  194. cars/pipelines/parameters/dsm_inputs.py +349 -0
  195. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  196. cars/pipelines/parameters/output_constants.py +52 -0
  197. cars/pipelines/parameters/output_parameters.py +438 -0
  198. cars/pipelines/parameters/sensor_inputs.py +859 -0
  199. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  200. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  202. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  204. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  206. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  207. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  208. cars/pipelines/pipeline.py +119 -0
  209. cars/pipelines/pipeline_constants.py +38 -0
  210. cars/pipelines/pipeline_template.py +135 -0
  211. cars/pipelines/subsampling/__init__.py +26 -0
  212. cars/pipelines/subsampling/subsampling.py +358 -0
  213. cars/pipelines/surface_modeling/__init__.py +26 -0
  214. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  215. cars/pipelines/tie_points/__init__.py +26 -0
  216. cars/pipelines/tie_points/tie_points.py +536 -0
  217. cars/starter.py +167 -0
  218. cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
  219. cars-1.0.0rc2.dist-info/METADATA +289 -0
  220. cars-1.0.0rc2.dist-info/RECORD +225 -0
  221. cars-1.0.0rc2.dist-info/WHEEL +4 -0
  222. cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
  223. cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
  224. cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
  225. cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2024 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 abstract direct_localization application class.
23
+ """
24
+ import numpy as np
25
+ import rasterio as rio
26
+ from rasterio.windows import Window
27
+ from scipy.interpolate import interpn
28
+ from shareloc.proj_utils import transform_physical_point_to_index
29
+
30
+ from cars.core import inputs
31
+ from cars.core.projection import point_cloud_conversion
32
+ from cars.pipelines.parameters import sensor_inputs_constants as sens_cst
33
+
34
+
35
+ def get_ground_truth( # pylint: disable=too-many-positional-arguments
36
+ geom_plugin,
37
+ grid,
38
+ sensor,
39
+ disp_to_alt_ratio,
40
+ target,
41
+ window,
42
+ geom_plugin_dem_median=None,
43
+ reverse=False,
44
+ ):
45
+ """
46
+ Computes ground truth in epipolar and sensor geometry.
47
+
48
+ :param geom_plugin_dem_median: path to initial dem
49
+ :type geom_plugin_dem_median: str
50
+ :param geom_plugin: Geometry plugin with user's DSM used to
51
+ generate epipolar grids.
52
+ :type geom_plugin: GeometryPlugin
53
+ :param grid: Grid left.
54
+ :type grid: CarsDataset
55
+ :param sensor: sensor data
56
+ Dict must contain keys: "image", "texture", "geomodel",
57
+ "no_data", "mask". Paths must be absolute.
58
+ :type sensor: dict
59
+ :param disp_to_alt_ratio: Disp to altitude ratio used for performance map.
60
+ :type disp_to_alt_ratio: float
61
+ :param target: sensor, epipolar or both outputs geometry
62
+ :type target: str
63
+ :param window: size of tile
64
+ :type window: np.ndarray
65
+ :param geom_plugin_dem_median: Geometry plugin with dem median
66
+ :type geom_plugin_dem_median: geometry_plugin
67
+ :param reverse: true if right-> left
68
+ :type reverse: bool
69
+ """
70
+
71
+ sensor_data_im = sensor[sens_cst.INPUT_IMG]["bands"]["b0"]["path"]
72
+ geomodel = sensor[sens_cst.INPUT_GEO_MODEL]
73
+
74
+ rows = np.arange(window[0], window[1])
75
+ cols = np.arange(window[2], window[3])
76
+
77
+ (positions_col, positions_row) = np.meshgrid(cols, rows)
78
+
79
+ direct_loc = None
80
+ if target == "epipolar":
81
+
82
+ positions = np.stack([positions_col, positions_row], axis=2)
83
+ sensor_positions = geom_plugin.sensor_position_from_grid(
84
+ grid,
85
+ np.reshape(
86
+ positions,
87
+ (
88
+ positions.shape[0] * positions.shape[1],
89
+ 2,
90
+ ),
91
+ ),
92
+ )
93
+
94
+ transform = inputs.rasterio_get_transform(sensor_data_im)
95
+ row, col = transform_physical_point_to_index(
96
+ ~transform, sensor_positions[:, 1], sensor_positions[:, 0]
97
+ )
98
+
99
+ _, _, alt = geom_plugin.direct_loc(
100
+ sensor_data_im,
101
+ geomodel,
102
+ col,
103
+ row,
104
+ )
105
+
106
+ alt = np.reshape(alt, (rows.shape[0], cols.shape[0]))
107
+
108
+ lat, lon, alt_ref = geom_plugin_dem_median.direct_loc(
109
+ sensor_data_im,
110
+ geomodel,
111
+ col,
112
+ row,
113
+ )
114
+
115
+ alt_ref = np.reshape(alt_ref, (rows.shape[0], cols.shape[0]))
116
+
117
+ ground_truth = -(alt - alt_ref) / disp_to_alt_ratio
118
+ if reverse:
119
+ ground_truth *= -1
120
+
121
+ direct_loc = np.column_stack((lon, lat, np.ravel(ground_truth)))
122
+
123
+ if target == "sensor":
124
+
125
+ lat, lon, alt = geom_plugin.direct_loc(
126
+ sensor_data_im,
127
+ geomodel,
128
+ positions_col.ravel(),
129
+ positions_row.ravel(),
130
+ )
131
+
132
+ ground_truth = np.reshape(alt, (rows.shape[0], cols.shape[0]))
133
+ direct_loc = np.column_stack((lon, lat, alt))
134
+
135
+ return ground_truth, direct_loc
136
+
137
+
138
+ def resample_auxiliary_values(
139
+ ground_position,
140
+ auxiliary_input,
141
+ window,
142
+ interpolation_method="nearest",
143
+ keep_band=False,
144
+ ):
145
+ """
146
+ Resample classification map in epipolar geometry
147
+
148
+ :param ground_position: Direct localization result (lon, lat, alt)
149
+ :type ground_position: 2D np.darray
150
+ :param auxiliary_input: Path to auxiliary_value
151
+ :type auxiliary_input: string
152
+ :param window: the tile window
153
+ :type window: list
154
+ :param interpolation_method: interpolation method
155
+ :type interpolation_method: string
156
+ :param keep_band: bool to see if we keep the band
157
+ :type keep_band: bool
158
+ """
159
+
160
+ # get the shape of the tile
161
+ shape = (window[1] - window[0], window[3] - window[2])
162
+
163
+ # Convert shareloc output in degree in UTM
164
+ auxiliary_epsg = inputs.rasterio_get_epsg(auxiliary_input)
165
+ utm_array = point_cloud_conversion(ground_position, 4326, auxiliary_epsg)
166
+
167
+ # Keep auxiliary input information
168
+ transform = inputs.rasterio_get_transform(auxiliary_input)
169
+ nb_bands = inputs.rasterio_get_nb_bands(auxiliary_input)
170
+ outside_interpolated_value = inputs.rasterio_get_nodata(auxiliary_input)
171
+
172
+ # Convert georef coordinates to pixel coordinates (x,y) -> (row,col)
173
+ rows_geo, cols_geo = transform_physical_point_to_index(
174
+ ~transform, utm_array[:, 1], utm_array[:, 0]
175
+ )
176
+
177
+ # Find the right window
178
+ with rio.open(auxiliary_input) as src:
179
+ width = src.width
180
+ height = src.height
181
+
182
+ # Put extreme values to nan
183
+ rows_geo[(rows_geo > height) | (rows_geo < 0)] = np.nan
184
+ cols_geo[(cols_geo > width) | (cols_geo < 0)] = np.nan
185
+
186
+ row_min, row_max = int(np.floor(np.nanmin(rows_geo))), int(
187
+ np.ceil(np.nanmax(rows_geo))
188
+ )
189
+ col_min, col_max = int(np.floor(np.nanmin(cols_geo))), int(
190
+ np.ceil(np.nanmax(cols_geo))
191
+ )
192
+
193
+ # put margin to ensure that the window englobe the coord to interp
194
+ margin = 2
195
+ row_min, row_max = max(0, row_min - margin), min(
196
+ src.height, row_max + margin
197
+ )
198
+ col_min, col_max = max(0, col_min - margin), min(
199
+ src.width, col_max + margin
200
+ )
201
+
202
+ # Construct the window and read the data
203
+ window = Window(col_min, row_min, col_max - col_min, row_max - row_min)
204
+
205
+ if keep_band:
206
+ data = src.read(window=window)
207
+ height = data.shape[1]
208
+ width = data.shape[2]
209
+ else:
210
+ data = src.read(1, window=window)
211
+ height = data.shape[0]
212
+ width = data.shape[1]
213
+
214
+ # Construct the grid that corresponds
215
+ grid_rows = np.linspace(row_min, row_max, height)
216
+ grid_cols = np.linspace(col_min, col_max, width)
217
+ grid = (grid_rows, grid_cols)
218
+
219
+ index = np.column_stack((rows_geo, cols_geo))
220
+
221
+ # Interpolation step
222
+ interpolated_points = interpolate(
223
+ grid,
224
+ data,
225
+ index,
226
+ method=interpolation_method,
227
+ fill_value=outside_interpolated_value,
228
+ )
229
+
230
+ if keep_band:
231
+ output_array = interpolated_points.reshape((nb_bands, *shape))
232
+ else:
233
+ output_array = interpolated_points.reshape(shape)
234
+
235
+ return output_array
236
+
237
+
238
+ def interpolate(points, values, positions, method="linear", fill_value=None):
239
+ """
240
+ Interpolate position
241
+
242
+ :param points: Points defining the grid
243
+ :type points: np.darray
244
+ :param values: Data
245
+ :type values: 2D np.darray, or 3D np.darray (band, row, col)
246
+ :param positions: Positions to interpolate
247
+ :type positions: np.darray
248
+ :param method: interpolation method
249
+ :type method: string : {'linear', 'nearest'}
250
+ :param fill_value: value to use for points outside of the interp domain
251
+ :type fill_value: float
252
+ :return: interpolated positions
253
+ :rtype: 1D np.darray or 2D np.darray (band, interpolated positions)
254
+ """
255
+ if len(values.shape) > 2:
256
+ interp_point = np.zeros((values.shape[0], positions.shape[0]))
257
+ for band in range(values.shape[0]):
258
+ interp_point[band, :] = interpn(
259
+ points,
260
+ values[band, :, :],
261
+ positions,
262
+ method=method,
263
+ bounds_error=False,
264
+ fill_value=fill_value,
265
+ )
266
+ else:
267
+ interp_point = interpn(
268
+ points,
269
+ values,
270
+ positions,
271
+ method=method,
272
+ bounds_error=False,
273
+ fill_value=fill_value,
274
+ )
275
+ return interp_point
@@ -0,0 +1,30 @@
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
+ CARS core cloud outlier removing module init file
23
+ """
24
+ # flake8: noqa: F401
25
+
26
+ from cars.applications.point_cloud_outlier_removal.abstract_outlier_removal_app import ( # pylint: disable=C0301
27
+ PointCloudOutlierRemoval,
28
+ )
29
+
30
+ from . import small_components_app, statistical_app
@@ -0,0 +1,385 @@
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 abstract PointsCloudOutlierRemoval application class.
23
+ """
24
+
25
+ import logging
26
+ import os
27
+ from abc import ABCMeta, abstractmethod
28
+ from typing import Dict
29
+
30
+ import numpy as np
31
+
32
+ from cars.applications import application_constants
33
+ from cars.applications.application import Application
34
+ from cars.applications.application_template import ScalingApplicationTemplate
35
+ from cars.applications.point_cloud_outlier_removal import (
36
+ outlier_removal_constants as pr_cst,
37
+ )
38
+ from cars.core import constants as cst
39
+ from cars.core.utils import safe_makedirs
40
+ from cars.data_structures import cars_dataset
41
+
42
+
43
+ @Application.register("point_cloud_outlier_removal")
44
+ class PointCloudOutlierRemoval(ScalingApplicationTemplate, metaclass=ABCMeta):
45
+ """
46
+ PointCloudOutlierRemoval
47
+ """
48
+
49
+ available_applications: Dict = {}
50
+ default_application = "statistical"
51
+
52
+ def __new__(cls, scaling_coeff, conf=None): # pylint: disable=W0613
53
+ """
54
+ Return the required application
55
+ :raises:
56
+ - KeyError when the required application is not registered
57
+
58
+ :param scaling_coeff: scaling factor for resolution
59
+ :type scaling_coeff: float
60
+ :param conf: configuration for points removal
61
+ :return: a application_to_use object
62
+ """
63
+
64
+ points_removal_method = cls.default_application
65
+ if bool(conf) is False or "method" not in conf:
66
+ logging.info(
67
+ "Points removal method not specified, "
68
+ "default {} is used".format(points_removal_method)
69
+ )
70
+ else:
71
+ points_removal_method = conf.get("method", cls.default_application)
72
+
73
+ if points_removal_method not in cls.available_applications:
74
+ logging.error(
75
+ "No Points removal application named {} registered".format(
76
+ points_removal_method
77
+ )
78
+ )
79
+ raise KeyError(
80
+ "No Points removal application named {} registered".format(
81
+ points_removal_method
82
+ )
83
+ )
84
+
85
+ logging.info(
86
+ "The PointCloudOutlierRemoval({}) application"
87
+ " will be used".format(points_removal_method)
88
+ )
89
+
90
+ return super(PointCloudOutlierRemoval, cls).__new__(
91
+ cls.available_applications[points_removal_method]
92
+ )
93
+
94
+ def __init_subclass__(cls, short_name, **kwargs): # pylint: disable=E0302
95
+ super().__init_subclass__(**kwargs)
96
+ # init orchestrator
97
+ cls.orchestrator = None
98
+ cls.available_applications[short_name] = cls
99
+
100
+ def __init__(self, scaling_coeff, conf=None):
101
+ """
102
+ Init function of PointCloudOutlierRemoval
103
+
104
+ :param scaling_coeff: scaling factor for resolution
105
+ :type scaling_coeff: float
106
+ :param conf: configuration
107
+ :return: an application_to_use object
108
+ """
109
+
110
+ super().__init__(scaling_coeff, conf=conf)
111
+
112
+ @abstractmethod
113
+ def get_on_ground_margin(self, resolution=0.5):
114
+ """
115
+ Get margins to use during point clouds fusion
116
+
117
+ :return: margin
118
+ :rtype: float
119
+
120
+ """
121
+
122
+ @abstractmethod
123
+ def get_epipolar_margin(self):
124
+ """
125
+ Get epipolar margin to use
126
+
127
+ :return: margin
128
+ :rtype: int
129
+ """
130
+
131
+ @abstractmethod
132
+ def get_method(self):
133
+ """
134
+ Get margins to use during point clouds fusion
135
+
136
+ :return: algorithm method
137
+ :rtype: string
138
+
139
+ """
140
+
141
+ @abstractmethod
142
+ def get_optimal_tile_size(
143
+ self,
144
+ max_ram_per_worker,
145
+ superposing_point_clouds=1,
146
+ point_cloud_resolution=0.5,
147
+ ):
148
+ """
149
+ Get the optimal tile size to use, depending on memory available
150
+
151
+ :param max_ram_per_worker: maximum ram available
152
+ :type max_ram_per_worker: int
153
+ :param superposing_point_clouds: number of point clouds superposing
154
+ :type superposing_point_clouds: int
155
+ :param point_cloud_resolution: resolution of point cloud
156
+ :type point_cloud_resolution: float
157
+
158
+ :return: optimal tile size in meter
159
+ :rtype: float
160
+
161
+ """
162
+
163
+ # pylint: disable=too-many-positional-arguments
164
+ def __register_epipolar_dataset__(
165
+ self,
166
+ epipolar_point_cloud,
167
+ depth_map_dir=None,
168
+ dump_dir=None,
169
+ app_name="",
170
+ pair_key="PAIR_0",
171
+ ):
172
+ """
173
+ Create dataset and registered the output in the orchestrator. the output
174
+ X, Y and Z ground coordinates will be saved in depth_map_dir if the
175
+ parameter is no None. Alternatively it will be saved to dump_dir if
176
+ save_intermediate_data is set and depth_map_dir is None.
177
+
178
+ :param epipolar_point_cloud: Merged point cloud
179
+ :type epipolar_point_cloud: CarsDataset
180
+ :param depth_map_dir: output depth map directory. If None output will be
181
+ written in dump_dir if intermediate data is requested
182
+ :type depth_map_dir: str
183
+ :param dump_dir: dump dir for output (except depth map) if intermediate
184
+ data is requested
185
+ :type dump_dir: str
186
+ :param app_name: application name for file names
187
+ :type app_name: str
188
+ :param pair_key: name of current pair for index registration
189
+ :type pair_key: str
190
+
191
+ :return: Filtered point cloud
192
+ :rtype: CarsDataset
193
+
194
+ """
195
+
196
+ # Create epipolar point cloud CarsDataset
197
+ filtered_point_cloud = cars_dataset.CarsDataset(
198
+ epipolar_point_cloud.dataset_type, name=app_name
199
+ )
200
+
201
+ filtered_point_cloud.create_empty_copy(epipolar_point_cloud)
202
+
203
+ # Update attributes to get epipolar info
204
+ filtered_point_cloud.attributes.update(epipolar_point_cloud.attributes)
205
+
206
+ if depth_map_dir or self.used_config.get(
207
+ application_constants.SAVE_INTERMEDIATE_DATA
208
+ ):
209
+ filtered_dir = (
210
+ depth_map_dir if depth_map_dir is not None else dump_dir
211
+ )
212
+ safe_makedirs(filtered_dir)
213
+ self.orchestrator.add_to_save_lists(
214
+ os.path.join(filtered_dir, "X.tif"),
215
+ cst.X,
216
+ filtered_point_cloud,
217
+ cars_ds_name="depth_map_x_filtered_" + app_name,
218
+ dtype=np.float64,
219
+ )
220
+
221
+ self.orchestrator.add_to_save_lists(
222
+ os.path.join(filtered_dir, "Y.tif"),
223
+ cst.Y,
224
+ filtered_point_cloud,
225
+ cars_ds_name="depth_map_y_filtered_" + app_name,
226
+ dtype=np.float64,
227
+ )
228
+ self.orchestrator.add_to_save_lists(
229
+ os.path.join(filtered_dir, "Z.tif"),
230
+ cst.Z,
231
+ filtered_point_cloud,
232
+ cars_ds_name="depth_map_z_filtered_" + app_name,
233
+ dtype=np.float64,
234
+ )
235
+
236
+ # update depth map index if required
237
+ if depth_map_dir:
238
+ index = {
239
+ cst.INDEX_DEPTH_MAP_X: os.path.join(pair_key, "X.tif"),
240
+ cst.INDEX_DEPTH_MAP_Y: os.path.join(pair_key, "Y.tif"),
241
+ cst.INDEX_DEPTH_MAP_Z: os.path.join(pair_key, "Z.tif"),
242
+ }
243
+ self.orchestrator.update_index({"depth_map": {pair_key: index}})
244
+
245
+ # Get saving infos in order to save tiles when they are computed
246
+ [saving_info] = self.orchestrator.get_saving_infos(
247
+ [filtered_point_cloud]
248
+ )
249
+
250
+ # Add infos to orchestrator.out_json
251
+ updating_dict = {
252
+ application_constants.APPLICATION_TAG: {
253
+ pr_cst.CLOUD_OUTLIER_REMOVAL_RUN_TAG: {app_name: {}},
254
+ }
255
+ }
256
+ self.orchestrator.update_out_info(updating_dict)
257
+
258
+ return filtered_point_cloud, saving_info
259
+
260
+ def __register_pc_dataset__(
261
+ self,
262
+ merged_point_cloud=None,
263
+ point_cloud_dir=None,
264
+ dump_dir=None,
265
+ app_name=None,
266
+ ):
267
+ """
268
+ Create dataset and registered the output in the orchestrator. The
269
+ point cloud dataset can be saved as laz using the save_laz_output
270
+ option. Alternatively, the point cloud will be saved as laz and csv
271
+ in the dump directory if the application save_intermediate data
272
+ configuration parameter is set.
273
+
274
+ :param merged_point_cloud: Merged point cloud
275
+ :type merged_point_cloud: CarsDataset
276
+ :param point_cloud_dir: output depth map directory. If None output will
277
+ be written in dump_dir if intermediate data is requested
278
+ :type point_cloud_dir: str
279
+ :param dump_dir: dump dir for output (except depth map) if intermediate
280
+ data is requested
281
+ :type dump_dir: str
282
+ :param app_name: application name for file names
283
+ :type app_name: str
284
+
285
+ :return: Filtered point cloud
286
+ :rtype: CarsDataset
287
+
288
+ """
289
+ if app_name is None:
290
+ app_name = ""
291
+
292
+ save_point_cloud_as_csv = self.used_config.get(
293
+ application_constants.SAVE_INTERMEDIATE_DATA, False
294
+ )
295
+ # Save laz point cloud if save_intermediate_date is activated (dump_dir)
296
+ # or if point_cloud_dir is provided (save as official product)
297
+ save_point_cloud_as_laz = (
298
+ point_cloud_dir is not None
299
+ or self.used_config.get(
300
+ application_constants.SAVE_INTERMEDIATE_DATA, False
301
+ )
302
+ )
303
+
304
+ # Create CarsDataset
305
+ filtered_point_cloud = cars_dataset.CarsDataset(
306
+ "points", name="point_cloud_removal_" + app_name
307
+ )
308
+
309
+ # Get tiling grid
310
+ filtered_point_cloud.create_empty_copy(merged_point_cloud)
311
+ filtered_point_cloud.attributes = merged_point_cloud.attributes.copy()
312
+
313
+ laz_pc_dir_name = None
314
+ if save_point_cloud_as_laz:
315
+ if point_cloud_dir is not None:
316
+ laz_pc_dir_name = point_cloud_dir
317
+ else:
318
+ laz_pc_dir_name = os.path.join(dump_dir, "laz")
319
+ safe_makedirs(laz_pc_dir_name)
320
+ self.orchestrator.add_to_compute_lists(
321
+ filtered_point_cloud,
322
+ cars_ds_name="filtered_point_cloud_laz_" + app_name,
323
+ )
324
+ csv_pc_dir_name = None
325
+ if save_point_cloud_as_csv:
326
+ csv_pc_dir_name = os.path.join(dump_dir, "csv")
327
+ safe_makedirs(csv_pc_dir_name)
328
+ self.orchestrator.add_to_compute_lists(
329
+ filtered_point_cloud,
330
+ cars_ds_name="filtered_point_cloud_csv_" + app_name,
331
+ )
332
+
333
+ # Get saving infos in order to save tiles when they are computed
334
+ [saving_info] = self.orchestrator.get_saving_infos(
335
+ [filtered_point_cloud]
336
+ )
337
+
338
+ # Add infos to orchestrator.out_json
339
+ updating_dict = {
340
+ application_constants.APPLICATION_TAG: {
341
+ pr_cst.CLOUD_OUTLIER_REMOVAL_RUN_TAG: {},
342
+ }
343
+ }
344
+ self.orchestrator.update_out_info(updating_dict)
345
+
346
+ return (
347
+ filtered_point_cloud,
348
+ laz_pc_dir_name,
349
+ csv_pc_dir_name,
350
+ saving_info,
351
+ )
352
+
353
+ @abstractmethod
354
+ def run( # pylint: disable=too-many-positional-arguments
355
+ self,
356
+ merged_point_cloud,
357
+ orchestrator=None,
358
+ save_laz_output=False,
359
+ depth_map_dir=None,
360
+ point_cloud_dir=None,
361
+ dump_dir=None,
362
+ epsg=None,
363
+ ):
364
+ """
365
+ Run PointCloudOutlierRemoval application.
366
+
367
+ Creates a CarsDataset filled with new point cloud tiles.
368
+
369
+ :param merged_point_cloud: merged point cloud
370
+ :type merged_point_cloud: CarsDataset filled with pandas.DataFrame
371
+ :param orchestrator: orchestrator used
372
+ :param save_laz_output: save output point cloud as laz
373
+ :type save_laz_output: bool
374
+ :param output_dir: output depth map directory. If None output will be
375
+ written in dump_dir if intermediate data is requested
376
+ :type output_dir: str
377
+ :param dump_dir: dump dir for output (except depth map) if intermediate
378
+ data is requested
379
+ :type dump_dir: str
380
+ :param epsg: cartographic reference for the point cloud (array input)
381
+ :type epsg: int
382
+
383
+ :return: filtered merged point cloud
384
+ :rtype: CarsDataset filled with xr.Dataset
385
+ """