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,1095 @@
|
|
|
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
|
+
# pylint: disable=too-many-lines
|
|
22
|
+
# attribute-defined-outside-init is disabled so that we can create and use
|
|
23
|
+
# attributes however we need, to stick to the "everything is attribute" logic
|
|
24
|
+
# introduced in issue#895
|
|
25
|
+
# pylint: disable=attribute-defined-outside-init
|
|
26
|
+
# pylint: disable=too-many-nested-blocks
|
|
27
|
+
"""
|
|
28
|
+
CARS default pipeline class file
|
|
29
|
+
"""
|
|
30
|
+
# Standard imports
|
|
31
|
+
from __future__ import print_function
|
|
32
|
+
|
|
33
|
+
import copy
|
|
34
|
+
import json
|
|
35
|
+
import logging
|
|
36
|
+
import os
|
|
37
|
+
import shutil
|
|
38
|
+
from collections import OrderedDict
|
|
39
|
+
from datetime import datetime
|
|
40
|
+
|
|
41
|
+
import yaml
|
|
42
|
+
|
|
43
|
+
# CARS imports
|
|
44
|
+
from cars.core import cars_logging
|
|
45
|
+
from cars.core.utils import safe_makedirs
|
|
46
|
+
from cars.data_structures import cars_dataset
|
|
47
|
+
from cars.orchestrator.cluster import log_wrapper
|
|
48
|
+
from cars.orchestrator.cluster.log_wrapper import cars_profile
|
|
49
|
+
from cars.pipelines import pipeline_constants as pipeline_cst
|
|
50
|
+
from cars.pipelines.filling.filling import FillingPipeline
|
|
51
|
+
from cars.pipelines.formatting.formatting import FormattingPipeline
|
|
52
|
+
from cars.pipelines.merging.merging import MergingPipeline
|
|
53
|
+
from cars.pipelines.parameters import advanced_parameters_constants as adv_cst
|
|
54
|
+
from cars.pipelines.parameters import dsm_inputs
|
|
55
|
+
from cars.pipelines.parameters import dsm_inputs_constants as dsm_cst
|
|
56
|
+
from cars.pipelines.parameters import output_constants as out_cst
|
|
57
|
+
from cars.pipelines.parameters import output_parameters, sensor_inputs
|
|
58
|
+
from cars.pipelines.parameters import sensor_inputs_constants as sens_cst
|
|
59
|
+
from cars.pipelines.parameters.output_constants import AUXILIARY
|
|
60
|
+
from cars.pipelines.pipeline import Pipeline
|
|
61
|
+
from cars.pipelines.pipeline_constants import (
|
|
62
|
+
ADVANCED,
|
|
63
|
+
APPLICATIONS,
|
|
64
|
+
INPUT,
|
|
65
|
+
ORCHESTRATOR,
|
|
66
|
+
OUTPUT,
|
|
67
|
+
PIPELINE,
|
|
68
|
+
)
|
|
69
|
+
from cars.pipelines.pipeline_template import PipelineTemplate
|
|
70
|
+
from cars.pipelines.subsampling.subsampling import SubsamplingPipeline
|
|
71
|
+
from cars.pipelines.surface_modeling.surface_modeling import (
|
|
72
|
+
SurfaceModelingPipeline,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
package_path = os.path.dirname(__file__)
|
|
76
|
+
FIRST_RES = "first_resolution"
|
|
77
|
+
INTERMEDIATE_RES = "intermediate_resolution"
|
|
78
|
+
FINAL_RES = "final_resolution"
|
|
79
|
+
|
|
80
|
+
PIPELINE_CONFS = {
|
|
81
|
+
FIRST_RES: os.path.join(
|
|
82
|
+
package_path,
|
|
83
|
+
"..",
|
|
84
|
+
"conf_resolution",
|
|
85
|
+
"conf_first_resolution.yaml",
|
|
86
|
+
),
|
|
87
|
+
INTERMEDIATE_RES: os.path.join(
|
|
88
|
+
package_path,
|
|
89
|
+
"..",
|
|
90
|
+
"conf_resolution",
|
|
91
|
+
"conf_intermediate_resolution.yaml",
|
|
92
|
+
),
|
|
93
|
+
FINAL_RES: os.path.join(
|
|
94
|
+
package_path,
|
|
95
|
+
"..",
|
|
96
|
+
"conf_resolution",
|
|
97
|
+
"conf_final_resolution.yaml",
|
|
98
|
+
),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@Pipeline.register(
|
|
103
|
+
"default",
|
|
104
|
+
)
|
|
105
|
+
class DefaultPipeline(PipelineTemplate):
|
|
106
|
+
"""
|
|
107
|
+
DefaultPipeline
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
# pylint: disable=too-many-instance-attributes
|
|
111
|
+
|
|
112
|
+
def __init__(self, conf, config_dir=None): # noqa: C901
|
|
113
|
+
"""
|
|
114
|
+
Creates pipeline
|
|
115
|
+
|
|
116
|
+
:param pipeline_name: name of the pipeline.
|
|
117
|
+
:type pipeline_name: str
|
|
118
|
+
:param cfg: configuration {'matching_cost_method': value}
|
|
119
|
+
:type cfg: dictionary
|
|
120
|
+
:param config_dir: path to dir containing json or yaml file
|
|
121
|
+
:type config_dir: str
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
self.config_dir = config_dir
|
|
125
|
+
# Transform relative path to absolute path
|
|
126
|
+
if config_dir is not None:
|
|
127
|
+
config_dir = os.path.abspath(config_dir)
|
|
128
|
+
|
|
129
|
+
# Check global conf
|
|
130
|
+
self.check_global_schema(conf)
|
|
131
|
+
|
|
132
|
+
self.out_dir = conf[OUTPUT][out_cst.OUT_DIRECTORY]
|
|
133
|
+
|
|
134
|
+
conf[PIPELINE] = self.check_pipeline(conf)
|
|
135
|
+
|
|
136
|
+
self.pipeline_to_use = conf[PIPELINE]
|
|
137
|
+
|
|
138
|
+
# Check input
|
|
139
|
+
conf[INPUT] = self.check_inputs(conf, config_json_dir=config_dir)
|
|
140
|
+
|
|
141
|
+
# check output
|
|
142
|
+
conf[OUTPUT] = self.check_output(conf)
|
|
143
|
+
|
|
144
|
+
self.intermediate_data_dir = os.path.join(
|
|
145
|
+
self.out_dir, "intermediate_data"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
conf[ORCHESTRATOR] = self.check_orchestrator(
|
|
149
|
+
conf.get(ORCHESTRATOR, None)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if self.pipeline_to_use[pipeline_cst.SUBSAMPLING]:
|
|
153
|
+
self.subsampling_conf = self.construct_subsampling_conf(conf)
|
|
154
|
+
conf[pipeline_cst.SUBSAMPLING] = self.check_subsampling(
|
|
155
|
+
self.subsampling_conf,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Get epipolar resolutions to use
|
|
159
|
+
self.resolutions = conf[pipeline_cst.SUBSAMPLING][ADVANCED][
|
|
160
|
+
adv_cst.RESOLUTIONS
|
|
161
|
+
]
|
|
162
|
+
else:
|
|
163
|
+
self.resolutions = [1]
|
|
164
|
+
|
|
165
|
+
for pipeline, activated in self.pipeline_to_use.items():
|
|
166
|
+
if pipeline in conf and not activated:
|
|
167
|
+
logging.warning(
|
|
168
|
+
f"You tried to override the {pipeline} pipeline but "
|
|
169
|
+
f"didn't specify it in the pipeline section. "
|
|
170
|
+
"Therefore, this pipeline will not be used"
|
|
171
|
+
)
|
|
172
|
+
if pipeline in conf and activated:
|
|
173
|
+
# Check pipeline conf format
|
|
174
|
+
self.check_pipeline_section(pipeline, conf[pipeline])
|
|
175
|
+
|
|
176
|
+
if pipeline_cst.SURFACE_MODELING not in conf:
|
|
177
|
+
conf[pipeline_cst.SURFACE_MODELING] = {}
|
|
178
|
+
if pipeline_cst.TIE_POINTS not in conf:
|
|
179
|
+
conf[pipeline_cst.TIE_POINTS] = {}
|
|
180
|
+
|
|
181
|
+
used_configurations = {}
|
|
182
|
+
self.positions = {}
|
|
183
|
+
self.used_conf = {}
|
|
184
|
+
|
|
185
|
+
self.keep_low_res_dir = True
|
|
186
|
+
|
|
187
|
+
if dsm_cst.DSMS in conf[INPUT] and len(self.resolutions) != 1:
|
|
188
|
+
logging.info(
|
|
189
|
+
"For the use of those pipelines, "
|
|
190
|
+
"you have to give only one resolution"
|
|
191
|
+
)
|
|
192
|
+
# overide epipolar resolutions
|
|
193
|
+
# TODO: delete with external dsm pipeline (refactoring)
|
|
194
|
+
self.resolutions = [1]
|
|
195
|
+
elif (
|
|
196
|
+
not self.pipeline_to_use[pipeline_cst.SUBSAMPLING]
|
|
197
|
+
and len(self.resolutions) != 1
|
|
198
|
+
):
|
|
199
|
+
logging.warning(
|
|
200
|
+
"As you're not using the subsampling pipeline, "
|
|
201
|
+
"the working resolution will be 1"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
self.resolutions = [1]
|
|
205
|
+
|
|
206
|
+
if self.pipeline_to_use[pipeline_cst.FILLING]:
|
|
207
|
+
self.filling_conf = self.construct_filling_conf(conf)
|
|
208
|
+
conf[pipeline_cst.FILLING] = self.check_filling(self.filling_conf)
|
|
209
|
+
consistent_filling = False
|
|
210
|
+
for app in conf[pipeline_cst.FILLING][APPLICATIONS]:
|
|
211
|
+
if "dsm_filling" in app:
|
|
212
|
+
consistent_filling = True
|
|
213
|
+
for filling_method in conf[INPUT][sens_cst.FILLING]:
|
|
214
|
+
if conf[INPUT][sens_cst.FILLING][filling_method]:
|
|
215
|
+
consistent_filling = True
|
|
216
|
+
if not consistent_filling:
|
|
217
|
+
self.pipeline_to_use[pipeline_cst.FILLING] = False
|
|
218
|
+
|
|
219
|
+
subsampling_used_conf = conf.get(pipeline_cst.SUBSAMPLING, {})
|
|
220
|
+
filling_used_conf = conf.get(pipeline_cst.FILLING, {})
|
|
221
|
+
|
|
222
|
+
if self.pipeline_to_use[pipeline_cst.SURFACE_MODELING]:
|
|
223
|
+
for epipolar_resolution_index, epipolar_res in enumerate(
|
|
224
|
+
self.resolutions
|
|
225
|
+
):
|
|
226
|
+
first_res = epipolar_resolution_index == 0
|
|
227
|
+
last_res = (
|
|
228
|
+
epipolar_resolution_index == len(self.resolutions) - 1
|
|
229
|
+
)
|
|
230
|
+
intermediate_res = not first_res and not last_res
|
|
231
|
+
|
|
232
|
+
# set computed bool
|
|
233
|
+
self.positions[epipolar_resolution_index] = {
|
|
234
|
+
"first_res": first_res,
|
|
235
|
+
"intermediate_res": intermediate_res,
|
|
236
|
+
"last_res": last_res,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
current_conf = copy.deepcopy(conf)
|
|
240
|
+
current_conf = extract_conf_with_resolution(
|
|
241
|
+
current_conf,
|
|
242
|
+
epipolar_res,
|
|
243
|
+
first_res,
|
|
244
|
+
intermediate_res,
|
|
245
|
+
last_res,
|
|
246
|
+
self.intermediate_data_dir,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if not isinstance(epipolar_res, int) or epipolar_res < 0:
|
|
250
|
+
raise RuntimeError("The resolution has to be an int > 0")
|
|
251
|
+
|
|
252
|
+
self.used_conf[epipolar_resolution_index] = current_conf
|
|
253
|
+
|
|
254
|
+
# Initialize unit pipeline in order to retrieve the
|
|
255
|
+
# used configuration
|
|
256
|
+
# This pipeline will not be run
|
|
257
|
+
_ = current_conf.pop(pipeline_cst.SUBSAMPLING, None)
|
|
258
|
+
_ = current_conf.pop(pipeline_cst.FILLING, None)
|
|
259
|
+
|
|
260
|
+
current_unit_pipeline = SurfaceModelingPipeline(
|
|
261
|
+
current_conf,
|
|
262
|
+
config_dir=self.config_dir,
|
|
263
|
+
)
|
|
264
|
+
if last_res and self.pipeline_to_use[pipeline_cst.FILLING]:
|
|
265
|
+
# Force classification saving for filling
|
|
266
|
+
if not current_unit_pipeline.used_conf[OUTPUT][AUXILIARY][
|
|
267
|
+
sens_cst.INPUT_CLASSIFICATION
|
|
268
|
+
]:
|
|
269
|
+
current_unit_pipeline.used_conf[OUTPUT][AUXILIARY][
|
|
270
|
+
sens_cst.INPUT_CLASSIFICATION
|
|
271
|
+
] = True
|
|
272
|
+
if not self.filling_conf[OUTPUT][AUXILIARY][
|
|
273
|
+
sens_cst.INPUT_CLASSIFICATION
|
|
274
|
+
]:
|
|
275
|
+
self.filling_conf[OUTPUT][AUXILIARY][
|
|
276
|
+
sens_cst.INPUT_CLASSIFICATION
|
|
277
|
+
] = True
|
|
278
|
+
# Get used_conf
|
|
279
|
+
used_configurations[epipolar_res] = (
|
|
280
|
+
current_unit_pipeline.used_conf
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Generate full used_conf
|
|
284
|
+
full_used_conf = merge_used_conf(
|
|
285
|
+
used_configurations,
|
|
286
|
+
self.resolutions,
|
|
287
|
+
os.path.abspath(self.out_dir),
|
|
288
|
+
)
|
|
289
|
+
else:
|
|
290
|
+
self.used_conf = copy.deepcopy(conf)
|
|
291
|
+
full_used_conf = self.used_conf
|
|
292
|
+
|
|
293
|
+
full_used_conf[pipeline_cst.SUBSAMPLING] = subsampling_used_conf
|
|
294
|
+
full_used_conf[pipeline_cst.PIPELINE] = conf[PIPELINE]
|
|
295
|
+
full_used_conf[pipeline_cst.FILLING] = filling_used_conf
|
|
296
|
+
|
|
297
|
+
# Save used_conf
|
|
298
|
+
cars_dataset.save_dict(
|
|
299
|
+
full_used_conf,
|
|
300
|
+
os.path.join(self.out_dir, "global_used_conf.yaml"),
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def check_inputs(self, conf, config_json_dir=None):
|
|
304
|
+
"""
|
|
305
|
+
Check the inputs given
|
|
306
|
+
|
|
307
|
+
:param conf: configuration
|
|
308
|
+
:type conf: dict
|
|
309
|
+
:param config_dir: directory of used json, if
|
|
310
|
+
user filled paths with relative paths
|
|
311
|
+
:type config_dir: str
|
|
312
|
+
|
|
313
|
+
:return: overloader inputs
|
|
314
|
+
:rtype: dict
|
|
315
|
+
"""
|
|
316
|
+
output_config = {}
|
|
317
|
+
if sens_cst.SENSORS in conf[INPUT] and dsm_cst.DSMS not in conf[INPUT]:
|
|
318
|
+
output_config = sensor_inputs.sensors_check_inputs(
|
|
319
|
+
conf[INPUT], config_dir=config_json_dir
|
|
320
|
+
)
|
|
321
|
+
elif dsm_cst.DSMS in conf[INPUT]:
|
|
322
|
+
output_config = {
|
|
323
|
+
**output_config,
|
|
324
|
+
**dsm_inputs.check_dsm_inputs(
|
|
325
|
+
conf[INPUT], config_dir=config_json_dir
|
|
326
|
+
),
|
|
327
|
+
}
|
|
328
|
+
else:
|
|
329
|
+
raise RuntimeError("No sensors or dsms in inputs")
|
|
330
|
+
|
|
331
|
+
return output_config
|
|
332
|
+
|
|
333
|
+
def check_output(self, conf):
|
|
334
|
+
"""
|
|
335
|
+
Check the output given
|
|
336
|
+
|
|
337
|
+
:param conf: configuration of output
|
|
338
|
+
:type conf: dict
|
|
339
|
+
|
|
340
|
+
:return overloader output
|
|
341
|
+
:rtype : dict
|
|
342
|
+
"""
|
|
343
|
+
conf_output, _ = output_parameters.check_output_parameters(
|
|
344
|
+
conf[INPUT], conf[OUTPUT]
|
|
345
|
+
)
|
|
346
|
+
return conf_output
|
|
347
|
+
|
|
348
|
+
def check_pipeline(self, conf): # noqa: C901
|
|
349
|
+
"""
|
|
350
|
+
Check the pipeline section
|
|
351
|
+
"""
|
|
352
|
+
possible_pipeline = [
|
|
353
|
+
pipeline_cst.SUBSAMPLING,
|
|
354
|
+
pipeline_cst.SURFACE_MODELING,
|
|
355
|
+
pipeline_cst.FILLING,
|
|
356
|
+
pipeline_cst.MERGING,
|
|
357
|
+
pipeline_cst.FORMATTING,
|
|
358
|
+
]
|
|
359
|
+
dict_pipeline = {}
|
|
360
|
+
|
|
361
|
+
if PIPELINE not in conf:
|
|
362
|
+
if dsm_cst.DSMS in conf[INPUT]:
|
|
363
|
+
conf[PIPELINE] = [pipeline_cst.MERGING, pipeline_cst.FORMATTING]
|
|
364
|
+
elif sens_cst.SENSORS in conf[INPUT]:
|
|
365
|
+
conf[PIPELINE] = [
|
|
366
|
+
pipeline_cst.SUBSAMPLING,
|
|
367
|
+
pipeline_cst.SURFACE_MODELING,
|
|
368
|
+
pipeline_cst.FORMATTING,
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
if isinstance(conf[PIPELINE], str):
|
|
372
|
+
if conf[PIPELINE] not in possible_pipeline:
|
|
373
|
+
raise RuntimeError("This pipeline does not exist")
|
|
374
|
+
dict_pipeline = {conf[PIPELINE]: True}
|
|
375
|
+
elif isinstance(conf[PIPELINE], list):
|
|
376
|
+
for elem in conf[PIPELINE]:
|
|
377
|
+
if elem not in possible_pipeline:
|
|
378
|
+
raise RuntimeError(f"The pipeline {elem} does not exist")
|
|
379
|
+
dict_pipeline.update({elem: True})
|
|
380
|
+
elif isinstance(conf[PIPELINE], dict):
|
|
381
|
+
for key, _ in conf[PIPELINE].items():
|
|
382
|
+
if key not in possible_pipeline:
|
|
383
|
+
raise RuntimeError(f"The pipeline {key} does not exist")
|
|
384
|
+
dict_pipeline = copy.deepcopy(conf[PIPELINE])
|
|
385
|
+
|
|
386
|
+
for key in possible_pipeline:
|
|
387
|
+
if key not in dict_pipeline:
|
|
388
|
+
dict_pipeline.update({key: False})
|
|
389
|
+
|
|
390
|
+
if (
|
|
391
|
+
dsm_cst.DSMS in conf[INPUT]
|
|
392
|
+
and not dict_pipeline[pipeline_cst.MERGING]
|
|
393
|
+
):
|
|
394
|
+
dict_pipeline[pipeline_cst.MERGING] = True
|
|
395
|
+
elif (
|
|
396
|
+
dsm_cst.DSMS in conf[INPUT]
|
|
397
|
+
and dict_pipeline[pipeline_cst.SURFACE_MODELING]
|
|
398
|
+
):
|
|
399
|
+
raise RuntimeError(
|
|
400
|
+
"You can not use the surface modeling pipeline with dsm inputs"
|
|
401
|
+
)
|
|
402
|
+
elif (
|
|
403
|
+
sens_cst.SENSORS in conf[INPUT]
|
|
404
|
+
and dict_pipeline[pipeline_cst.MERGING]
|
|
405
|
+
and dsm_cst.DSMS not in conf[INPUT]
|
|
406
|
+
):
|
|
407
|
+
raise RuntimeError(
|
|
408
|
+
"You can not use the merging pipeline with sensors inputs only"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
activate_filling = False
|
|
412
|
+
if pipeline_cst.FILLING in conf[INPUT]:
|
|
413
|
+
for filling_method in conf[INPUT][pipeline_cst.FILLING]:
|
|
414
|
+
if conf[INPUT][pipeline_cst.FILLING][filling_method]:
|
|
415
|
+
activate_filling = True
|
|
416
|
+
if pipeline_cst.FILLING in conf and conf[pipeline_cst.FILLING]:
|
|
417
|
+
activate_filling = True
|
|
418
|
+
|
|
419
|
+
if activate_filling:
|
|
420
|
+
dict_pipeline[pipeline_cst.FILLING] = True
|
|
421
|
+
|
|
422
|
+
if (
|
|
423
|
+
pipeline_cst.SURFACE_MODELING in conf[INPUT]
|
|
424
|
+
and not dict_pipeline[pipeline_cst.SURFACE_MODELING]
|
|
425
|
+
):
|
|
426
|
+
dict_pipeline[pipeline_cst.SURFACE_MODELING] = True
|
|
427
|
+
|
|
428
|
+
if (
|
|
429
|
+
pipeline_cst.MERGING in conf[INPUT]
|
|
430
|
+
and not dict_pipeline[pipeline_cst.MERGING]
|
|
431
|
+
):
|
|
432
|
+
dict_pipeline[pipeline_cst.MERGING] = True
|
|
433
|
+
|
|
434
|
+
if (
|
|
435
|
+
pipeline_cst.SUBSAMPLING in conf[INPUT]
|
|
436
|
+
and not dict_pipeline[pipeline_cst.SUBSAMPLING]
|
|
437
|
+
):
|
|
438
|
+
dict_pipeline[pipeline_cst.SUBSAMPLING] = True
|
|
439
|
+
|
|
440
|
+
return dict_pipeline
|
|
441
|
+
|
|
442
|
+
def check_subsampling(self, conf):
|
|
443
|
+
"""
|
|
444
|
+
Check the subsampling section
|
|
445
|
+
|
|
446
|
+
:param conf: configuration of subsampling
|
|
447
|
+
:type conf: dict
|
|
448
|
+
"""
|
|
449
|
+
pipeline = SubsamplingPipeline(conf)
|
|
450
|
+
advanced = pipeline.check_advanced(
|
|
451
|
+
conf[pipeline_cst.SUBSAMPLING].get(ADVANCED, {}),
|
|
452
|
+
conf[INPUT],
|
|
453
|
+
)
|
|
454
|
+
applications = pipeline.check_applications(
|
|
455
|
+
conf[pipeline_cst.SUBSAMPLING].get(APPLICATIONS, {})
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
return {ADVANCED: advanced, APPLICATIONS: applications}
|
|
459
|
+
|
|
460
|
+
def check_filling(self, conf):
|
|
461
|
+
"""
|
|
462
|
+
Check the filling section
|
|
463
|
+
|
|
464
|
+
:param conf: configuration of subsampling
|
|
465
|
+
:type conf: dict
|
|
466
|
+
"""
|
|
467
|
+
|
|
468
|
+
pipeline = FillingPipeline(conf, pre_check=True)
|
|
469
|
+
advanced = pipeline.check_advanced(
|
|
470
|
+
conf[pipeline_cst.FILLING],
|
|
471
|
+
conf[INPUT],
|
|
472
|
+
)
|
|
473
|
+
applications = pipeline.check_applications(
|
|
474
|
+
conf[pipeline_cst.FILLING].get(APPLICATIONS, {})
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
return {ADVANCED: advanced, APPLICATIONS: applications}
|
|
478
|
+
|
|
479
|
+
def check_pipeline_section(self, pipeline_name, pipeline_conf):
|
|
480
|
+
"""
|
|
481
|
+
Check any pipeline section
|
|
482
|
+
|
|
483
|
+
:param pipeline_name: key name in conf
|
|
484
|
+
:type pipeline_name: str
|
|
485
|
+
:param pipeline_conf: pipeline configuration
|
|
486
|
+
:type pipeline_conf: dict
|
|
487
|
+
"""
|
|
488
|
+
for key in pipeline_conf:
|
|
489
|
+
if key not in [APPLICATIONS, ADVANCED]:
|
|
490
|
+
raise KeyError(
|
|
491
|
+
"Keys of a pipeline must be 'applications' or 'advanced'"
|
|
492
|
+
)
|
|
493
|
+
if pipeline_name in (
|
|
494
|
+
pipeline_cst.SURFACE_MODELING,
|
|
495
|
+
pipeline_cst.TIE_POINTS,
|
|
496
|
+
):
|
|
497
|
+
int_keys = [int(epi_res) for epi_res in self.resolutions]
|
|
498
|
+
string_keys = [str(key) for key in int_keys]
|
|
499
|
+
possible_keys = ["all"] + int_keys + string_keys
|
|
500
|
+
|
|
501
|
+
for section in pipeline_conf:
|
|
502
|
+
for key in pipeline_conf[section]:
|
|
503
|
+
if key not in possible_keys:
|
|
504
|
+
raise KeyError(
|
|
505
|
+
"When meta pipeline is used, keys of {} pipeline"
|
|
506
|
+
"must be in {}".format(
|
|
507
|
+
pipeline_name,
|
|
508
|
+
string_keys + ["all"],
|
|
509
|
+
)
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
def cleanup_low_res_dir(self):
|
|
513
|
+
"""
|
|
514
|
+
Clean low res dir
|
|
515
|
+
"""
|
|
516
|
+
|
|
517
|
+
if os.path.exists(self.intermediate_data_dir) and os.path.isdir(
|
|
518
|
+
self.intermediate_data_dir
|
|
519
|
+
):
|
|
520
|
+
try:
|
|
521
|
+
shutil.rmtree(self.intermediate_data_dir)
|
|
522
|
+
logging.info(
|
|
523
|
+
f"th directory {self.intermediate_data_dir} "
|
|
524
|
+
f" has been cleaned."
|
|
525
|
+
)
|
|
526
|
+
except Exception as exception:
|
|
527
|
+
logging.error(
|
|
528
|
+
f"Error while deleting {self.intermediate_data_dir}: "
|
|
529
|
+
f"{exception}"
|
|
530
|
+
)
|
|
531
|
+
else:
|
|
532
|
+
logging.info(
|
|
533
|
+
f"The directory {self.intermediate_data_dir} has not "
|
|
534
|
+
f"been deleted"
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
def construct_merging_conf(self, conf):
|
|
538
|
+
"""
|
|
539
|
+
Construct the right conf for merging
|
|
540
|
+
"""
|
|
541
|
+
merging_conf = {}
|
|
542
|
+
merging_conf[INPUT] = copy.deepcopy(conf[INPUT])
|
|
543
|
+
merging_conf[ORCHESTRATOR] = copy.deepcopy(conf[ORCHESTRATOR])
|
|
544
|
+
merging_conf[OUTPUT] = {}
|
|
545
|
+
merging_conf[OUTPUT]["directory"] = os.path.join(
|
|
546
|
+
self.intermediate_data_dir, pipeline_cst.MERGING
|
|
547
|
+
)
|
|
548
|
+
merging_conf[OUTPUT][AUXILIARY] = conf[OUTPUT].get(AUXILIARY, {})
|
|
549
|
+
|
|
550
|
+
merging_conf[pipeline_cst.MERGING] = conf.get(pipeline_cst.MERGING, {})
|
|
551
|
+
|
|
552
|
+
return merging_conf
|
|
553
|
+
|
|
554
|
+
def construct_subsampling_conf(self, conf):
|
|
555
|
+
"""
|
|
556
|
+
Construct the right conf for subsampling
|
|
557
|
+
"""
|
|
558
|
+
subsampling_conf = {}
|
|
559
|
+
subsampling_conf[INPUT] = copy.deepcopy(conf[INPUT])
|
|
560
|
+
subsampling_conf[ORCHESTRATOR] = copy.deepcopy(conf[ORCHESTRATOR])
|
|
561
|
+
subsampling_conf[OUTPUT] = {}
|
|
562
|
+
subsampling_conf[OUTPUT]["directory"] = self.intermediate_data_dir
|
|
563
|
+
|
|
564
|
+
subsampling_conf[pipeline_cst.SUBSAMPLING] = conf.get(
|
|
565
|
+
pipeline_cst.SUBSAMPLING, {}
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return subsampling_conf
|
|
569
|
+
|
|
570
|
+
def construct_formatting_conf(self, input_dir):
|
|
571
|
+
"""
|
|
572
|
+
Construct the right conf for formatting
|
|
573
|
+
"""
|
|
574
|
+
|
|
575
|
+
formatting_conf = {}
|
|
576
|
+
formatting_conf[INPUT] = {}
|
|
577
|
+
formatting_conf[INPUT]["input_path"] = input_dir
|
|
578
|
+
formatting_conf[OUTPUT] = {}
|
|
579
|
+
formatting_conf[OUTPUT]["directory"] = self.out_dir
|
|
580
|
+
|
|
581
|
+
return formatting_conf
|
|
582
|
+
|
|
583
|
+
def construct_filling_conf(self, conf):
|
|
584
|
+
"""
|
|
585
|
+
Construct the right conf for filling
|
|
586
|
+
"""
|
|
587
|
+
filling_conf = {}
|
|
588
|
+
filling_conf[INPUT] = copy.deepcopy(conf[INPUT])
|
|
589
|
+
_ = filling_conf[INPUT].pop(dsm_cst.DSMS, None)
|
|
590
|
+
filling_conf[OUTPUT] = copy.deepcopy(conf[OUTPUT])
|
|
591
|
+
filling_conf[OUTPUT]["directory"] = self.intermediate_data_dir
|
|
592
|
+
filling_conf[pipeline_cst.FILLING] = conf.get(pipeline_cst.FILLING, {})
|
|
593
|
+
return filling_conf
|
|
594
|
+
|
|
595
|
+
@cars_profile(name="Run_default_pipeline", interval=0.5)
|
|
596
|
+
def run(self, args=None): # noqa C901
|
|
597
|
+
"""
|
|
598
|
+
Run pipeline
|
|
599
|
+
|
|
600
|
+
"""
|
|
601
|
+
|
|
602
|
+
global_log_file = os.path.join(
|
|
603
|
+
self.out_dir,
|
|
604
|
+
"logs",
|
|
605
|
+
"{}_{}.log".format(
|
|
606
|
+
datetime.now().strftime("%y-%m-%d_%Hh%Mm"), "default_pipeline"
|
|
607
|
+
),
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
previous_out_dir = None
|
|
611
|
+
current_surface_modeling_out_dir = None
|
|
612
|
+
updated_conf = {}
|
|
613
|
+
|
|
614
|
+
if self.pipeline_to_use[pipeline_cst.SUBSAMPLING]:
|
|
615
|
+
subsampling_pipeline = SubsamplingPipeline(
|
|
616
|
+
self.subsampling_conf, self.config_dir
|
|
617
|
+
)
|
|
618
|
+
subsampling_pipeline.run()
|
|
619
|
+
|
|
620
|
+
if self.pipeline_to_use[pipeline_cst.SURFACE_MODELING]:
|
|
621
|
+
for resolution_index, epipolar_res in enumerate(self.resolutions):
|
|
622
|
+
|
|
623
|
+
# Get tested unit pipeline
|
|
624
|
+
current_conf = self.used_conf[resolution_index]
|
|
625
|
+
current_surface_modeling_out_dir = current_conf[OUTPUT][
|
|
626
|
+
"directory"
|
|
627
|
+
]
|
|
628
|
+
|
|
629
|
+
# Put right directory for subsampling
|
|
630
|
+
if self.pipeline_to_use[pipeline_cst.SUBSAMPLING]:
|
|
631
|
+
if epipolar_res != 1:
|
|
632
|
+
yaml_file = os.path.join(
|
|
633
|
+
self.intermediate_data_dir,
|
|
634
|
+
"subsampling/res_"
|
|
635
|
+
+ str(epipolar_res)
|
|
636
|
+
+ "/input.yaml",
|
|
637
|
+
)
|
|
638
|
+
with open(yaml_file, encoding="utf-8") as f:
|
|
639
|
+
data = yaml.safe_load(f)
|
|
640
|
+
|
|
641
|
+
json_str = json.dumps(data, indent=4)
|
|
642
|
+
data = json.loads(json_str)
|
|
643
|
+
|
|
644
|
+
current_conf[INPUT] = data
|
|
645
|
+
|
|
646
|
+
# update directory for unit pipeline
|
|
647
|
+
current_conf[OUTPUT][
|
|
648
|
+
"directory"
|
|
649
|
+
] = current_surface_modeling_out_dir
|
|
650
|
+
|
|
651
|
+
# get position
|
|
652
|
+
first_res, _, last_res = (
|
|
653
|
+
self.positions[resolution_index]["first_res"],
|
|
654
|
+
self.positions[resolution_index]["intermediate_res"],
|
|
655
|
+
self.positions[resolution_index]["last_res"],
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
# setup logging
|
|
659
|
+
loglevel = getattr(args, "loglevel", "PROGRESS").upper()
|
|
660
|
+
|
|
661
|
+
current_log_dir = os.path.join(
|
|
662
|
+
self.out_dir, "logs", "res_" + str(epipolar_res)
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
cars_logging.setup_logging(
|
|
666
|
+
loglevel,
|
|
667
|
+
out_dir=current_log_dir,
|
|
668
|
+
pipeline="surface_modeling",
|
|
669
|
+
global_log_file=global_log_file,
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
cars_logging.add_progress_message(
|
|
673
|
+
"Starting surface modeling pipeline for resolution 1/"
|
|
674
|
+
+ str(epipolar_res)
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
# define wich resolution
|
|
678
|
+
if first_res and last_res:
|
|
679
|
+
which_resolution = "single"
|
|
680
|
+
elif first_res:
|
|
681
|
+
which_resolution = "first"
|
|
682
|
+
elif last_res:
|
|
683
|
+
which_resolution = "final"
|
|
684
|
+
else:
|
|
685
|
+
which_resolution = "intermediate"
|
|
686
|
+
|
|
687
|
+
# Overide with a priori
|
|
688
|
+
if not first_res:
|
|
689
|
+
dsm = os.path.join(previous_out_dir, "dsm/dsm.tif")
|
|
690
|
+
current_conf[INPUT][sens_cst.LOW_RES_DSM] = dsm
|
|
691
|
+
|
|
692
|
+
updated_pipeline = SurfaceModelingPipeline(
|
|
693
|
+
current_conf,
|
|
694
|
+
config_dir=self.config_dir,
|
|
695
|
+
)
|
|
696
|
+
updated_pipeline.run(
|
|
697
|
+
which_resolution=which_resolution,
|
|
698
|
+
log_dir=current_log_dir,
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
# update previous out dir
|
|
702
|
+
previous_out_dir = current_surface_modeling_out_dir
|
|
703
|
+
|
|
704
|
+
# generate summary
|
|
705
|
+
log_wrapper.generate_summary(
|
|
706
|
+
current_log_dir,
|
|
707
|
+
updated_pipeline.used_conf,
|
|
708
|
+
pipeline_cst.SURFACE_MODELING,
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
updated_conf[epipolar_res] = updated_pipeline.used_conf
|
|
712
|
+
|
|
713
|
+
# Generate full used_conf
|
|
714
|
+
full_used_conf = merge_used_conf(
|
|
715
|
+
updated_conf,
|
|
716
|
+
self.resolutions,
|
|
717
|
+
os.path.abspath(self.out_dir),
|
|
718
|
+
)
|
|
719
|
+
else:
|
|
720
|
+
full_used_conf = self.used_conf
|
|
721
|
+
|
|
722
|
+
final_conf = None
|
|
723
|
+
if self.pipeline_to_use[pipeline_cst.MERGING]:
|
|
724
|
+
merging_conf = self.construct_merging_conf(self.used_conf)
|
|
725
|
+
merging_pipeline = MergingPipeline(merging_conf, self.config_dir)
|
|
726
|
+
merging_pipeline.run()
|
|
727
|
+
|
|
728
|
+
final_conf = merging_pipeline.used_conf
|
|
729
|
+
|
|
730
|
+
if updated_conf and final_conf is None:
|
|
731
|
+
last_key = list(updated_conf.keys())[-1]
|
|
732
|
+
final_conf = updated_conf[last_key]
|
|
733
|
+
elif not updated_conf and final_conf is None:
|
|
734
|
+
final_conf = self.used_conf
|
|
735
|
+
|
|
736
|
+
formatting_input_dir = final_conf[OUTPUT][out_cst.OUT_DIRECTORY]
|
|
737
|
+
|
|
738
|
+
if self.pipeline_to_use[pipeline_cst.FILLING]:
|
|
739
|
+
if self.filling_conf[INPUT]["dsm_to_fill"] is None:
|
|
740
|
+
if (
|
|
741
|
+
not self.pipeline_to_use[pipeline_cst.SURFACE_MODELING]
|
|
742
|
+
and not self.pipeline_to_use[pipeline_cst.MERGING]
|
|
743
|
+
):
|
|
744
|
+
raise RuntimeError(
|
|
745
|
+
"You have to fill the dsm_to_fill part of the input if "
|
|
746
|
+
"you want to use the filling pipeline separately"
|
|
747
|
+
)
|
|
748
|
+
|
|
749
|
+
self.filling_conf[INPUT]["dsm_to_fill"] = {}
|
|
750
|
+
aux_path = os.path.join(
|
|
751
|
+
final_conf[OUTPUT][out_cst.OUT_DIRECTORY], "dsm/"
|
|
752
|
+
)
|
|
753
|
+
self.filling_conf[INPUT]["dsm_to_fill"]["dsm"] = os.path.join(
|
|
754
|
+
aux_path, "dsm.tif"
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
for aux_output, val in final_conf[OUTPUT][
|
|
758
|
+
out_cst.AUXILIARY
|
|
759
|
+
].items():
|
|
760
|
+
if val:
|
|
761
|
+
self.filling_conf[INPUT]["dsm_to_fill"][aux_output] = (
|
|
762
|
+
os.path.join(aux_path, aux_output + ".tif")
|
|
763
|
+
)
|
|
764
|
+
initial_elevation = final_conf[INPUT][
|
|
765
|
+
sens_cst.INITIAL_ELEVATION
|
|
766
|
+
].get("dem", None)
|
|
767
|
+
|
|
768
|
+
if (
|
|
769
|
+
initial_elevation is not None
|
|
770
|
+
and "dem_median" in initial_elevation
|
|
771
|
+
):
|
|
772
|
+
self.filling_conf[INPUT][sens_cst.INITIAL_ELEVATION] = None
|
|
773
|
+
|
|
774
|
+
filling_pipeline = FillingPipeline(
|
|
775
|
+
self.filling_conf, self.config_dir
|
|
776
|
+
)
|
|
777
|
+
filling_pipeline.run()
|
|
778
|
+
|
|
779
|
+
formatting_input_dir = os.path.join(
|
|
780
|
+
filling_pipeline.used_conf[OUTPUT][out_cst.OUT_DIRECTORY],
|
|
781
|
+
pipeline_cst.FILLING,
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
if self.pipeline_to_use[pipeline_cst.FORMATTING]:
|
|
785
|
+
formatting_conf = self.construct_formatting_conf(
|
|
786
|
+
formatting_input_dir
|
|
787
|
+
)
|
|
788
|
+
formatting_pipeline = FormattingPipeline(
|
|
789
|
+
formatting_conf, self.config_dir
|
|
790
|
+
)
|
|
791
|
+
formatting_pipeline.run(current_surface_modeling_out_dir)
|
|
792
|
+
|
|
793
|
+
if self.pipeline_to_use[pipeline_cst.FILLING]:
|
|
794
|
+
full_used_conf[pipeline_cst.FILLING] = {
|
|
795
|
+
ADVANCED: filling_pipeline.used_conf[ADVANCED],
|
|
796
|
+
APPLICATIONS: filling_pipeline.used_conf[APPLICATIONS],
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
# Save used_conf
|
|
800
|
+
cars_dataset.save_dict(
|
|
801
|
+
full_used_conf,
|
|
802
|
+
os.path.join(self.out_dir, "global_used_conf.yaml"),
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
# Merge profiling in pdf
|
|
806
|
+
log_wrapper.generate_pdf_profiling(os.path.join(self.out_dir, "logs"))
|
|
807
|
+
|
|
808
|
+
# clean outdir
|
|
809
|
+
if not self.keep_low_res_dir:
|
|
810
|
+
self.cleanup_low_res_dir()
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def extract_conf_section(
|
|
814
|
+
current_conf_section,
|
|
815
|
+
res,
|
|
816
|
+
default_conf_for_res=None,
|
|
817
|
+
filling_applications=None,
|
|
818
|
+
):
|
|
819
|
+
"""
|
|
820
|
+
Extract applications for current resolution
|
|
821
|
+
|
|
822
|
+
:param current_applications_conf: current applications configuration
|
|
823
|
+
:type current_applications_conf: dict
|
|
824
|
+
:param res: resolution to extract
|
|
825
|
+
:type res: int
|
|
826
|
+
:param default_conf_for_res: default configuration for resolution
|
|
827
|
+
:type default_conf_for_res: dict
|
|
828
|
+
:param filling_applications: filling applications configuration
|
|
829
|
+
:type filling_applications: dict
|
|
830
|
+
|
|
831
|
+
:return: configuration for the given resolution
|
|
832
|
+
:rtype: dict
|
|
833
|
+
"""
|
|
834
|
+
|
|
835
|
+
# "all" : applied to all conf
|
|
836
|
+
# int (1, 2, 4, 8, 16, ...) applied for specified resolution
|
|
837
|
+
|
|
838
|
+
all_conf = current_conf_section.get("all", {})
|
|
839
|
+
# Overide with default_conf_for_res
|
|
840
|
+
if default_conf_for_res is not None:
|
|
841
|
+
all_conf = overide_pipeline_conf(all_conf, default_conf_for_res)
|
|
842
|
+
# Get configuration for current res
|
|
843
|
+
if res in current_conf_section:
|
|
844
|
+
# key is int
|
|
845
|
+
key = res
|
|
846
|
+
else:
|
|
847
|
+
key = str(res)
|
|
848
|
+
|
|
849
|
+
res_conf = current_conf_section.get(key, {})
|
|
850
|
+
|
|
851
|
+
# Overide all conf with current res conf
|
|
852
|
+
new_application_conf = overide_pipeline_conf(all_conf, res_conf)
|
|
853
|
+
|
|
854
|
+
# Overide with filling applications
|
|
855
|
+
if filling_applications is not None:
|
|
856
|
+
new_application_conf = overide_pipeline_conf(
|
|
857
|
+
new_application_conf,
|
|
858
|
+
filling_applications,
|
|
859
|
+
append_classification=True,
|
|
860
|
+
)
|
|
861
|
+
return new_application_conf
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
# pylint: disable=too-many-positional-arguments
|
|
865
|
+
def extract_conf_with_resolution(
|
|
866
|
+
current_conf,
|
|
867
|
+
res,
|
|
868
|
+
first_res,
|
|
869
|
+
intermediate_res,
|
|
870
|
+
last_res,
|
|
871
|
+
intermediate_data_dir,
|
|
872
|
+
):
|
|
873
|
+
"""
|
|
874
|
+
Extract the configuration for the given resolution
|
|
875
|
+
|
|
876
|
+
:param current_conf: current configuration
|
|
877
|
+
:type current_conf: dict
|
|
878
|
+
:param res: resolution to extract
|
|
879
|
+
:type res: int
|
|
880
|
+
:return: configuration for the given resolution
|
|
881
|
+
:rtype: dict
|
|
882
|
+
:param first_res: is first resolution
|
|
883
|
+
:type first_res: bool
|
|
884
|
+
:param intermediate_res: is intermediate resolution
|
|
885
|
+
:type intermediate_res: bool
|
|
886
|
+
:param last_res: is last resolution
|
|
887
|
+
:type last_res: bool
|
|
888
|
+
:param previous_out_dir: path to previous outdir
|
|
889
|
+
:type: previous_out_dir: str
|
|
890
|
+
"""
|
|
891
|
+
|
|
892
|
+
surface_modeling_out_dir = os.path.join(
|
|
893
|
+
intermediate_data_dir, "surface_modeling", "res" + str(res)
|
|
894
|
+
)
|
|
895
|
+
safe_makedirs(surface_modeling_out_dir)
|
|
896
|
+
|
|
897
|
+
new_conf = copy.deepcopy(current_conf)
|
|
898
|
+
|
|
899
|
+
# Overide configuration with pipeline conf
|
|
900
|
+
if first_res:
|
|
901
|
+
# read the first resolution conf with json package
|
|
902
|
+
with open(PIPELINE_CONFS[FIRST_RES], "r", encoding="utf-8") as file:
|
|
903
|
+
overiding_conf = yaml.safe_load(file)
|
|
904
|
+
elif intermediate_res:
|
|
905
|
+
with open(
|
|
906
|
+
PIPELINE_CONFS[INTERMEDIATE_RES], "r", encoding="utf-8"
|
|
907
|
+
) as file:
|
|
908
|
+
overiding_conf = yaml.safe_load(file)
|
|
909
|
+
else:
|
|
910
|
+
with open(PIPELINE_CONFS[FINAL_RES], "r", encoding="utf-8") as file:
|
|
911
|
+
overiding_conf = yaml.safe_load(file)
|
|
912
|
+
|
|
913
|
+
if last_res and dsm_cst.DSMS not in current_conf[INPUT]:
|
|
914
|
+
# Use filling applications only for last resolution
|
|
915
|
+
filling_applications_for_surface_modeling = (
|
|
916
|
+
generate_filling_applications_for_surface_modeling(
|
|
917
|
+
current_conf[INPUT]
|
|
918
|
+
)
|
|
919
|
+
)
|
|
920
|
+
else:
|
|
921
|
+
filling_applications_for_surface_modeling = {}
|
|
922
|
+
|
|
923
|
+
# Extract surface modeling conf
|
|
924
|
+
new_conf[pipeline_cst.SURFACE_MODELING] = {}
|
|
925
|
+
new_conf[pipeline_cst.SURFACE_MODELING][APPLICATIONS] = (
|
|
926
|
+
extract_conf_section(
|
|
927
|
+
current_conf[pipeline_cst.SURFACE_MODELING].get(APPLICATIONS, {}),
|
|
928
|
+
res,
|
|
929
|
+
overiding_conf.get(APPLICATIONS, {}),
|
|
930
|
+
filling_applications_for_surface_modeling,
|
|
931
|
+
)
|
|
932
|
+
)
|
|
933
|
+
new_conf[pipeline_cst.SURFACE_MODELING][ADVANCED] = extract_conf_section(
|
|
934
|
+
current_conf[pipeline_cst.SURFACE_MODELING].get(ADVANCED, {}),
|
|
935
|
+
res,
|
|
936
|
+
)
|
|
937
|
+
|
|
938
|
+
# Extract tie points conf
|
|
939
|
+
if current_conf[pipeline_cst.TIE_POINTS] is not None:
|
|
940
|
+
new_conf[pipeline_cst.TIE_POINTS] = {}
|
|
941
|
+
new_conf[pipeline_cst.TIE_POINTS][APPLICATIONS] = extract_conf_section(
|
|
942
|
+
current_conf[pipeline_cst.TIE_POINTS].get(APPLICATIONS, {}),
|
|
943
|
+
res,
|
|
944
|
+
overiding_conf.get(APPLICATIONS, {}),
|
|
945
|
+
)
|
|
946
|
+
new_conf[pipeline_cst.TIE_POINTS][ADVANCED] = extract_conf_section(
|
|
947
|
+
current_conf[pipeline_cst.TIE_POINTS].get(ADVANCED, {}),
|
|
948
|
+
res,
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
overiding_conf = {
|
|
952
|
+
OUTPUT: {out_cst.OUT_DIRECTORY: surface_modeling_out_dir},
|
|
953
|
+
}
|
|
954
|
+
new_conf = overide_pipeline_conf(new_conf, overiding_conf)
|
|
955
|
+
|
|
956
|
+
# Overide output to not compute data
|
|
957
|
+
if not last_res:
|
|
958
|
+
overiding_conf = {
|
|
959
|
+
pipeline_cst.SURFACE_MODELING: {
|
|
960
|
+
APPLICATIONS: {
|
|
961
|
+
"dense_matching": {
|
|
962
|
+
"performance_map_method": ["risk", "intervals"]
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
},
|
|
966
|
+
}
|
|
967
|
+
new_conf = overide_pipeline_conf(new_conf, overiding_conf)
|
|
968
|
+
|
|
969
|
+
# set product level to dsm
|
|
970
|
+
new_conf[OUTPUT][out_cst.PRODUCT_LEVEL] = ["dsm"]
|
|
971
|
+
# remove resolution to let CARS compute it for current
|
|
972
|
+
# epipolar resolution
|
|
973
|
+
new_conf[OUTPUT]["resolution"] = None
|
|
974
|
+
|
|
975
|
+
# Save the less possible things
|
|
976
|
+
for aux_key in new_conf[OUTPUT][out_cst.AUXILIARY]:
|
|
977
|
+
if aux_key != "image":
|
|
978
|
+
new_conf[OUTPUT][out_cst.AUXILIARY][aux_key] = False
|
|
979
|
+
|
|
980
|
+
return new_conf
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
def generate_filling_applications_for_surface_modeling(inputs_conf):
|
|
984
|
+
"""
|
|
985
|
+
Generate filling applications configuration according to inputs
|
|
986
|
+
|
|
987
|
+
:param inputs_conf: inputs configuration
|
|
988
|
+
:type inputs_conf: dict
|
|
989
|
+
"""
|
|
990
|
+
|
|
991
|
+
filling_applications = {}
|
|
992
|
+
|
|
993
|
+
# Generate applications configuration
|
|
994
|
+
for _, classif_values in inputs_conf[sens_cst.FILLING].items():
|
|
995
|
+
# No filling
|
|
996
|
+
if classif_values is None:
|
|
997
|
+
continue
|
|
998
|
+
|
|
999
|
+
classif_values = list(map(str, classif_values))
|
|
1000
|
+
|
|
1001
|
+
# Update application configuration
|
|
1002
|
+
new_filling_conf = {
|
|
1003
|
+
"dense_match_filling": {
|
|
1004
|
+
"method": "zero_padding",
|
|
1005
|
+
"classification": classif_values,
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
# Update application configuration
|
|
1010
|
+
filling_applications = overide_pipeline_conf(
|
|
1011
|
+
filling_applications, new_filling_conf, append_classification=True
|
|
1012
|
+
)
|
|
1013
|
+
|
|
1014
|
+
return filling_applications
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
def overide_pipeline_conf(conf, overiding_conf, append_classification=False):
|
|
1018
|
+
"""
|
|
1019
|
+
Merge two dictionaries recursively without removing keys from the base conf.
|
|
1020
|
+
|
|
1021
|
+
:param conf: base configuration dictionary
|
|
1022
|
+
:type conf: dict
|
|
1023
|
+
:param overiding_conf: overriding configuration dictionary
|
|
1024
|
+
:type overiding_conf: dict
|
|
1025
|
+
:return: merged configuration
|
|
1026
|
+
:rtype: dict
|
|
1027
|
+
"""
|
|
1028
|
+
result = copy.deepcopy(conf)
|
|
1029
|
+
|
|
1030
|
+
def merge_recursive(base_dict, override_dict):
|
|
1031
|
+
"""
|
|
1032
|
+
Main recursive function
|
|
1033
|
+
"""
|
|
1034
|
+
for key, value in override_dict.items():
|
|
1035
|
+
if (
|
|
1036
|
+
key in base_dict
|
|
1037
|
+
and isinstance(base_dict[key], dict)
|
|
1038
|
+
and isinstance(value, dict)
|
|
1039
|
+
):
|
|
1040
|
+
merge_recursive(base_dict[key], value)
|
|
1041
|
+
elif (
|
|
1042
|
+
append_classification
|
|
1043
|
+
and key in base_dict
|
|
1044
|
+
and isinstance(base_dict[key], list)
|
|
1045
|
+
and isinstance(value, list)
|
|
1046
|
+
and key == "classification"
|
|
1047
|
+
):
|
|
1048
|
+
# extend list, avoiding duplicates
|
|
1049
|
+
base_dict[key] = list(
|
|
1050
|
+
OrderedDict.fromkeys(base_dict[key] + value)
|
|
1051
|
+
)
|
|
1052
|
+
else:
|
|
1053
|
+
base_dict[key] = value
|
|
1054
|
+
|
|
1055
|
+
merge_recursive(result, overiding_conf)
|
|
1056
|
+
return result
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
def merge_used_conf(used_configurations, resolutions, out_dir):
|
|
1060
|
+
"""
|
|
1061
|
+
Merge all used configuration
|
|
1062
|
+
"""
|
|
1063
|
+
used_configurations = copy.deepcopy(used_configurations)
|
|
1064
|
+
|
|
1065
|
+
merged_conf = {
|
|
1066
|
+
INPUT: used_configurations[resolutions[-1]][INPUT],
|
|
1067
|
+
OUTPUT: used_configurations[resolutions[0]][OUTPUT],
|
|
1068
|
+
ORCHESTRATOR: used_configurations[resolutions[0]][ORCHESTRATOR],
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
merged_conf[OUTPUT]["directory"] = out_dir
|
|
1072
|
+
|
|
1073
|
+
merged_conf[pipeline_cst.TIE_POINTS] = {APPLICATIONS: {}, ADVANCED: {}}
|
|
1074
|
+
merged_conf[pipeline_cst.SURFACE_MODELING] = {
|
|
1075
|
+
APPLICATIONS: {},
|
|
1076
|
+
ADVANCED: {},
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
for resolution in resolutions:
|
|
1080
|
+
used_conf = used_configurations[resolution]
|
|
1081
|
+
if pipeline_cst.TIE_POINTS in used_conf:
|
|
1082
|
+
merged_conf[pipeline_cst.TIE_POINTS][APPLICATIONS][
|
|
1083
|
+
str(resolution)
|
|
1084
|
+
] = used_conf[pipeline_cst.TIE_POINTS][APPLICATIONS]
|
|
1085
|
+
merged_conf[pipeline_cst.TIE_POINTS][ADVANCED][str(resolution)] = (
|
|
1086
|
+
used_conf[pipeline_cst.TIE_POINTS][ADVANCED]
|
|
1087
|
+
)
|
|
1088
|
+
merged_conf[pipeline_cst.SURFACE_MODELING][APPLICATIONS][
|
|
1089
|
+
str(resolution)
|
|
1090
|
+
] = used_conf[pipeline_cst.SURFACE_MODELING][APPLICATIONS]
|
|
1091
|
+
merged_conf[pipeline_cst.SURFACE_MODELING][ADVANCED][
|
|
1092
|
+
str(resolution)
|
|
1093
|
+
] = used_conf[pipeline_cst.SURFACE_MODELING][ADVANCED]
|
|
1094
|
+
|
|
1095
|
+
return merged_conf
|