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.
- cars/__init__.py +74 -0
- cars/applications/__init__.py +37 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +104 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +655 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1460 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-313-i386-linux-musl.so +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +588 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +270 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_correction_app.py +496 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +634 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +762 -0
- cars/applications/resampling/resampling_algo.py +614 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
- cars/applications/sparse_matching/sift_app.py +735 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +757 -0
- cars/cars.py +177 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +1119 -0
- cars/core/geometry/shareloc_geometry.py +598 -0
- cars/core/inputs.py +568 -0
- cars/core/outputs.py +176 -0
- cars/core/preprocessing.py +722 -0
- cars/core/projection.py +843 -0
- cars/core/roi_tools.py +215 -0
- cars/core/tiling.py +774 -0
- cars/core/utils.py +164 -0
- cars/data_structures/__init__.py +23 -0
- cars/data_structures/cars_dataset.py +1541 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +244 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +1075 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/orchestrator.py +905 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +786 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +417 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
- cars/pipelines/parameters/application_parameters.py +71 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +918 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +454 -0
- cars/pipelines/parameters/sensor_inputs.py +842 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +31 -0
- cars/pipelines/pipeline_template.py +139 -0
- cars/pipelines/unit/__init__.py +26 -0
- cars/pipelines/unit/unit_pipeline.py +2850 -0
- cars/starter.py +167 -0
- cars-1.0.0rc1.dist-info/METADATA +292 -0
- cars-1.0.0rc1.dist-info/RECORD +202 -0
- cars-1.0.0rc1.dist-info/WHEEL +5 -0
- cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
- cars.libs/libgcc_s-1257a076.so.1 +0 -0
- 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
|