cars 1.0.0rc3__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cars/__init__.py +74 -0
- cars/applications/__init__.py +40 -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 +105 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -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 +46 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +641 -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 +1461 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-313-x86_64-linux-gnu.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 +597 -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 +278 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
- cars/applications/dsm_merging/__init__.py +28 -0
- cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
- cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
- cars/applications/grid_correction/__init__.py +30 -0
- cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
- cars/applications/grid_correction/grid_correction_app.py +557 -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_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 +522 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -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 +639 -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 +760 -0
- cars/applications/resampling/resampling_algo.py +590 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sensors_subsampling/__init__.py +32 -0
- cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
- cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
- cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
- cars/applications/sparse_matching/sift_app.py +724 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -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 +750 -0
- cars/cars.py +179 -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 +1130 -0
- cars/core/geometry/shareloc_geometry.py +604 -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 +1544 -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 +250 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +381 -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 +728 -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 +986 -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/memory_tools.py +47 -0
- cars/orchestrator/orchestrator.py +755 -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 +4 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +1095 -0
- cars/pipelines/filling/__init__.py +26 -0
- cars/pipelines/filling/filling.py +981 -0
- cars/pipelines/formatting/__init__.py +26 -0
- cars/pipelines/formatting/formatting.py +190 -0
- cars/pipelines/merging/__init__.py +26 -0
- cars/pipelines/merging/merging.py +439 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +256 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
- cars/pipelines/parameters/application_parameters.py +72 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +349 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +435 -0
- cars/pipelines/parameters/sensor_inputs.py +859 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +51 -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 +38 -0
- cars/pipelines/pipeline_template.py +135 -0
- cars/pipelines/subsampling/__init__.py +26 -0
- cars/pipelines/subsampling/subsampling.py +358 -0
- cars/pipelines/surface_modeling/__init__.py +26 -0
- cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
- cars/pipelines/tie_points/__init__.py +26 -0
- cars/pipelines/tie_points/tie_points.py +536 -0
- cars/starter.py +167 -0
- cars-1.0.0rc3.dist-info/METADATA +289 -0
- cars-1.0.0rc3.dist-info/RECORD +220 -0
- cars-1.0.0rc3.dist-info/WHEEL +6 -0
- cars-1.0.0rc3.dist-info/entry_points.txt +8 -0
|
@@ -0,0 +1,599 @@
|
|
|
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 matching application class.
|
|
23
|
+
"""
|
|
24
|
+
import logging
|
|
25
|
+
import math
|
|
26
|
+
import os
|
|
27
|
+
from abc import ABCMeta, abstractmethod
|
|
28
|
+
from typing import Dict
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
import xarray as xr
|
|
32
|
+
from shareloc.geofunctions.rectification_grid import RectificationGrid
|
|
33
|
+
|
|
34
|
+
import cars.applications.sparse_matching.sparse_matching_constants as sm_cst
|
|
35
|
+
import cars.applications.sparse_matching.sparse_matching_wrappers as sm_wrapper
|
|
36
|
+
import cars.orchestrator.orchestrator as ocht
|
|
37
|
+
from cars.applications import application_constants
|
|
38
|
+
from cars.applications.application import Application
|
|
39
|
+
from cars.applications.application_template import ApplicationTemplate
|
|
40
|
+
from cars.core import constants as cst
|
|
41
|
+
from cars.core import inputs
|
|
42
|
+
from cars.core.utils import safe_makedirs
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@Application.register("sparse_matching")
|
|
46
|
+
class SparseMatching(ApplicationTemplate, metaclass=ABCMeta):
|
|
47
|
+
"""
|
|
48
|
+
SparseMatching
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
available_applications: Dict = {}
|
|
52
|
+
default_application = "sift"
|
|
53
|
+
|
|
54
|
+
def __new__(cls, conf=None): # pylint: disable=W0613
|
|
55
|
+
"""
|
|
56
|
+
Return the required application
|
|
57
|
+
:raises:
|
|
58
|
+
- KeyError when the required application is not registered
|
|
59
|
+
|
|
60
|
+
:param conf: configuration for matching
|
|
61
|
+
:return: a application_to_use object
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
matching_method = cls.default_application
|
|
65
|
+
if bool(conf) is False or "method" not in conf:
|
|
66
|
+
logging.info(
|
|
67
|
+
"Sparse Matching method not specified, default "
|
|
68
|
+
" {} is used".format(matching_method)
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
matching_method = conf.get("method", cls.default_application)
|
|
72
|
+
|
|
73
|
+
if matching_method not in cls.available_applications:
|
|
74
|
+
logging.error(
|
|
75
|
+
"No matching application named {} registered".format(
|
|
76
|
+
matching_method
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
raise KeyError(
|
|
80
|
+
"No matching application named {} registered".format(
|
|
81
|
+
matching_method
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
logging.info(
|
|
86
|
+
"The SparseMatching({}) application will be used".format(
|
|
87
|
+
matching_method
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return super(SparseMatching, cls).__new__(
|
|
92
|
+
cls.available_applications[matching_method]
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def __init_subclass__(cls, short_name, **kwargs): # pylint: disable=E0302
|
|
96
|
+
super().__init_subclass__(**kwargs)
|
|
97
|
+
for name in short_name:
|
|
98
|
+
cls.available_applications[name] = cls
|
|
99
|
+
|
|
100
|
+
def __init__(self, conf=None):
|
|
101
|
+
"""
|
|
102
|
+
Init function of SparseMatching
|
|
103
|
+
|
|
104
|
+
:param conf: configuration
|
|
105
|
+
:return: an application_to_use object
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
super().__init__(conf=conf)
|
|
109
|
+
|
|
110
|
+
@abstractmethod
|
|
111
|
+
def get_tile_margin(self):
|
|
112
|
+
"""
|
|
113
|
+
Get tile margin corresponding to sparse matches
|
|
114
|
+
|
|
115
|
+
:return: margin
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
@abstractmethod
|
|
120
|
+
def get_epipolar_error_upper_bound(self):
|
|
121
|
+
"""
|
|
122
|
+
Get epipolar error upper bound corresponding to sparse matches
|
|
123
|
+
|
|
124
|
+
:return: margin
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
@abstractmethod
|
|
129
|
+
def get_epipolar_error_maximum_bias(self):
|
|
130
|
+
"""
|
|
131
|
+
Get epipolar error lower bound corresponding to sparse matches
|
|
132
|
+
|
|
133
|
+
:return: margin
|
|
134
|
+
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
@abstractmethod
|
|
138
|
+
def get_match_filter_constant(self):
|
|
139
|
+
"""
|
|
140
|
+
Get get_match_filter_constant :
|
|
141
|
+
constant in the formula to compute threshold of outliers
|
|
142
|
+
|
|
143
|
+
:return: match_filter_constant
|
|
144
|
+
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
@abstractmethod
|
|
148
|
+
def get_match_filter_mean_factor(self):
|
|
149
|
+
"""
|
|
150
|
+
Get match_filter_mean_factor :
|
|
151
|
+
factor of mean in the formula
|
|
152
|
+
to compute threshold of outliers
|
|
153
|
+
|
|
154
|
+
:return: match_filter_mean_factor
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
@abstractmethod
|
|
159
|
+
def get_match_filter_knn(self):
|
|
160
|
+
"""
|
|
161
|
+
Get match_filter_knn :
|
|
162
|
+
number of neighboors used to measure isolation of matches
|
|
163
|
+
|
|
164
|
+
:return: match_filter_knn
|
|
165
|
+
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
@abstractmethod
|
|
169
|
+
def get_match_filter_dev_factor(self):
|
|
170
|
+
"""
|
|
171
|
+
Get match_filter_dev_factor :
|
|
172
|
+
factor of deviation in the formula
|
|
173
|
+
to compute threshold of outliers
|
|
174
|
+
|
|
175
|
+
:return: match_filter_dev_factor
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
@abstractmethod
|
|
180
|
+
def get_minimum_nb_matches(self):
|
|
181
|
+
"""
|
|
182
|
+
Get minimum_nb_matches :
|
|
183
|
+
get the minimum number of matches
|
|
184
|
+
|
|
185
|
+
:return: minimum_nb_matches
|
|
186
|
+
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
def get_margins_strip_fun(
|
|
190
|
+
self, disp_min=None, disp_max=None, method="sift"
|
|
191
|
+
):
|
|
192
|
+
"""
|
|
193
|
+
Get margins function to use in resampling
|
|
194
|
+
|
|
195
|
+
:param disp_min: disp min for info
|
|
196
|
+
:param disp_max: disp max for info
|
|
197
|
+
:param method: method for the margins
|
|
198
|
+
|
|
199
|
+
:return: margins function
|
|
200
|
+
:rtype: function generating xr.Dataset
|
|
201
|
+
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
# Compute margins
|
|
205
|
+
corner = ["left", "up", "right", "down"]
|
|
206
|
+
data = np.zeros(len(corner))
|
|
207
|
+
col = np.arange(len(corner))
|
|
208
|
+
margins = xr.Dataset(
|
|
209
|
+
{"left_margin": (["col"], data)}, coords={"col": col}
|
|
210
|
+
)
|
|
211
|
+
margins["right_margin"] = xr.DataArray(data, dims=["col"])
|
|
212
|
+
|
|
213
|
+
left_margin = self.get_tile_margin()
|
|
214
|
+
|
|
215
|
+
if method == "sift":
|
|
216
|
+
right_margin = self.get_tile_margin() + int(
|
|
217
|
+
math.floor(
|
|
218
|
+
self.get_epipolar_error_upper_bound()
|
|
219
|
+
+ self.get_epipolar_error_maximum_bias()
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
else:
|
|
223
|
+
right_margin = left_margin
|
|
224
|
+
|
|
225
|
+
# Compute margins for left region
|
|
226
|
+
margins["left_margin"].data = [0, left_margin, 0, left_margin]
|
|
227
|
+
|
|
228
|
+
# Compute margins for right region
|
|
229
|
+
margins["right_margin"].data = [0, right_margin, 0, right_margin]
|
|
230
|
+
|
|
231
|
+
# add disp range info
|
|
232
|
+
margins.attrs["disp_min"] = disp_min
|
|
233
|
+
margins.attrs["disp_max"] = disp_max
|
|
234
|
+
|
|
235
|
+
logging.info(
|
|
236
|
+
"Margins added to left region for matching: {}".format(
|
|
237
|
+
margins["left_margin"].data
|
|
238
|
+
)
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
logging.info(
|
|
242
|
+
"Margins added to right region for matching: {}".format(
|
|
243
|
+
margins["right_margin"].data
|
|
244
|
+
)
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def margins_wrapper( # pylint: disable=unused-argument
|
|
248
|
+
row_min, row_max, col_min, col_max
|
|
249
|
+
):
|
|
250
|
+
"""
|
|
251
|
+
Generates margins Dataset used in resampling
|
|
252
|
+
|
|
253
|
+
:param row_min: row min
|
|
254
|
+
:param row_max: row max
|
|
255
|
+
:param col_min: col min
|
|
256
|
+
:param col_max: col max
|
|
257
|
+
|
|
258
|
+
:return: margins
|
|
259
|
+
:rtype: xr.Dataset
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
# Constant margins for all tiles
|
|
263
|
+
return margins
|
|
264
|
+
|
|
265
|
+
return margins_wrapper
|
|
266
|
+
|
|
267
|
+
def get_margins_tile_fun(self, grid_left, disp_range_grid, method="sift"):
|
|
268
|
+
"""
|
|
269
|
+
Get Margins function that generates margins needed by
|
|
270
|
+
matching method, to use during resampling
|
|
271
|
+
|
|
272
|
+
:param grid_left: left epipolar grid
|
|
273
|
+
:type grid_left: dict
|
|
274
|
+
:param disp_range_grid: minimum and maximum disparity grid
|
|
275
|
+
:return: function that generates margin for given roi
|
|
276
|
+
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
if method == "sift":
|
|
280
|
+
right_margin = self.get_tile_margin() + int(
|
|
281
|
+
math.floor(
|
|
282
|
+
self.get_epipolar_error_upper_bound()
|
|
283
|
+
+ self.get_epipolar_error_maximum_bias()
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
else:
|
|
287
|
+
right_margin = self.get_tile_margin()
|
|
288
|
+
|
|
289
|
+
disp_min_grid_arr, _ = inputs.rasterio_read_as_array(
|
|
290
|
+
disp_range_grid["grid_min_path"]
|
|
291
|
+
)
|
|
292
|
+
disp_max_grid_arr, _ = inputs.rasterio_read_as_array(
|
|
293
|
+
disp_range_grid["grid_max_path"]
|
|
294
|
+
)
|
|
295
|
+
step_row = disp_range_grid["step_row"]
|
|
296
|
+
step_col = disp_range_grid["step_col"]
|
|
297
|
+
row_range = disp_range_grid["row_range"]
|
|
298
|
+
col_range = disp_range_grid["col_range"]
|
|
299
|
+
|
|
300
|
+
# get disp_to_alt_ratio
|
|
301
|
+
disp_to_alt_ratio = grid_left["disp_to_alt_ratio"]
|
|
302
|
+
|
|
303
|
+
# Compute global range of logging
|
|
304
|
+
disp_min_global = np.min(disp_min_grid_arr)
|
|
305
|
+
disp_max_global = np.max(disp_max_grid_arr)
|
|
306
|
+
|
|
307
|
+
logging.info(
|
|
308
|
+
"Global Disparity range for current pair: "
|
|
309
|
+
"[{:.3f} pix., {:.3f} pix.] "
|
|
310
|
+
"(or [{:.3f} m., {:.3f} m.])".format(
|
|
311
|
+
disp_min_global,
|
|
312
|
+
disp_max_global,
|
|
313
|
+
disp_min_global * disp_to_alt_ratio,
|
|
314
|
+
disp_max_global * disp_to_alt_ratio,
|
|
315
|
+
)
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
def margins_wrapper(row_min, row_max, col_min, col_max):
|
|
319
|
+
"""
|
|
320
|
+
Generates margins Dataset used in resampling
|
|
321
|
+
|
|
322
|
+
:param row_min: row min
|
|
323
|
+
:param row_max: row max
|
|
324
|
+
:param col_min: col min
|
|
325
|
+
:param col_max: col max
|
|
326
|
+
|
|
327
|
+
:return: margins
|
|
328
|
+
:rtype: xr.Dataset
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
assert row_min < row_max
|
|
332
|
+
assert col_min < col_max
|
|
333
|
+
|
|
334
|
+
# Get region in grid
|
|
335
|
+
|
|
336
|
+
grid_row_min = max(0, int(np.floor((row_min - 1) / step_row)) - 1)
|
|
337
|
+
grid_row_max = min(
|
|
338
|
+
len(row_range), int(np.ceil((row_max + 1) / step_row) + 1)
|
|
339
|
+
)
|
|
340
|
+
grid_col_min = max(0, int(np.floor((col_min - 1) / step_col)) - 1)
|
|
341
|
+
grid_col_max = min(
|
|
342
|
+
len(col_range), int(np.ceil((col_max + 1) / step_col)) + 1
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# Compute disp min and max in row
|
|
346
|
+
disp_min = np.min(
|
|
347
|
+
disp_min_grid_arr[
|
|
348
|
+
grid_row_min:grid_row_max, grid_col_min:grid_col_max
|
|
349
|
+
]
|
|
350
|
+
)
|
|
351
|
+
disp_max = np.max(
|
|
352
|
+
disp_max_grid_arr[
|
|
353
|
+
grid_row_min:grid_row_max, grid_col_min:grid_col_max
|
|
354
|
+
]
|
|
355
|
+
)
|
|
356
|
+
# round disp min and max
|
|
357
|
+
disp_min = int(math.floor(disp_min))
|
|
358
|
+
disp_max = int(math.ceil(disp_max))
|
|
359
|
+
|
|
360
|
+
# Compute margins for the correlator
|
|
361
|
+
margins = sm_wrapper.get_margins(
|
|
362
|
+
self.get_tile_margin(), right_margin, disp_min, disp_max
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
return margins
|
|
366
|
+
|
|
367
|
+
return margins_wrapper
|
|
368
|
+
|
|
369
|
+
def filter_matches( # pylint: disable=too-many-positional-arguments
|
|
370
|
+
self,
|
|
371
|
+
epipolar_matches_left,
|
|
372
|
+
grid_left,
|
|
373
|
+
grid_right,
|
|
374
|
+
geom_plugin,
|
|
375
|
+
orchestrator=None,
|
|
376
|
+
pair_key="pair_0",
|
|
377
|
+
pair_folder=None,
|
|
378
|
+
save_matches=False,
|
|
379
|
+
):
|
|
380
|
+
"""
|
|
381
|
+
Transform matches CarsDataset to numpy matches, and filters matches
|
|
382
|
+
|
|
383
|
+
:param cars_orchestrator: orchestrator
|
|
384
|
+
:param epipolar_matches_left: matches. CarsDataset contains:
|
|
385
|
+
|
|
386
|
+
- N x M Delayed tiles \
|
|
387
|
+
Each tile will be a future pandas DataFrame containing:
|
|
388
|
+
|
|
389
|
+
- data : (L, 4) shape matches
|
|
390
|
+
- attributes containing "disp_lower_bound", "disp_upper_bound", \
|
|
391
|
+
"elevation_delta_lower_bound","elevation_delta_upper_bound"
|
|
392
|
+
:type epipolar_matches_left: CarsDataset
|
|
393
|
+
:param grid_left: left epipolar grid dict
|
|
394
|
+
:type grid_left: dict
|
|
395
|
+
:param grid_right: right epipolar grid dict
|
|
396
|
+
:type grid_right: dict
|
|
397
|
+
:param save_matches: true is matches needs to be saved
|
|
398
|
+
:type save_matches: bool
|
|
399
|
+
|
|
400
|
+
:return filtered matches
|
|
401
|
+
:rtype: np.ndarray
|
|
402
|
+
|
|
403
|
+
"""
|
|
404
|
+
|
|
405
|
+
# Default orchestrator
|
|
406
|
+
if orchestrator is None:
|
|
407
|
+
# Create default sequential orchestrator for current application
|
|
408
|
+
# be awere, no out_json will be shared between orchestrators
|
|
409
|
+
# No files saved
|
|
410
|
+
cars_orchestrator = ocht.Orchestrator(
|
|
411
|
+
orchestrator_conf={"mode": "sequential"}
|
|
412
|
+
)
|
|
413
|
+
else:
|
|
414
|
+
cars_orchestrator = orchestrator
|
|
415
|
+
|
|
416
|
+
if pair_folder is None:
|
|
417
|
+
pair_folder = os.path.join(cars_orchestrator.out_dir, "tmp")
|
|
418
|
+
|
|
419
|
+
epipolar_error_upper_bound = self.get_epipolar_error_upper_bound()
|
|
420
|
+
epipolar_error_maximum_bias = self.get_epipolar_error_maximum_bias()
|
|
421
|
+
|
|
422
|
+
grid_left = RectificationGrid(
|
|
423
|
+
grid_left["path"],
|
|
424
|
+
interpolator=geom_plugin.interpolator,
|
|
425
|
+
)
|
|
426
|
+
grid_right = RectificationGrid(
|
|
427
|
+
grid_right["path"],
|
|
428
|
+
interpolator=geom_plugin.interpolator,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
# Concatenated matches
|
|
432
|
+
list_matches = []
|
|
433
|
+
for row in range(epipolar_matches_left.shape[0]):
|
|
434
|
+
for col in range(epipolar_matches_left.shape[1]):
|
|
435
|
+
# CarsDataset containing Pandas DataFrame, not Delayed anymore
|
|
436
|
+
if epipolar_matches_left[row, col] is not None:
|
|
437
|
+
epipolar_matches = epipolar_matches_left[
|
|
438
|
+
row, col
|
|
439
|
+
].to_numpy()
|
|
440
|
+
|
|
441
|
+
sensor_matches = geom_plugin.matches_to_sensor_coords(
|
|
442
|
+
grid_left,
|
|
443
|
+
grid_right,
|
|
444
|
+
epipolar_matches,
|
|
445
|
+
cst.MATCHES_MODE,
|
|
446
|
+
)
|
|
447
|
+
sensor_matches = np.concatenate(sensor_matches, axis=1)
|
|
448
|
+
matches = np.concatenate(
|
|
449
|
+
[
|
|
450
|
+
epipolar_matches,
|
|
451
|
+
sensor_matches,
|
|
452
|
+
],
|
|
453
|
+
axis=1,
|
|
454
|
+
)
|
|
455
|
+
list_matches.append(matches)
|
|
456
|
+
|
|
457
|
+
matches = np.concatenate(list_matches)
|
|
458
|
+
|
|
459
|
+
raw_nb_matches = matches.shape[0]
|
|
460
|
+
|
|
461
|
+
logging.info(
|
|
462
|
+
"Raw number of matches found: {} matches".format(raw_nb_matches)
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
# Export matches
|
|
466
|
+
raw_matches_array_path = None
|
|
467
|
+
if save_matches:
|
|
468
|
+
safe_makedirs(pair_folder)
|
|
469
|
+
|
|
470
|
+
logging.info("Writing raw matches file")
|
|
471
|
+
raw_matches_array_path = os.path.join(
|
|
472
|
+
pair_folder, "raw_matches.npy"
|
|
473
|
+
)
|
|
474
|
+
np.save(raw_matches_array_path, matches)
|
|
475
|
+
|
|
476
|
+
# Filter matches that are out of margin
|
|
477
|
+
epipolar_median_shift = np.median(matches[:, 3] - matches[:, 1])
|
|
478
|
+
|
|
479
|
+
if np.abs(epipolar_median_shift) > epipolar_error_maximum_bias:
|
|
480
|
+
epipolar_median_shift = epipolar_error_maximum_bias * np.sign(
|
|
481
|
+
epipolar_median_shift
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
matches = matches[
|
|
485
|
+
((matches[:, 3] - matches[:, 1]) - epipolar_median_shift)
|
|
486
|
+
>= -epipolar_error_upper_bound
|
|
487
|
+
]
|
|
488
|
+
matches = matches[
|
|
489
|
+
((matches[:, 3] - matches[:, 1]) - epipolar_median_shift)
|
|
490
|
+
<= epipolar_error_upper_bound
|
|
491
|
+
]
|
|
492
|
+
|
|
493
|
+
matches_discarded_message = (
|
|
494
|
+
"{} matches discarded because their epipolar error "
|
|
495
|
+
"is greater than --epipolar_error_upper_bound = {} pix"
|
|
496
|
+
).format(raw_nb_matches - matches.shape[0], epipolar_error_upper_bound)
|
|
497
|
+
|
|
498
|
+
if epipolar_error_maximum_bias != 0:
|
|
499
|
+
matches_discarded_message += (
|
|
500
|
+
" considering a shift of {} pix".format(epipolar_median_shift)
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
logging.info(matches_discarded_message)
|
|
504
|
+
|
|
505
|
+
filtered_matches_array_path = None
|
|
506
|
+
if save_matches:
|
|
507
|
+
logging.info("Writing filtered matches file")
|
|
508
|
+
filtered_matches_array_path = os.path.join(
|
|
509
|
+
pair_folder, "filtered_matches.npy"
|
|
510
|
+
)
|
|
511
|
+
np.save(filtered_matches_array_path, matches)
|
|
512
|
+
|
|
513
|
+
# Retrieve number of matches
|
|
514
|
+
nb_matches = matches.shape[0]
|
|
515
|
+
|
|
516
|
+
# Check if we have enough matches
|
|
517
|
+
# TODO: we could also make it a warning and continue
|
|
518
|
+
# with uncorrected grid
|
|
519
|
+
# and default disparity range
|
|
520
|
+
if nb_matches < self.get_minimum_nb_matches():
|
|
521
|
+
error_message_matches = (
|
|
522
|
+
"Insufficient amount of matches found ({} < {}), "
|
|
523
|
+
"can not safely estimate epipolar error correction "
|
|
524
|
+
" and disparity range".format(
|
|
525
|
+
nb_matches, self.get_minimum_nb_matches()
|
|
526
|
+
)
|
|
527
|
+
)
|
|
528
|
+
logging.warning(error_message_matches)
|
|
529
|
+
|
|
530
|
+
logging.info(
|
|
531
|
+
"Number of matches kept for epipolar "
|
|
532
|
+
"error correction: {} matches".format(nb_matches)
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
# Compute epipolar error
|
|
536
|
+
if matches.shape[0] > 0:
|
|
537
|
+
epipolar_error = matches[:, 1] - matches[:, 3]
|
|
538
|
+
epi_error_mean = np.mean(epipolar_error)
|
|
539
|
+
epi_error_std = np.std(epipolar_error)
|
|
540
|
+
epi_error_max = np.max(np.fabs(epipolar_error))
|
|
541
|
+
else:
|
|
542
|
+
epi_error_mean = 0
|
|
543
|
+
epi_error_std = 0
|
|
544
|
+
epi_error_max = 0
|
|
545
|
+
logging.info(
|
|
546
|
+
"Epipolar error before correction: mean = {:.3f} pix., "
|
|
547
|
+
"standard deviation = {:.3f} pix., max = {:.3f} pix.".format(
|
|
548
|
+
epi_error_mean,
|
|
549
|
+
epi_error_std,
|
|
550
|
+
epi_error_max,
|
|
551
|
+
)
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
# Update orchestrator out_json
|
|
555
|
+
raw_matches_infos = {
|
|
556
|
+
application_constants.APPLICATION_TAG: {
|
|
557
|
+
sm_cst.MATCH_FILTERING_TAG: {
|
|
558
|
+
pair_key: {
|
|
559
|
+
sm_cst.NUMBER_MATCHES_TAG: nb_matches,
|
|
560
|
+
sm_cst.RAW_NUMBER_MATCHES_TAG: raw_nb_matches,
|
|
561
|
+
sm_cst.BEFORE_CORRECTION_EPI_ERROR_MEAN: epi_error_mean,
|
|
562
|
+
sm_cst.BEFORE_CORRECTION_EPI_ERROR_STD: epi_error_std,
|
|
563
|
+
sm_cst.BEFORE_CORRECTION_EPI_ERROR_MAX: epi_error_max,
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
cars_orchestrator.update_out_info(raw_matches_infos)
|
|
569
|
+
|
|
570
|
+
return matches
|
|
571
|
+
|
|
572
|
+
@abstractmethod
|
|
573
|
+
def get_save_matches(self):
|
|
574
|
+
"""
|
|
575
|
+
Get save_matches parameter
|
|
576
|
+
|
|
577
|
+
:return: true is save_matches activated
|
|
578
|
+
:rtype: bool
|
|
579
|
+
"""
|
|
580
|
+
|
|
581
|
+
@abstractmethod
|
|
582
|
+
def run( # pylint: disable=too-many-positional-arguments
|
|
583
|
+
self,
|
|
584
|
+
epipolar_image_left,
|
|
585
|
+
epipolar_image_right,
|
|
586
|
+
disp_to_alt_ratio,
|
|
587
|
+
orchestrator=None,
|
|
588
|
+
pair_folder=None,
|
|
589
|
+
pair_key="PAIR_0",
|
|
590
|
+
classif_bands_to_mask=None,
|
|
591
|
+
):
|
|
592
|
+
"""
|
|
593
|
+
Run Matching application.
|
|
594
|
+
|
|
595
|
+
Create left and right CarsDataset filled with pandas.DataFrame ,
|
|
596
|
+
corresponding to epipolar 2D disparities, on the same geometry
|
|
597
|
+
that epipolar_images_left and epipolar_images_right.
|
|
598
|
+
|
|
599
|
+
"""
|