cars 1.0.0rc1__cp313-cp313-musllinux_1_2_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 (202) 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-313-i386-linux-musl.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 +202 -0
  199. cars-1.0.0rc1.dist-info/WHEEL +5 -0
  200. cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
  201. cars.libs/libgcc_s-1257a076.so.1 +0 -0
  202. cars.libs/libstdc++-0530927c.so.6.0.32 +0 -0
@@ -0,0 +1,360 @@
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
+ # pylint: disable=too-many-lines
21
+
22
+ """
23
+ Sparse matching Sift module:
24
+ contains sift sparse matching method
25
+ """
26
+
27
+ # Standard imports
28
+ from __future__ import absolute_import
29
+
30
+ # Third party imports
31
+ import numpy as np
32
+ from vlsift.sift.sift import sift
33
+
34
+ # CARS imports
35
+ from cars.applications.sparse_matching.sparse_matching_wrappers import (
36
+ euclidean_matrix_distance,
37
+ )
38
+ from cars.core import constants as cst
39
+
40
+
41
+ def compute_matches( # pylint: disable=too-many-positional-arguments
42
+ left: np.ndarray,
43
+ right: np.ndarray,
44
+ left_mask: np.ndarray = None,
45
+ right_mask: np.ndarray = None,
46
+ left_origin: [float, float] = None,
47
+ right_origin: [float, float] = None,
48
+ matching_threshold: float = 0.7,
49
+ n_octave: int = 8,
50
+ n_scale_per_octave: int = 3,
51
+ peak_threshold: float = 4.0,
52
+ edge_threshold: float = 10.0,
53
+ magnification: float = 7.0,
54
+ window_size: int = 2,
55
+ backmatching: bool = True,
56
+ disp_lower_bound=None,
57
+ disp_upper_bound=None,
58
+ ):
59
+ """
60
+ Compute matches between left and right
61
+ Convention for masks: True is a valid pixel
62
+
63
+ :param left: left image as numpy array
64
+ :type left: np.ndarray
65
+ :param right: right image as numpy array
66
+ :type right: np.ndarray
67
+ :param left_mask: left mask as numpy array
68
+ :type left_mask: np.ndarray
69
+ :param right_mask: right mask as numpy array
70
+ :type right_mask: np.ndarray
71
+ :param left_origin: left image origin in the full image
72
+ :type left_origin: [float, float]
73
+ :param right_origin: right image origin in the full image
74
+ :type right_origin: [float, float]
75
+ :param matching_threshold: threshold for the ratio to nearest second match
76
+ :type matching_threshold: float
77
+ :param n_octave: the number of octaves of the DoG scale space
78
+ :type n_octave: int
79
+ :param n_scale_per_octave: the nb of levels / octave of the DoG scale space
80
+ :type n_scale_per_octave: int
81
+ :param peak_threshold: the peak selection threshold
82
+ :type peak_threshold: float
83
+ :param edge_threshold: the edge selection threshold
84
+ :type edge_threshold: float
85
+ :param magnification: set the descriptor magnification factor
86
+ :type magnification: float
87
+ :param window_size: size of the window
88
+ :type window_size: int
89
+ :param backmatching: also check that right vs. left gives same match
90
+ :type backmatching: bool
91
+
92
+ :return: matches
93
+ :rtype: numpy buffer of shape (nb_matches,4)
94
+
95
+ """
96
+ left_origin = [0, 0] if left_origin is None else left_origin
97
+ right_origin = [0, 0] if right_origin is None else right_origin
98
+
99
+ # compute keypoints + descriptors
100
+ left_frames, left_descr = sift(
101
+ left,
102
+ n_octaves=n_octave,
103
+ n_levels=n_scale_per_octave,
104
+ first_octave=-1,
105
+ peak_thresh=peak_threshold,
106
+ edge_thresh=edge_threshold,
107
+ magnification=magnification,
108
+ window_size=window_size,
109
+ float_descriptors=True,
110
+ compute_descriptor=True,
111
+ verbose=False,
112
+ )
113
+
114
+ right_frames, right_descr = sift(
115
+ right,
116
+ n_octaves=n_octave,
117
+ n_levels=n_scale_per_octave,
118
+ first_octave=-1,
119
+ peak_thresh=peak_threshold,
120
+ edge_thresh=edge_threshold,
121
+ magnification=magnification,
122
+ window_size=window_size,
123
+ float_descriptors=True,
124
+ compute_descriptor=True,
125
+ verbose=False,
126
+ )
127
+
128
+ # Filter keypoints that falls out of the validity mask (0=valid)
129
+ if left_mask is not None:
130
+ pixel_indices = np.floor(left_frames[:, 0:2]).astype(int)
131
+ valid_left_frames_mask = left_mask[
132
+ pixel_indices[:, 0], pixel_indices[:, 1]
133
+ ]
134
+ left_frames = left_frames[valid_left_frames_mask]
135
+ left_descr = left_descr[valid_left_frames_mask]
136
+
137
+ if right_mask is not None:
138
+ pixel_indices = np.floor(right_frames[:, 0:2]).astype(int)
139
+ valid_right_frames_mask = right_mask[
140
+ pixel_indices[:, 0], pixel_indices[:, 1]
141
+ ]
142
+ right_frames = right_frames[valid_right_frames_mask]
143
+ right_descr = right_descr[valid_right_frames_mask]
144
+
145
+ # Early return for empty frames
146
+ # also if there are points to match
147
+ # need minimum two right points to find the second nearest neighbor
148
+ # (and two left points for backmatching)
149
+ if left_frames.shape[0] < 2 or right_frames.shape[0] < 2:
150
+ return np.empty((0, 4))
151
+
152
+ # translate matches according image origin
153
+ # revert origin due to frame convention: [Y, X, S, TH] X: 1, Y: 0)
154
+ left_frames[:, 0:2] += left_origin[::-1]
155
+ right_frames[:, 0:2] += right_origin[::-1]
156
+
157
+ # sort frames (and descriptors) along X axis
158
+ order = np.argsort(left_frames[:, 1])
159
+ left_frames = left_frames[order]
160
+ left_descr = left_descr[order]
161
+
162
+ order = np.argsort(right_frames[:, 1])
163
+ right_frames = right_frames[order]
164
+ right_descr = right_descr[order]
165
+
166
+ # compute best matches by blocks
167
+ splits = np.arange(500, len(left_frames), 500)
168
+ left_frames_splitted = np.split(left_frames, splits)
169
+ left_descr_splitted = np.split(left_descr, splits)
170
+ splits = np.insert(splits, 0, 0)
171
+
172
+ matches_id = []
173
+
174
+ for (
175
+ left_id_offset,
176
+ left_frames_block,
177
+ left_descr_block,
178
+ ) in zip( # noqa: B905
179
+ splits, left_frames_splitted, left_descr_splitted
180
+ ):
181
+ if disp_lower_bound is not None and disp_upper_bound is not None:
182
+ # Find right block extremas
183
+ right_x_min = np.min(left_frames_block[:, 1]) + disp_lower_bound
184
+ right_x_max = np.max(left_frames_block[:, 1]) + disp_upper_bound
185
+ if (
186
+ np.max(right_frames[:, 1]) > right_x_min
187
+ and np.min(right_frames[:, 1]) < right_x_max
188
+ ):
189
+ left_id = np.min(np.where(right_frames[:, 1] > right_x_min))
190
+ right_id = np.max(np.where(right_frames[:, 1] < right_x_max))
191
+ right_descr_block = right_descr[left_id:right_id]
192
+ right_id_offset = left_id
193
+ else:
194
+ right_descr_block = []
195
+ right_id_offset = 0
196
+ else:
197
+ right_descr_block = right_descr
198
+ right_id_offset = 0
199
+
200
+ if len(left_descr_block) >= 2 and len(right_descr_block) >= 2:
201
+ # compute euclidean matrix distance
202
+ emd = euclidean_matrix_distance(left_descr_block, right_descr_block)
203
+
204
+ # get nearest sift (regarding descriptors)
205
+ id_nearest_dlr = (
206
+ np.arange(np.shape(emd)[0]),
207
+ np.nanargmin(emd, axis=1),
208
+ )
209
+ id_nearest_drl = (
210
+ np.nanargmin(emd, axis=0),
211
+ np.arange(np.shape(emd)[1]),
212
+ )
213
+
214
+ # get absolute distances
215
+ dist_dlr = emd[id_nearest_dlr]
216
+ dist_drl = emd[id_nearest_drl]
217
+
218
+ # get relative distance (ratio to second nearest distance)
219
+ second_dist_dlr = np.partition(emd, 1, axis=1)[:, 1]
220
+ dist_dlr /= second_dist_dlr
221
+ second_dist_drl = np.partition(emd, 1, axis=0)[1, :]
222
+ dist_drl /= second_dist_drl
223
+
224
+ # stack matches which its distance
225
+ id_matches_dlr = np.column_stack((*id_nearest_dlr, dist_dlr))
226
+ id_matches_drl = np.column_stack((*id_nearest_drl, dist_drl))
227
+
228
+ # check backmatching
229
+ if backmatching is True:
230
+ back = (
231
+ id_matches_dlr[:, 0]
232
+ == id_matches_drl[id_matches_dlr[:, 1].astype(int)][:, 0]
233
+ )
234
+ id_matches_dlr = id_matches_dlr[back]
235
+
236
+ # threshold matches
237
+ id_matches_dlr = id_matches_dlr[
238
+ id_matches_dlr[:, -1] < matching_threshold, :
239
+ ][:, :-1]
240
+
241
+ id_matches_dlr += (left_id_offset, right_id_offset)
242
+
243
+ matches_id.append(id_matches_dlr)
244
+
245
+ if matches_id:
246
+ matches_id = np.concatenate(matches_id)
247
+ else:
248
+ matches_id = np.empty((0, 4))
249
+
250
+ # retrieve points: [Y, X, S, TH] X: 1, Y: 0
251
+ # fyi: ``S`` is the scale and ``TH`` is the orientation (in radians)
252
+ left_points = left_frames[matches_id[:, 0].astype(int), 1::-1]
253
+ right_points = right_frames[matches_id[:, 1].astype(int), 1::-1]
254
+ matches = np.concatenate((left_points, right_points), axis=1)
255
+ return matches
256
+
257
+
258
+ def dataset_matching( # pylint: disable=too-many-positional-arguments
259
+ ds1,
260
+ ds2,
261
+ used_band,
262
+ matching_threshold=0.7,
263
+ n_octave=8,
264
+ n_scale_per_octave=3,
265
+ peak_threshold=4.0,
266
+ edge_threshold=10.0,
267
+ magnification=7.0,
268
+ window_size=2,
269
+ backmatching=True,
270
+ disp_lower_bound=None,
271
+ disp_upper_bound=None,
272
+ classif_bands_to_mask=None,
273
+ ):
274
+ """
275
+ Compute sift matches between two datasets
276
+ produced by stereo.epipolar_rectify_images
277
+
278
+ :param ds1: Left image dataset
279
+ :type ds1: xarray.Dataset as produced by stereo.epipolar_rectify_images
280
+ :param ds2: Right image dataset
281
+ :type ds2: xarray.Dataset as produced by stereo.epipolar_rectify_images
282
+ :param matching_threshold: threshold for the ratio to nearest second match
283
+ :type matching_threshold: float
284
+ :param n_octave: the number of octaves of the DoG scale space
285
+ :type n_octave: int
286
+ :param n_scale_per_octave: the nb of levels / octave of the DoG scale space
287
+ :type n_scale_per_octave: int
288
+ :param peak_threshold: the peak selection threshold
289
+ :type peak_threshold: int
290
+ :param edge_threshold: the edge selection threshold.
291
+ :param magnification: set the descriptor magnification factor
292
+ :type magnification: float
293
+ :param window_size: size of the window
294
+ :type window_size: int
295
+ :param backmatching: also check that right vs. left gives same match
296
+ :type backmatching: bool
297
+ :param classif_bands_to_mask: bands from classif to mask
298
+ :type classif_bands_to_mask: list of str / int
299
+
300
+ :return: matches
301
+ :rtype: numpy buffer of shape (nb_matches,4)
302
+ """
303
+ # get input data from dataset
304
+ origin1 = [float(ds1.attrs["region"][0]), float(ds1.attrs["region"][1])]
305
+ origin2 = [float(ds2.attrs["region"][0]), float(ds2.attrs["region"][1])]
306
+
307
+ left = ds1.im.loc[used_band].values
308
+ right = ds2.im.loc[used_band].values
309
+ # Generate validity masks
310
+ left_mask = ds1.msk.loc[used_band].values == 0
311
+ right_mask = ds2.msk.loc[used_band].values == 0
312
+
313
+ # Update validity masks: all classes (used in filling) in
314
+ # classification should be 0
315
+ if cst.EPI_CLASSIFICATION in ds1 and classif_bands_to_mask not in (
316
+ None,
317
+ [],
318
+ ):
319
+ classif_values = (
320
+ ds1[cst.EPI_CLASSIFICATION]
321
+ .sel(band_classif=classif_bands_to_mask)
322
+ .values
323
+ )
324
+ left_mask = np.logical_and(
325
+ left_mask, ~np.any(classif_values > 0, axis=0)
326
+ )
327
+
328
+ if cst.EPI_CLASSIFICATION in ds2 and classif_bands_to_mask not in (
329
+ None,
330
+ [],
331
+ ):
332
+ classif_values = (
333
+ ds2[cst.EPI_CLASSIFICATION]
334
+ .sel(band_classif=classif_bands_to_mask)
335
+ .values
336
+ )
337
+ right_mask = np.logical_and(
338
+ right_mask, ~np.any(classif_values > 0, axis=0)
339
+ )
340
+
341
+ matches = compute_matches(
342
+ left,
343
+ right,
344
+ left_mask=left_mask,
345
+ right_mask=right_mask,
346
+ left_origin=origin1,
347
+ right_origin=origin2,
348
+ matching_threshold=matching_threshold,
349
+ n_octave=n_octave,
350
+ n_scale_per_octave=n_scale_per_octave,
351
+ peak_threshold=peak_threshold,
352
+ edge_threshold=edge_threshold,
353
+ magnification=magnification,
354
+ window_size=window_size,
355
+ backmatching=backmatching,
356
+ disp_lower_bound=disp_lower_bound,
357
+ disp_upper_bound=disp_upper_bound,
358
+ )
359
+
360
+ return matches
@@ -0,0 +1,68 @@
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 sparse matching.
23
+ """
24
+
25
+
26
+ # USED VARIABLES
27
+
28
+
29
+ SPARSE_MATCHING_RUN_TAG = "sparse_matching"
30
+
31
+
32
+ # INFOS
33
+
34
+ # Sparse matching PARAMS
35
+ DISPARITY_MARGIN_TAG = "disparity_margin"
36
+ ELEVATION_DELTA_LOWER_BOUND = "elevation_delta_lower_bound"
37
+ ELEVATION_DELTA_UPPER_BOUND = "elevation_delta_upper_bound"
38
+ EPIPOLAR_ERROR_UPPER_BOUND = "epipolar_error_upper_bound"
39
+ EPIPOLAR_ERROR_MAXIMUM_BIAS = "epipolar_error_maximum_bias"
40
+
41
+ SIFT_THRESH_HOLD = "sift_matching_threshold"
42
+ SIFT_N_OCTAVE = "sift_n_octave"
43
+ SIFT_N_SCALE_PER_OCTAVE = "sift_n_scale_per_octave"
44
+ SIFT_PEAK_THRESHOLD = "sift_peak_threshold"
45
+ SIFT_EDGE_THRESHOLD = "sift_edge_threshold"
46
+ SIFT_MAGNIFICATION = "sift_magnification"
47
+ SIFT_BACK_MATCHING = "sift_back_matching"
48
+
49
+ # Sparse matching RUN
50
+ DISP_LOWER_BOUND = "disp_lower_bound"
51
+ DISP_UPPER_BOUND = "disp_upper_bound"
52
+
53
+
54
+ # disparity range computation
55
+ DISPARITY_RANGE_COMPUTATION_TAG = "disparity_range_computation"
56
+ MINIMUM_DISPARITY_TAG = "minimum_disparity"
57
+ MAXIMUM_DISPARITY_TAG = "maximum_disparity"
58
+ MATCHES_TAG = "matches"
59
+ DISPARITY_MARGIN_PARAM_TAG = "disparity_margin_param"
60
+
61
+ # Matches filtering
62
+ METHOD = "method"
63
+ MATCH_FILTERING_TAG = "match_filtering"
64
+ NUMBER_MATCHES_TAG = "number_matches"
65
+ RAW_NUMBER_MATCHES_TAG = "raw_number_matches"
66
+ BEFORE_CORRECTION_EPI_ERROR_MEAN = "before_correction_epi_error_mean"
67
+ BEFORE_CORRECTION_EPI_ERROR_STD = "before_correction_epi_error_std"
68
+ BEFORE_CORRECTION_EPI_ERROR_MAX = "before_correction_epi_error_max"
@@ -0,0 +1,238 @@
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
+ # pylint: disable=too-many-lines
21
+
22
+ """
23
+ Sparse matching Sift module:
24
+ contains sift sparse matching method
25
+ """
26
+
27
+ # Standard imports
28
+ from __future__ import absolute_import
29
+
30
+ import logging
31
+
32
+ # Third party imports
33
+ import numpy as np
34
+ import pandas
35
+
36
+ # CARS imports
37
+ import cars.applications.sparse_matching.sparse_matching_constants as sm_cst
38
+ from cars.applications import application_constants
39
+ from cars.applications.point_cloud_outlier_removal import outlier_removal_algo
40
+ from cars.orchestrator.cluster.log_wrapper import cars_profile
41
+
42
+
43
+ def euclidean_matrix_distance(descr1: np.array, descr2: np.array):
44
+ """Compute a matrix containing cross euclidean distance
45
+ :param descr1: first keypoints descriptor
46
+ :type descr1: numpy.ndarray
47
+ :param descr2: second keypoints descriptor
48
+ :type descr2: numpy.ndarray
49
+ :return euclidean matrix distance
50
+ :rtype: float
51
+ """
52
+ sq_descr1 = np.sum(descr1**2, axis=1)[:, np.newaxis]
53
+ sq_descr2 = np.sum(descr2**2, axis=1)
54
+ dot_descr12 = np.dot(descr1, descr2.T)
55
+ return np.sqrt(sq_descr1 + sq_descr2 - 2 * dot_descr12)
56
+
57
+
58
+ def remove_epipolar_outliers(matches, percent=0.1):
59
+ # TODO used only in test functions to test compute_disparity_range
60
+ # Refactor with sparse_matching
61
+ """
62
+ This function will filter the match vector
63
+ according to a quantile of epipolar error
64
+ used for testing compute_disparity_range sparse method
65
+
66
+ :param matches: the [4,N] matches array
67
+ :type matches: numpy array
68
+ :param percent: the quantile to remove at each extrema
69
+ :type percent: float
70
+ :return: the filtered match array
71
+ :rtype: numpy array
72
+ """
73
+ epipolar_error_min = np.percentile(matches[:, 1] - matches[:, 3], percent)
74
+ epipolar_error_max = np.percentile(
75
+ matches[:, 1] - matches[:, 3], 100 - percent
76
+ )
77
+ logging.info(
78
+ "Epipolar error range after outlier rejection: [{},{}]".format(
79
+ epipolar_error_min, epipolar_error_max
80
+ )
81
+ )
82
+ out = matches[(matches[:, 1] - matches[:, 3]) < epipolar_error_max]
83
+ out = out[(out[:, 1] - out[:, 3]) > epipolar_error_min]
84
+
85
+ return out
86
+
87
+
88
+ def compute_disparity_range(matches, percent=0.1):
89
+ # TODO: Refactor with dense_matching to have only one API ?
90
+ """
91
+ This function will compute the disparity range
92
+ from matches by filtering percent outliers
93
+
94
+ :param matches: the [4,N] matches array
95
+ :type matches: numpy array
96
+ :param percent: the quantile to remove at each extrema (in %)
97
+ :type percent: float
98
+ :return: the disparity range
99
+ :rtype: float, float
100
+ """
101
+ disparity = matches[:, 2] - matches[:, 0]
102
+
103
+ mindisp = np.percentile(disparity, percent)
104
+ maxdisp = np.percentile(disparity, 100 - percent)
105
+
106
+ return mindisp, maxdisp
107
+
108
+
109
+ def compute_disp_min_disp_max(
110
+ pd_cloud,
111
+ orchestrator,
112
+ disp_margin=0.1,
113
+ pair_key=None,
114
+ disp_to_alt_ratio=None,
115
+ ):
116
+ """
117
+ Compute disp min and disp max from triangulated and filtered matches
118
+
119
+ :param pd_cloud: triangulated_matches
120
+ :type pd_cloud: pandas Dataframe
121
+ :param orchestrator: orchestrator used
122
+ :type orchestrator: Orchestrator
123
+ :param disp_margin: disparity margin
124
+ :type disp_margin: float
125
+ :param disp_to_alt_ratio: used for logging info
126
+ :type disp_to_alt_ratio: float
127
+
128
+ :return: disp min and disp max
129
+ :rtype: float, float
130
+ """
131
+
132
+ # Obtain dmin dmax
133
+ filt_disparity = np.array(pd_cloud.iloc[:, 3])
134
+ dmax = np.nanmax(filt_disparity)
135
+ dmin = np.nanmin(filt_disparity)
136
+
137
+ margin = abs(dmax - dmin) * disp_margin
138
+ dmin -= margin
139
+ dmax += margin
140
+
141
+ logging.info(
142
+ "Disparity range with margin: [{:.3f} pix., {:.3f} pix.] "
143
+ "(margin = {:.3f} pix.)".format(dmin, dmax, margin)
144
+ )
145
+
146
+ if disp_to_alt_ratio is not None:
147
+ logging.info(
148
+ "Equivalent range in meters: [{:.3f} m, {:.3f} m] "
149
+ "(margin = {:.3f} m)".format(
150
+ dmin * disp_to_alt_ratio,
151
+ dmax * disp_to_alt_ratio,
152
+ margin * disp_to_alt_ratio,
153
+ )
154
+ )
155
+
156
+ # update orchestrator_out_json
157
+ updating_infos = {
158
+ application_constants.APPLICATION_TAG: {
159
+ sm_cst.DISPARITY_RANGE_COMPUTATION_TAG: {
160
+ pair_key: {
161
+ sm_cst.DISPARITY_MARGIN_PARAM_TAG: disp_margin,
162
+ sm_cst.MINIMUM_DISPARITY_TAG: dmin,
163
+ sm_cst.MAXIMUM_DISPARITY_TAG: dmax,
164
+ }
165
+ }
166
+ }
167
+ }
168
+ orchestrator.update_out_info(updating_infos)
169
+
170
+ return dmin, dmax
171
+
172
+
173
+ @cars_profile(name="Filter_point_cloud_matches")
174
+ def filter_point_cloud_matches(
175
+ pd_cloud,
176
+ match_filter_knn=25,
177
+ match_filter_constant=0,
178
+ match_filter_mean_factor=1,
179
+ match_filter_dev_factor=3,
180
+ ):
181
+ """
182
+ Filter triangulated matches
183
+
184
+ :param pd_cloud: triangulated_matches
185
+ :type pd_cloud: pandas Dataframe
186
+ :param match_filter_knn: number of neighboors used to measure
187
+ isolation of matches
188
+ :type match_filter_knn: int
189
+ :param match_filter_dev_factor: factor of deviation in the
190
+ formula to compute threshold of outliers
191
+ :type match_filter_dev_factor: float
192
+
193
+ :return: disp min and disp max
194
+ :rtype: float, float
195
+ """
196
+
197
+ # Statistical filtering
198
+ filter_cloud, _ = outlier_removal_algo.statistical_outlier_filtering(
199
+ pd_cloud,
200
+ k=match_filter_knn,
201
+ filtering_constant=match_filter_constant,
202
+ mean_factor=match_filter_mean_factor,
203
+ dev_factor=match_filter_dev_factor,
204
+ )
205
+
206
+ # filter nans
207
+ filter_cloud.dropna(axis=0, inplace=True)
208
+
209
+ return filter_cloud
210
+
211
+
212
+ def transform_triangulated_matches_to_dataframe(triangulated_matches):
213
+ """
214
+
215
+ :param triangulated_matches: triangulated matches
216
+ :type: cars_dataset
217
+ """
218
+ # Concatenated matches
219
+ list_matches = []
220
+ attrs = None
221
+ for row in range(triangulated_matches.shape[0]):
222
+ for col in range(triangulated_matches.shape[1]):
223
+ # CarsDataset containing Pandas DataFrame, not Delayed anymore
224
+ if triangulated_matches[row, col] is not None:
225
+ epipolar_matches = triangulated_matches[row, col]
226
+
227
+ if attrs is None:
228
+ attrs = epipolar_matches.attrs
229
+
230
+ list_matches.append(epipolar_matches)
231
+
232
+ if list_matches:
233
+ triangulated_matches_df = pandas.concat(list_matches, ignore_index=True)
234
+ triangulated_matches_df.attrs = attrs
235
+ else:
236
+ raise RuntimeError("No match have been found in sparse matching")
237
+
238
+ return triangulated_matches_df
@@ -0,0 +1,32 @@
1
+ # pylint: disable=missing-module-docstring
2
+ # flake8: noqa
3
+ #
4
+ # !/usr/bin/env python
5
+ # coding: utf8
6
+ #
7
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
8
+ #
9
+ # This file is part of CARS
10
+ # (see https://github.com/CNES/cars).
11
+ #
12
+ # Licensed under the Apache License, Version 2.0 (the "License");
13
+ # you may not use this file except in compliance with the License.
14
+ # You may obtain a copy of the License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the License is distributed on an "AS IS" BASIS,
20
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ # See the License for the specific language governing permissions and
22
+ # limitations under the License.
23
+ #
24
+ """
25
+ CARS core triangulation module init file
26
+ """
27
+
28
+ from cars.applications.triangulation.abstract_triangulation_app import (
29
+ Triangulation,
30
+ )
31
+
32
+ from . import line_of_sight_intersection_app