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,722 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
Preprocessing contains function used in pipelines
|
|
23
|
+
"""
|
|
24
|
+
# pylint: disable=too-many-lines
|
|
25
|
+
|
|
26
|
+
# Standard imports
|
|
27
|
+
from __future__ import print_function
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import logging
|
|
31
|
+
import math
|
|
32
|
+
import os
|
|
33
|
+
|
|
34
|
+
import numpy as np
|
|
35
|
+
import utm
|
|
36
|
+
from pyproj import CRS
|
|
37
|
+
from shapely.geometry import Polygon
|
|
38
|
+
|
|
39
|
+
import cars.orchestrator.orchestrator as ocht
|
|
40
|
+
from cars.applications.grid_generation import grid_generation_algo as grids_algo
|
|
41
|
+
|
|
42
|
+
# CARS imports
|
|
43
|
+
from cars.core import inputs, projection, tiling
|
|
44
|
+
from cars.core.utils import safe_makedirs
|
|
45
|
+
from cars.orchestrator.cluster.log_wrapper import cars_profile
|
|
46
|
+
from cars.pipelines.parameters import sensor_inputs_constants as sens_cst
|
|
47
|
+
|
|
48
|
+
PREPROCESSING_TAG = "pair_preprocessing"
|
|
49
|
+
LEFT_ENVELOPE_TAG = "left_envelope"
|
|
50
|
+
RIGHT_ENVELOPE_TAG = "right_envelope"
|
|
51
|
+
ENVELOPES_INTERSECTION_TAG = "envelopes_intersection"
|
|
52
|
+
ENVELOPES_INTERSECTION_BB_TAG = "envelopes_intersection_bounding_box"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_utm_zone_as_epsg_code(lon, lat):
|
|
56
|
+
"""
|
|
57
|
+
Returns the EPSG code of the UTM zone where the lat, lon point falls in
|
|
58
|
+
|
|
59
|
+
:param lon: longitude of the point
|
|
60
|
+
:type lon: float
|
|
61
|
+
:param lat: latitude of the point
|
|
62
|
+
:type lat: float
|
|
63
|
+
:return: The EPSG code corresponding to the UTM zone
|
|
64
|
+
:rtype: int
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
if lon is None or lat is None or np.isnan(lon) or np.isnan(lat):
|
|
68
|
+
logging.warning(
|
|
69
|
+
"An incorrect position was given when trying "
|
|
70
|
+
"to select the right EPSG for computations. "
|
|
71
|
+
"The default EPSG 32632 will be used."
|
|
72
|
+
)
|
|
73
|
+
return 32632
|
|
74
|
+
|
|
75
|
+
if lat > 84:
|
|
76
|
+
logging.warning(
|
|
77
|
+
"Since the latitude is above 84°, the EPSG 32661 will be used."
|
|
78
|
+
)
|
|
79
|
+
return 32661
|
|
80
|
+
|
|
81
|
+
if lat < -80:
|
|
82
|
+
logging.warning(
|
|
83
|
+
"Since the latitude is under -80°, the EPSG 32761 will be used."
|
|
84
|
+
)
|
|
85
|
+
return 32761
|
|
86
|
+
|
|
87
|
+
zone = utm.from_latlon(lat, lon)[2]
|
|
88
|
+
|
|
89
|
+
north_south = 600 if lat >= 0 else 700
|
|
90
|
+
return 32000 + north_south + zone
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@cars_profile(name="Compute terrain bbox")
|
|
94
|
+
def compute_terrain_bbox( # pylint: disable=too-many-positional-arguments # noqa: 751
|
|
95
|
+
sensor_image_left,
|
|
96
|
+
sensor_image_right,
|
|
97
|
+
epipolar_image_left,
|
|
98
|
+
grid_left,
|
|
99
|
+
grid_right,
|
|
100
|
+
epsg,
|
|
101
|
+
geometry_plugin,
|
|
102
|
+
disp_min=-10,
|
|
103
|
+
disp_max=10,
|
|
104
|
+
resolution=0.5,
|
|
105
|
+
roi_poly=None,
|
|
106
|
+
pair_key="PAIR_0",
|
|
107
|
+
pair_folder=None,
|
|
108
|
+
orchestrator=None,
|
|
109
|
+
check_inputs=False,
|
|
110
|
+
):
|
|
111
|
+
"""
|
|
112
|
+
Compute terrain bounding box of current pair
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
:param srtm_dir: srtm directory
|
|
116
|
+
:type srtm_dir: str
|
|
117
|
+
:param default_alt: default altitude
|
|
118
|
+
:type default_alt: int
|
|
119
|
+
:param geoid: geoid path
|
|
120
|
+
:type geoid: str
|
|
121
|
+
:param sensor_image_left: left image
|
|
122
|
+
Dict Must contain keys : "image", "texture", "geomodel",
|
|
123
|
+
"no_data", "mask". Paths must be absolutes
|
|
124
|
+
:type sensor_image_left: dict
|
|
125
|
+
:param sensor_image_right: right image
|
|
126
|
+
Dict Must contain keys : "image", "texture", "geomodel",
|
|
127
|
+
"no_data", "mask". Paths must be absolutes
|
|
128
|
+
:type sensor_image_right: dict
|
|
129
|
+
:param grid_left: left grid. Grid dict contains :
|
|
130
|
+
- "grid_spacing", "grid_origin", \
|
|
131
|
+
"epipolar_size_x", "epipolar_size_y", \
|
|
132
|
+
"epipolar_origin_x", "epipolar_origin_y", \
|
|
133
|
+
"epipolar_spacing_x", "epipolar_spacing", \
|
|
134
|
+
"disp_to_alt_ratio", "path"
|
|
135
|
+
:type grid_left: dict
|
|
136
|
+
:param grid_right: right grid. Grid dict contains :
|
|
137
|
+
- "grid_spacing", "grid_origin",\
|
|
138
|
+
"epipolar_size_x", "epipolar_size_y", \
|
|
139
|
+
"epipolar_origin_x", "epipolar_origin_y", \
|
|
140
|
+
"epipolar_spacing_x", "epipolar_spacing", \
|
|
141
|
+
"disp_to_alt_ratio", "path"
|
|
142
|
+
:type grid_right: dict
|
|
143
|
+
:param epsg: epsg to use
|
|
144
|
+
:type epsg: str
|
|
145
|
+
:param geometry_plugin: geometry plugin to use
|
|
146
|
+
:type geometry_plugin: AbstractGeometry
|
|
147
|
+
:param disp_min: minimum disparity
|
|
148
|
+
:type disp_min: int
|
|
149
|
+
:param disp_max: maximum disparity
|
|
150
|
+
:type disp_max: int
|
|
151
|
+
:param resolution: resolution
|
|
152
|
+
:type resolution: float
|
|
153
|
+
:param roi_poly: roi polygon
|
|
154
|
+
:type roi_poly: Polygon
|
|
155
|
+
:param pair_key: pair key id
|
|
156
|
+
:type pair_key: str
|
|
157
|
+
:param pair_folder: pair folder to save data to
|
|
158
|
+
:type pair_folder: str
|
|
159
|
+
:param orchestrator: orchestrator
|
|
160
|
+
:type orchestrator: Orchestrator
|
|
161
|
+
:param check_inputs: true if user wants to check inputs
|
|
162
|
+
:type check_inputs: bool
|
|
163
|
+
|
|
164
|
+
:return: former post prepare configuration
|
|
165
|
+
:rtype: dict
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
# Default orchestrator
|
|
170
|
+
if orchestrator is None:
|
|
171
|
+
# Create default sequential orchestrator for current application
|
|
172
|
+
# be awere, no out_json will be shared between orchestrators
|
|
173
|
+
# No files saved
|
|
174
|
+
orchestrator = ocht.Orchestrator(
|
|
175
|
+
orchestrator_conf={"mode": "sequential"}
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
if pair_folder is None:
|
|
179
|
+
pair_folder = os.path.join(orchestrator.out_dir, "tmp")
|
|
180
|
+
safe_makedirs(pair_folder)
|
|
181
|
+
|
|
182
|
+
out_dir = pair_folder
|
|
183
|
+
|
|
184
|
+
# Check that the envelopes intersect one another
|
|
185
|
+
logging.info("Computing images envelopes and their intersection")
|
|
186
|
+
geojson1 = os.path.join(out_dir, "left_envelope.geojson")
|
|
187
|
+
geojson2 = os.path.join(out_dir, "right_envelope.geojson")
|
|
188
|
+
out_envelopes_intersection = os.path.join(
|
|
189
|
+
out_dir, "envelopes_intersection.geojson"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
sensor1 = sensor_image_left[sens_cst.INPUT_IMG]
|
|
193
|
+
sensor2 = sensor_image_right[sens_cst.INPUT_IMG]
|
|
194
|
+
geomodel1 = sensor_image_left[sens_cst.INPUT_GEO_MODEL]
|
|
195
|
+
geomodel2 = sensor_image_right[sens_cst.INPUT_GEO_MODEL]
|
|
196
|
+
|
|
197
|
+
inter_poly, (
|
|
198
|
+
inter_xmin,
|
|
199
|
+
inter_ymin,
|
|
200
|
+
inter_xmax,
|
|
201
|
+
inter_ymax,
|
|
202
|
+
) = projection.ground_intersection_envelopes(
|
|
203
|
+
sensor1["bands"]["b0"]["path"],
|
|
204
|
+
sensor2["bands"]["b0"]["path"],
|
|
205
|
+
geomodel1,
|
|
206
|
+
geomodel2,
|
|
207
|
+
geometry_plugin,
|
|
208
|
+
geojson1,
|
|
209
|
+
geojson2,
|
|
210
|
+
out_envelopes_intersection,
|
|
211
|
+
envelope_file_driver="GeoJSON",
|
|
212
|
+
intersect_file_driver="GeoJSON",
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
json_data_1 = None
|
|
216
|
+
json_data_2 = None
|
|
217
|
+
json_data_intersect = None
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
with open(geojson1, "r", encoding="utf-8") as file_1:
|
|
221
|
+
json_data_1 = json.load(file_1)
|
|
222
|
+
|
|
223
|
+
with open(geojson2, "r", encoding="utf-8") as file_2:
|
|
224
|
+
json_data_2 = json.load(file_2)
|
|
225
|
+
|
|
226
|
+
with open(out_envelopes_intersection, "r", encoding="utf-8") as file_3:
|
|
227
|
+
json_data_intersect = json.load(file_3)
|
|
228
|
+
except Exception as exc:
|
|
229
|
+
raise FileNotFoundError("Unable to read bbox GeoJSON files") from exc
|
|
230
|
+
|
|
231
|
+
# update out_json
|
|
232
|
+
updating_dict = {
|
|
233
|
+
PREPROCESSING_TAG: {
|
|
234
|
+
pair_key: {
|
|
235
|
+
LEFT_ENVELOPE_TAG: json_data_1,
|
|
236
|
+
RIGHT_ENVELOPE_TAG: json_data_2,
|
|
237
|
+
ENVELOPES_INTERSECTION_TAG: json_data_intersect,
|
|
238
|
+
ENVELOPES_INTERSECTION_BB_TAG: [
|
|
239
|
+
inter_xmin,
|
|
240
|
+
inter_ymin,
|
|
241
|
+
inter_xmax,
|
|
242
|
+
inter_ymax,
|
|
243
|
+
],
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
orchestrator.update_out_info(updating_dict)
|
|
249
|
+
|
|
250
|
+
if check_inputs:
|
|
251
|
+
logging.info("Checking DEM coverage")
|
|
252
|
+
_, epsg1 = inputs.read_vector(geojson1)
|
|
253
|
+
__, dem_coverage = projection.compute_dem_intersection_with_poly(
|
|
254
|
+
geometry_plugin.dem, inter_poly, epsg1
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if dem_coverage < 100.0:
|
|
258
|
+
logging.warning(
|
|
259
|
+
"The input DEM covers {}% of the useful zone".format(
|
|
260
|
+
int(dem_coverage)
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Get largest epipolar regions from configuration file
|
|
265
|
+
largest_epipolar_region = [
|
|
266
|
+
0,
|
|
267
|
+
0,
|
|
268
|
+
grid_left["epipolar_size_x"],
|
|
269
|
+
grid_left["epipolar_size_y"],
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
# Numpy array with corners of largest epipolar region.
|
|
273
|
+
# Order does not matter here,
|
|
274
|
+
# since it will be passed to grids.compute_epipolar_grid_min_max
|
|
275
|
+
corners = np.array(
|
|
276
|
+
[
|
|
277
|
+
[
|
|
278
|
+
[largest_epipolar_region[0], largest_epipolar_region[1]],
|
|
279
|
+
[largest_epipolar_region[0], largest_epipolar_region[3]],
|
|
280
|
+
],
|
|
281
|
+
[
|
|
282
|
+
[largest_epipolar_region[2], largest_epipolar_region[3]],
|
|
283
|
+
[largest_epipolar_region[2], largest_epipolar_region[1]],
|
|
284
|
+
],
|
|
285
|
+
],
|
|
286
|
+
dtype=np.float64,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# Compute terrain min and max again, this time using estimated epsg code
|
|
290
|
+
terrain_dispmin, terrain_dispmax = grids_algo.compute_epipolar_grid_min_max(
|
|
291
|
+
geometry_plugin,
|
|
292
|
+
corners,
|
|
293
|
+
sensor1,
|
|
294
|
+
sensor2,
|
|
295
|
+
geomodel1,
|
|
296
|
+
geomodel2,
|
|
297
|
+
grid_left,
|
|
298
|
+
grid_right,
|
|
299
|
+
epsg,
|
|
300
|
+
disp_min,
|
|
301
|
+
disp_max,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Compute bounds from epipolar image corners and dispmin/dispmax
|
|
305
|
+
terrain_bounds = np.stack((terrain_dispmin, terrain_dispmax), axis=0)
|
|
306
|
+
terrain_min = np.nanmin(terrain_bounds, axis=(0, 1))
|
|
307
|
+
terrain_max = np.nanmax(terrain_bounds, axis=(0, 1))
|
|
308
|
+
|
|
309
|
+
terrain_area = (terrain_max[0] - terrain_min[0]) * (
|
|
310
|
+
terrain_max[1] - terrain_min[1]
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
logging.info(
|
|
314
|
+
"Terrain area covered: {} square meters (or square degrees)".format(
|
|
315
|
+
terrain_area
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
# Retrieve bounding box of the ground intersection of the envelopes
|
|
320
|
+
inter_poly, inter_epsg = inputs.read_vector(out_envelopes_intersection)
|
|
321
|
+
|
|
322
|
+
# Project polygon if epsg is different
|
|
323
|
+
if epsg != inter_epsg:
|
|
324
|
+
inter_poly = projection.polygon_projection(inter_poly, inter_epsg, epsg)
|
|
325
|
+
|
|
326
|
+
(inter_xmin, inter_ymin, inter_xmax, inter_ymax) = inter_poly.bounds
|
|
327
|
+
|
|
328
|
+
# Align bounding box to integer resolution steps
|
|
329
|
+
xmin, ymin, xmax, ymax = tiling.snap_to_grid(
|
|
330
|
+
inter_xmin, inter_ymin, inter_xmax, inter_ymax, resolution
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
logging.info(
|
|
334
|
+
"Terrain bounding box : [{}, {}] x [{}, {}]".format(
|
|
335
|
+
xmin, xmax, ymin, ymax
|
|
336
|
+
)
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
terrain_bounding_box = [xmin, ymin, xmax, ymax]
|
|
340
|
+
|
|
341
|
+
# Check if roi given by user intersects with current terrain region
|
|
342
|
+
if roi_poly is not None:
|
|
343
|
+
if not roi_poly.intersects(inter_poly):
|
|
344
|
+
logging.warning(
|
|
345
|
+
"The pair composed of {} and {} "
|
|
346
|
+
"does not intersect the requested ROI".format(
|
|
347
|
+
sensor_image_left[sens_cst.INPUT_IMG],
|
|
348
|
+
sensor_image_right[sens_cst.INPUT_IMG],
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# Get number of epipolar tiles that are previously used
|
|
353
|
+
nb_epipolar_tiles = (
|
|
354
|
+
epipolar_image_left.shape[0] * epipolar_image_left.shape[1]
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
# Compute average epipolar tile width
|
|
358
|
+
epipolar_average_tile_width = math.sqrt(terrain_area / nb_epipolar_tiles)
|
|
359
|
+
|
|
360
|
+
return (terrain_bounding_box, epipolar_average_tile_width), inter_poly
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@cars_profile(name="Compute roi poly")
|
|
364
|
+
def compute_roi_poly(input_roi_poly, input_roi_epsg, epsg):
|
|
365
|
+
"""
|
|
366
|
+
Compute roi polygon from input roi
|
|
367
|
+
|
|
368
|
+
:param input_roi_poly: roi polygon
|
|
369
|
+
:type input_roi_poly: shapely Polygon
|
|
370
|
+
:param input_roi_epsg: epsg of roi
|
|
371
|
+
:type input_roi_epsg: str
|
|
372
|
+
:param epsg: epsg to use
|
|
373
|
+
:type epsg: str
|
|
374
|
+
|
|
375
|
+
:return: polygon of roi with right epsg
|
|
376
|
+
:rtype: Polygon
|
|
377
|
+
|
|
378
|
+
"""
|
|
379
|
+
roi_poly = input_roi_poly
|
|
380
|
+
|
|
381
|
+
if input_roi_poly is not None:
|
|
382
|
+
if input_roi_epsg != epsg:
|
|
383
|
+
roi_poly = projection.polygon_projection(
|
|
384
|
+
roi_poly, input_roi_epsg, epsg
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
return roi_poly
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
@cars_profile(name="Compute epsg")
|
|
391
|
+
def compute_epsg( # pylint: disable=too-many-positional-arguments
|
|
392
|
+
sensor_image_left,
|
|
393
|
+
sensor_image_right,
|
|
394
|
+
grid_left,
|
|
395
|
+
grid_right,
|
|
396
|
+
geometry_plugin,
|
|
397
|
+
disp_min=-10,
|
|
398
|
+
disp_max=10,
|
|
399
|
+
):
|
|
400
|
+
"""
|
|
401
|
+
Compute epsg to use
|
|
402
|
+
|
|
403
|
+
:param sensor_image_left: left image
|
|
404
|
+
Dict Must contain keys : "image", "texture", "geomodel",
|
|
405
|
+
"no_data", "mask". Paths must be absolutes
|
|
406
|
+
:type sensor_image_left: dict
|
|
407
|
+
:param sensor_image_right: right image
|
|
408
|
+
Dict Must contain keys : "image", "texture", "geomodel",
|
|
409
|
+
"no_data", "mask". Paths must be absolutes
|
|
410
|
+
:type sensor_image_right: dict
|
|
411
|
+
:param grid_left: left grid. Grid dict contains :
|
|
412
|
+
- Attributes containing: "grid_spacing", "grid_origin", \
|
|
413
|
+
"epipolar_size_x", "epipolar_size_y", \
|
|
414
|
+
"epipolar_origin_x", "epipolar_origin_y", \
|
|
415
|
+
"epipolar_spacing_x", "epipolar_spacing", \
|
|
416
|
+
"disp_to_alt_ratio", "path"
|
|
417
|
+
:type grid_left: dict
|
|
418
|
+
:param grid_right: right grid. Grid dict contains :
|
|
419
|
+
- Attributes containing: "grid_spacing", "grid_origin", \
|
|
420
|
+
"epipolar_size_x", "epipolar_size_y", \
|
|
421
|
+
"epipolar_origin_x", "epipolar_origin_y", \
|
|
422
|
+
"epipolar_spacing_x", "epipolar_spacing", \
|
|
423
|
+
"disp_to_alt_ratio", "path"
|
|
424
|
+
:type grid_right: dict
|
|
425
|
+
:param geometry_plugin: geometry plugin to use
|
|
426
|
+
:type geometry_plugin: AbstractGeometry
|
|
427
|
+
:param srtm_dir: srtm directory
|
|
428
|
+
:type srtm_dir: str
|
|
429
|
+
:param default_alt: default altitude
|
|
430
|
+
:type default_alt: int
|
|
431
|
+
:param disp_min: minimum disparity
|
|
432
|
+
:type disp_min: int
|
|
433
|
+
:param disp_max: maximum disparity
|
|
434
|
+
:type disp_max: int
|
|
435
|
+
|
|
436
|
+
:return: epsg
|
|
437
|
+
:rtype: str
|
|
438
|
+
|
|
439
|
+
"""
|
|
440
|
+
sensor1 = sensor_image_left[sens_cst.INPUT_IMG]
|
|
441
|
+
sensor2 = sensor_image_right[sens_cst.INPUT_IMG]
|
|
442
|
+
geomodel1 = sensor_image_left[sens_cst.INPUT_GEO_MODEL]
|
|
443
|
+
geomodel2 = sensor_image_right[sens_cst.INPUT_GEO_MODEL]
|
|
444
|
+
|
|
445
|
+
# Get largest epipolar regions from configuration file
|
|
446
|
+
largest_epipolar_region = [
|
|
447
|
+
0,
|
|
448
|
+
0,
|
|
449
|
+
grid_left["epipolar_size_x"],
|
|
450
|
+
grid_left["epipolar_size_y"],
|
|
451
|
+
]
|
|
452
|
+
|
|
453
|
+
# Numpy array with corners of largest epipolar region.
|
|
454
|
+
# Order does not matter here,
|
|
455
|
+
# since it will be passed to grids.compute_epipolar_grid_min_max
|
|
456
|
+
corners = np.array(
|
|
457
|
+
[
|
|
458
|
+
[
|
|
459
|
+
[largest_epipolar_region[0], largest_epipolar_region[1]],
|
|
460
|
+
[largest_epipolar_region[0], largest_epipolar_region[3]],
|
|
461
|
+
],
|
|
462
|
+
[
|
|
463
|
+
[largest_epipolar_region[2], largest_epipolar_region[3]],
|
|
464
|
+
[largest_epipolar_region[2], largest_epipolar_region[1]],
|
|
465
|
+
],
|
|
466
|
+
],
|
|
467
|
+
dtype=np.float64,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Compute epipolar image terrain position corners
|
|
471
|
+
# for min and max disparity
|
|
472
|
+
(
|
|
473
|
+
terrain_dispmin,
|
|
474
|
+
_,
|
|
475
|
+
) = grids_algo.compute_epipolar_grid_min_max(
|
|
476
|
+
geometry_plugin,
|
|
477
|
+
corners,
|
|
478
|
+
sensor1,
|
|
479
|
+
sensor2,
|
|
480
|
+
geomodel1,
|
|
481
|
+
geomodel2,
|
|
482
|
+
grid_left,
|
|
483
|
+
grid_right,
|
|
484
|
+
4326,
|
|
485
|
+
disp_min,
|
|
486
|
+
disp_max,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
epsg = get_utm_zone_as_epsg_code(*np.nanmean(terrain_dispmin, axis=0))
|
|
490
|
+
|
|
491
|
+
logging.info("EPSG code: {}".format(epsg))
|
|
492
|
+
|
|
493
|
+
return epsg
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def crop_terrain_bounds_with_roi(roi_poly, xmin, ymin, xmax, ymax):
|
|
497
|
+
"""
|
|
498
|
+
Crop current terrain bounds with roi
|
|
499
|
+
|
|
500
|
+
:param roi_poly: Polygon of ROI
|
|
501
|
+
:type roi_poly: Shapely Polygon
|
|
502
|
+
:param xmin: xmin
|
|
503
|
+
:type xmin: float
|
|
504
|
+
:param ymin: ymin
|
|
505
|
+
:type ymin: float
|
|
506
|
+
:param xmax: xmax
|
|
507
|
+
:type xmax: float
|
|
508
|
+
:param ymax: ymax
|
|
509
|
+
:type ymax: float
|
|
510
|
+
|
|
511
|
+
:return: new xmin, ymin, xmax, ymax
|
|
512
|
+
:rtype: (float, float, float, float)
|
|
513
|
+
"""
|
|
514
|
+
# terrain bounding box polygon
|
|
515
|
+
terrain_poly = Polygon(
|
|
516
|
+
[
|
|
517
|
+
(xmin, ymin),
|
|
518
|
+
(xmax, ymin),
|
|
519
|
+
(xmax, ymax),
|
|
520
|
+
(xmin, ymax),
|
|
521
|
+
(xmin, ymin),
|
|
522
|
+
]
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
if not roi_poly.intersects(terrain_poly):
|
|
526
|
+
raise RuntimeError("None of the input data intersect the requested ROI")
|
|
527
|
+
# Show ROI if valid (no exception raised) :
|
|
528
|
+
logging.info("Setting terrain bounding box to the requested ROI")
|
|
529
|
+
new_xmin, new_ymin, new_xmax, new_ymax = roi_poly.bounds
|
|
530
|
+
|
|
531
|
+
return new_xmin, new_ymin, new_xmax, new_ymax
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
@cars_profile(name="Compute terrain bounds")
|
|
535
|
+
def compute_terrain_bounds(list_of_terrain_roi, roi_poly=None, resolution=0.5):
|
|
536
|
+
"""
|
|
537
|
+
Compute Terrain bounds of merged pairs
|
|
538
|
+
|
|
539
|
+
:param list_of_terrain_roi: list of terrain roi
|
|
540
|
+
list of (terrain bbox, terrain epi_tile_size)
|
|
541
|
+
:type list_of_terrain_roi: list
|
|
542
|
+
:param roi_poly: terrain roi of given roi
|
|
543
|
+
:type roi_poly: Polygon
|
|
544
|
+
:param resolution: list of terrain roi
|
|
545
|
+
:type resolution: float
|
|
546
|
+
|
|
547
|
+
:return: bounds, optimal_terrain_tile_width_average
|
|
548
|
+
|
|
549
|
+
"""
|
|
550
|
+
|
|
551
|
+
# get lists
|
|
552
|
+
(
|
|
553
|
+
list_terrain_bounding_box,
|
|
554
|
+
list_terrain_epi_tile_width,
|
|
555
|
+
) = zip( # noqa: B905
|
|
556
|
+
*list_of_terrain_roi
|
|
557
|
+
)
|
|
558
|
+
list_terrain_bounding_box = list(list_terrain_bounding_box)
|
|
559
|
+
list_terrain_epi_tile_width = list(list_terrain_epi_tile_width)
|
|
560
|
+
|
|
561
|
+
xmin, ymin, xmax, ymax = tiling.union(list_terrain_bounding_box)
|
|
562
|
+
|
|
563
|
+
if roi_poly is not None:
|
|
564
|
+
(xmin, ymin, xmax, ymax) = crop_terrain_bounds_with_roi(
|
|
565
|
+
roi_poly, xmin, ymin, xmax, ymax
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
xmin, ymin, xmax, ymax = tiling.snap_to_grid(
|
|
569
|
+
xmin, ymin, xmax, ymax, resolution
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
logging.info(
|
|
573
|
+
"Total terrain bounding box : [{}, {}] x [{}, {}]".format(
|
|
574
|
+
xmin, xmax, ymin, ymax
|
|
575
|
+
)
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
bounds = [xmin, ymin, xmax, ymax]
|
|
579
|
+
|
|
580
|
+
# Compute optimal terrain tile width
|
|
581
|
+
optimal_terrain_tile_width_average = np.nanmean(list_terrain_epi_tile_width)
|
|
582
|
+
|
|
583
|
+
optimal_terrain_tile_width = (
|
|
584
|
+
int(math.ceil(optimal_terrain_tile_width_average / resolution))
|
|
585
|
+
* resolution
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
logging.info(
|
|
589
|
+
"Optimal terrain tile size: {}x{} pixels".format(
|
|
590
|
+
int(optimal_terrain_tile_width / resolution),
|
|
591
|
+
int(optimal_terrain_tile_width / resolution),
|
|
592
|
+
)
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
return bounds, optimal_terrain_tile_width
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def get_conversion_factor(bounds, epsg, epsg_cloud):
|
|
599
|
+
"""
|
|
600
|
+
Conmpute conversion factor
|
|
601
|
+
|
|
602
|
+
:param bounds: terrain bounds
|
|
603
|
+
:type bounds: list
|
|
604
|
+
:param epsg: epsg of bounds
|
|
605
|
+
:type epsg: int
|
|
606
|
+
:param epsg_cloud: epsg of the input cloud
|
|
607
|
+
:type epsg_cloud: int
|
|
608
|
+
:return: conversion factor
|
|
609
|
+
:rtype: float
|
|
610
|
+
"""
|
|
611
|
+
|
|
612
|
+
conversion_factor = 1
|
|
613
|
+
|
|
614
|
+
# only if epsg and epsg_cloud are different
|
|
615
|
+
spatial_ref = CRS.from_epsg(epsg)
|
|
616
|
+
spatial_ref_cloud = CRS.from_epsg(epsg_cloud)
|
|
617
|
+
is_geographic = spatial_ref.is_geographic or spatial_ref_cloud.is_geographic
|
|
618
|
+
if is_geographic and epsg != epsg_cloud:
|
|
619
|
+
# Compute bounds and terrain grid
|
|
620
|
+
[xmin, ymin, xmax, ymax] = bounds
|
|
621
|
+
bounds_points = [
|
|
622
|
+
[xmin, ymin],
|
|
623
|
+
[xmax, ymax],
|
|
624
|
+
]
|
|
625
|
+
bounds_point_epsg_cloud = projection.point_cloud_conversion(
|
|
626
|
+
bounds_points, epsg, epsg_cloud
|
|
627
|
+
)
|
|
628
|
+
# Compute area in both epsg
|
|
629
|
+
terrain_area_epsg = (xmax - xmin) * (ymax - ymin)
|
|
630
|
+
terrain_area_epsg_cloud = (
|
|
631
|
+
bounds_point_epsg_cloud[1][0] - bounds_point_epsg_cloud[0][0]
|
|
632
|
+
) * (bounds_point_epsg_cloud[1][1] - bounds_point_epsg_cloud[0][1])
|
|
633
|
+
# Compute conversion factor
|
|
634
|
+
conversion_factor = math.sqrt(
|
|
635
|
+
terrain_area_epsg / terrain_area_epsg_cloud
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
return conversion_factor
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def convert_optimal_tile_size_with_epsg(
|
|
642
|
+
bounds, optimal_terrain_tile_width, epsg, epsg_cloud
|
|
643
|
+
):
|
|
644
|
+
"""
|
|
645
|
+
Convert optimal_tile_size according to epsg.
|
|
646
|
+
Only if epsg_cloud is different of the output epsg.
|
|
647
|
+
|
|
648
|
+
:param bounds: terrain bounds
|
|
649
|
+
:type bounds: list
|
|
650
|
+
:param optimal_terrain_tile_width: initial optimal_terrain_tile_width
|
|
651
|
+
:type optimal_terrain_tile_width: float
|
|
652
|
+
:param epsg: target epsg
|
|
653
|
+
:type epsg: int
|
|
654
|
+
:param epsg_cloud: epsg of the input cloud
|
|
655
|
+
:type epsg_cloud: int
|
|
656
|
+
:return: converted optimal tile size
|
|
657
|
+
:rtype: float
|
|
658
|
+
"""
|
|
659
|
+
|
|
660
|
+
# Convert optimal terrain tile width
|
|
661
|
+
conversion_factor = get_conversion_factor(bounds, epsg, epsg_cloud)
|
|
662
|
+
optimal_terrain_tile_width *= conversion_factor
|
|
663
|
+
return optimal_terrain_tile_width
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
@cars_profile(name="Compute epipolar roi")
|
|
667
|
+
def compute_epipolar_roi( # pylint: disable=too-many-positional-arguments
|
|
668
|
+
terrain_roi_poly,
|
|
669
|
+
terrain_roi_epsg,
|
|
670
|
+
geometry_plugin,
|
|
671
|
+
sensor_image_left,
|
|
672
|
+
sensor_image_right,
|
|
673
|
+
grid_left,
|
|
674
|
+
grid_right,
|
|
675
|
+
output_path,
|
|
676
|
+
disp_min=0,
|
|
677
|
+
disp_max=0,
|
|
678
|
+
):
|
|
679
|
+
"""
|
|
680
|
+
Compute epipolar roi to use
|
|
681
|
+
|
|
682
|
+
:param terrain_roi_poly: terrain roi polygon
|
|
683
|
+
:param terrain_roi_epsg: terrain roi epsg
|
|
684
|
+
:param geometry_plugin: geometry plugin to use
|
|
685
|
+
:param epsg: epsg
|
|
686
|
+
:param disp_min: minimum disparity
|
|
687
|
+
:param disp_max: maximum disparity
|
|
688
|
+
|
|
689
|
+
:return: epipolar region to use, with tile_size a sample
|
|
690
|
+
"""
|
|
691
|
+
|
|
692
|
+
if terrain_roi_poly is None:
|
|
693
|
+
return None
|
|
694
|
+
|
|
695
|
+
roi_bbox = terrain_roi_poly.bounds
|
|
696
|
+
|
|
697
|
+
pair_folder = os.path.join(output_path, "tmp")
|
|
698
|
+
safe_makedirs(pair_folder)
|
|
699
|
+
|
|
700
|
+
sensor1 = sensor_image_left[sens_cst.INPUT_IMG]
|
|
701
|
+
sensor2 = sensor_image_right[sens_cst.INPUT_IMG]
|
|
702
|
+
geomodel1 = sensor_image_left[sens_cst.INPUT_GEO_MODEL]
|
|
703
|
+
geomodel2 = sensor_image_right[sens_cst.INPUT_GEO_MODEL]
|
|
704
|
+
|
|
705
|
+
epipolar_roi = grids_algo.terrain_region_to_epipolar(
|
|
706
|
+
roi_bbox,
|
|
707
|
+
sensor1,
|
|
708
|
+
sensor2,
|
|
709
|
+
geomodel1,
|
|
710
|
+
geomodel2,
|
|
711
|
+
grid_left,
|
|
712
|
+
grid_right,
|
|
713
|
+
geometry_plugin,
|
|
714
|
+
epsg=terrain_roi_epsg,
|
|
715
|
+
disp_min=disp_min,
|
|
716
|
+
disp_max=disp_max,
|
|
717
|
+
tile_size=100,
|
|
718
|
+
epipolar_size_x=grid_left["epipolar_size_x"],
|
|
719
|
+
epipolar_size_y=grid_left["epipolar_size_y"],
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
return epipolar_roi
|