cars 1.0.0rc1__cp313-cp313-musllinux_1_2_i686.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cars might be problematic. Click here for more details.
- cars/__init__.py +74 -0
- cars/applications/__init__.py +37 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +104 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +655 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1460 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-313-i386-linux-musl.so +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +588 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +270 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_correction_app.py +496 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +634 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +762 -0
- cars/applications/resampling/resampling_algo.py +614 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
- cars/applications/sparse_matching/sift_app.py +735 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +757 -0
- cars/cars.py +177 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +1119 -0
- cars/core/geometry/shareloc_geometry.py +598 -0
- cars/core/inputs.py +568 -0
- cars/core/outputs.py +176 -0
- cars/core/preprocessing.py +722 -0
- cars/core/projection.py +843 -0
- cars/core/roi_tools.py +215 -0
- cars/core/tiling.py +774 -0
- cars/core/utils.py +164 -0
- cars/data_structures/__init__.py +23 -0
- cars/data_structures/cars_dataset.py +1541 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +244 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +1075 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/orchestrator.py +905 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +786 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +417 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
- cars/pipelines/parameters/application_parameters.py +71 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +918 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +454 -0
- cars/pipelines/parameters/sensor_inputs.py +842 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +31 -0
- cars/pipelines/pipeline_template.py +139 -0
- cars/pipelines/unit/__init__.py +26 -0
- cars/pipelines/unit/unit_pipeline.py +2850 -0
- cars/starter.py +167 -0
- cars-1.0.0rc1.dist-info/METADATA +292 -0
- cars-1.0.0rc1.dist-info/RECORD +202 -0
- cars-1.0.0rc1.dist-info/WHEEL +5 -0
- cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
- cars.libs/libgcc_s-1257a076.so.1 +0 -0
- cars.libs/libstdc++-0530927c.so.6.0.32 +0 -0
|
@@ -0,0 +1,918 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
# pylint: disable=too-many-lines
|
|
21
|
+
"""
|
|
22
|
+
CARS dsm inputs
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import collections
|
|
26
|
+
import logging
|
|
27
|
+
import os
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
import rasterio
|
|
31
|
+
import xarray as xr
|
|
32
|
+
from affine import Affine
|
|
33
|
+
from json_checker import Checker, Or
|
|
34
|
+
from rasterio.windows import from_bounds
|
|
35
|
+
|
|
36
|
+
# CARS imports
|
|
37
|
+
import cars.orchestrator.orchestrator as ocht
|
|
38
|
+
import cars.pipelines.parameters.dsm_inputs_constants as dsm_cst
|
|
39
|
+
from cars.applications.rasterization.rasterization_wrappers import (
|
|
40
|
+
update_data,
|
|
41
|
+
update_weights,
|
|
42
|
+
)
|
|
43
|
+
from cars.core import constants as cst
|
|
44
|
+
from cars.core import inputs, preprocessing, tiling
|
|
45
|
+
from cars.core.geometry.abstract_geometry import AbstractGeometry
|
|
46
|
+
from cars.core.utils import make_relative_path_absolute, safe_makedirs
|
|
47
|
+
from cars.data_structures import cars_dataset
|
|
48
|
+
from cars.pipelines.parameters import sensor_inputs as sens_inp
|
|
49
|
+
from cars.pipelines.parameters import sensor_inputs_constants as sens_cst
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def check_dsm_inputs(conf, config_dir=None):
|
|
53
|
+
"""
|
|
54
|
+
Check the inputs given
|
|
55
|
+
|
|
56
|
+
:param conf: configuration of inputs
|
|
57
|
+
:type conf: dict
|
|
58
|
+
:param config_dir: directory of used json/yaml, if
|
|
59
|
+
user filled paths with relative paths
|
|
60
|
+
:type config_dir: str
|
|
61
|
+
|
|
62
|
+
:return: overloader inputs
|
|
63
|
+
:rtype: dict
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
overloaded_conf = {}
|
|
67
|
+
|
|
68
|
+
# Overload some optional parameters
|
|
69
|
+
overloaded_conf[dsm_cst.DSMS] = {}
|
|
70
|
+
|
|
71
|
+
overloaded_conf[sens_cst.ROI] = conf.get(sens_cst.ROI, None)
|
|
72
|
+
|
|
73
|
+
overloaded_conf[sens_cst.INITIAL_ELEVATION] = (
|
|
74
|
+
sens_inp.get_initial_elevation(
|
|
75
|
+
conf.get(sens_cst.INITIAL_ELEVATION, None)
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
overloaded_conf[sens_cst.SENSORS] = conf.get(sens_cst.SENSORS, None)
|
|
80
|
+
|
|
81
|
+
overloaded_conf[sens_cst.PAIRING] = conf.get(sens_cst.PAIRING, None)
|
|
82
|
+
|
|
83
|
+
# Validate inputs
|
|
84
|
+
inputs_schema = {
|
|
85
|
+
dsm_cst.DSMS: dict,
|
|
86
|
+
sens_cst.ROI: Or(str, dict, None),
|
|
87
|
+
sens_cst.INITIAL_ELEVATION: Or(dict, None),
|
|
88
|
+
sens_cst.SENSORS: Or(dict, None),
|
|
89
|
+
sens_cst.PAIRING: Or([[str]], None),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
checker_inputs = Checker(inputs_schema)
|
|
93
|
+
checker_inputs.validate(overloaded_conf)
|
|
94
|
+
|
|
95
|
+
# Validate depth maps
|
|
96
|
+
|
|
97
|
+
dsm_schema = {
|
|
98
|
+
cst.DSM_CLASSIF: Or(str, None),
|
|
99
|
+
cst.DSM_ALT: Or(str, None),
|
|
100
|
+
cst.DSM_ALT_INF: Or(str, None),
|
|
101
|
+
cst.DSM_ALT_SUP: Or(str, None),
|
|
102
|
+
cst.DSM_WEIGHTS_SUM: Or(str, None),
|
|
103
|
+
cst.DSM_MSK: Or(str, None),
|
|
104
|
+
cst.DSM_NB_PTS: Or(str, None),
|
|
105
|
+
cst.DSM_NB_PTS_IN_CELL: Or(str, None),
|
|
106
|
+
cst.DSM_MEAN: Or(str, None),
|
|
107
|
+
cst.DSM_STD_DEV: Or(str, None),
|
|
108
|
+
cst.DSM_INF_MEAN: Or(str, None),
|
|
109
|
+
cst.DSM_INF_STD: Or(str, None),
|
|
110
|
+
cst.DSM_SUP_MEAN: Or(str, None),
|
|
111
|
+
cst.DSM_SUP_STD: Or(str, None),
|
|
112
|
+
cst.DSM_AMBIGUITY: Or(str, None),
|
|
113
|
+
cst.DSM_PERFORMANCE_MAP: Or(str, None),
|
|
114
|
+
cst.DSM_SOURCE_PC: Or(str, None),
|
|
115
|
+
cst.DSM_FILLING: Or(str, None),
|
|
116
|
+
cst.DSM_COLOR: Or(str, None),
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
checker_pc = Checker(dsm_schema)
|
|
120
|
+
for dsm_key in conf[dsm_cst.DSMS]:
|
|
121
|
+
# Get depth maps with default
|
|
122
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key] = {}
|
|
123
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_ALT] = conf[
|
|
124
|
+
dsm_cst.DSMS
|
|
125
|
+
][dsm_key].get("dsm", None)
|
|
126
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_CLASSIF] = conf[
|
|
127
|
+
dsm_cst.DSMS
|
|
128
|
+
][dsm_key].get("classification", None)
|
|
129
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_COLOR] = conf[
|
|
130
|
+
dsm_cst.DSMS
|
|
131
|
+
][dsm_key].get("image", None)
|
|
132
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_MSK] = conf[
|
|
133
|
+
dsm_cst.DSMS
|
|
134
|
+
][dsm_key].get("mask", None)
|
|
135
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_ALT_INF] = conf[
|
|
136
|
+
dsm_cst.DSMS
|
|
137
|
+
][dsm_key].get("dsm_inf", None)
|
|
138
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_ALT_SUP] = conf[
|
|
139
|
+
dsm_cst.DSMS
|
|
140
|
+
][dsm_key].get("dsm_sup", None)
|
|
141
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_WEIGHTS_SUM] = conf[
|
|
142
|
+
dsm_cst.DSMS
|
|
143
|
+
][dsm_key].get("weights", None)
|
|
144
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_NB_PTS] = conf[
|
|
145
|
+
dsm_cst.DSMS
|
|
146
|
+
][dsm_key].get("dsm_n_pts", None)
|
|
147
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_NB_PTS_IN_CELL] = conf[
|
|
148
|
+
dsm_cst.DSMS
|
|
149
|
+
][dsm_key].get("dsm_pts_in_cell", None)
|
|
150
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_MEAN] = conf[
|
|
151
|
+
dsm_cst.DSMS
|
|
152
|
+
][dsm_key].get("dsm_mean", None)
|
|
153
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_STD_DEV] = conf[
|
|
154
|
+
dsm_cst.DSMS
|
|
155
|
+
][dsm_key].get("dsm_std", None)
|
|
156
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_INF_MEAN] = conf[
|
|
157
|
+
dsm_cst.DSMS
|
|
158
|
+
][dsm_key].get("dsm_inf_mean", None)
|
|
159
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_INF_STD] = conf[
|
|
160
|
+
dsm_cst.DSMS
|
|
161
|
+
][dsm_key].get("dsm_inf_std", None)
|
|
162
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_SUP_MEAN] = conf[
|
|
163
|
+
dsm_cst.DSMS
|
|
164
|
+
][dsm_key].get("dsm_sup_mean", None)
|
|
165
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_SUP_STD] = conf[
|
|
166
|
+
dsm_cst.DSMS
|
|
167
|
+
][dsm_key].get("dsm_sup_std", None)
|
|
168
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_AMBIGUITY] = conf[
|
|
169
|
+
dsm_cst.DSMS
|
|
170
|
+
][dsm_key].get("ambiguity", None)
|
|
171
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_PERFORMANCE_MAP] = conf[
|
|
172
|
+
dsm_cst.DSMS
|
|
173
|
+
][dsm_key].get("performance_map", None)
|
|
174
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_SOURCE_PC] = conf[
|
|
175
|
+
dsm_cst.DSMS
|
|
176
|
+
][dsm_key].get("contributing_pair", None)
|
|
177
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.DSM_FILLING] = conf[
|
|
178
|
+
dsm_cst.DSMS
|
|
179
|
+
][dsm_key].get("filling", None)
|
|
180
|
+
|
|
181
|
+
# validate
|
|
182
|
+
checker_pc.validate(overloaded_conf[dsm_cst.DSMS][dsm_key])
|
|
183
|
+
|
|
184
|
+
# Modify to absolute path
|
|
185
|
+
if config_dir is not None:
|
|
186
|
+
modify_to_absolute_path(config_dir, overloaded_conf)
|
|
187
|
+
else:
|
|
188
|
+
logging.debug(
|
|
189
|
+
"path of config file was not given,"
|
|
190
|
+
"relative path are not transformed to absolute paths"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
for dsm_key in conf[dsm_cst.DSMS]:
|
|
194
|
+
# check sizes
|
|
195
|
+
check_input_size(
|
|
196
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.INDEX_DSM_ALT],
|
|
197
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][
|
|
198
|
+
cst.INDEX_DSM_CLASSIFICATION
|
|
199
|
+
],
|
|
200
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.INDEX_DSM_COLOR],
|
|
201
|
+
overloaded_conf[dsm_cst.DSMS][dsm_key][cst.INDEX_DSM_MASK],
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Check srtm dir
|
|
205
|
+
sens_inp.check_srtm(
|
|
206
|
+
overloaded_conf[sens_cst.INITIAL_ELEVATION][sens_cst.DEM_PATH]
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
check_phasing(conf[dsm_cst.DSMS])
|
|
210
|
+
|
|
211
|
+
overloaded_conf[sens_cst.LOADERS] = sens_inp.check_loaders(
|
|
212
|
+
conf.get(sens_cst.LOADERS, {})
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
classif_loader = overloaded_conf[sens_cst.LOADERS][
|
|
216
|
+
sens_cst.INPUT_CLASSIFICATION
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
overloaded_conf[sens_cst.FILLING] = sens_inp.check_filling(
|
|
220
|
+
conf.get(sens_cst.FILLING, {}), classif_loader
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
if sens_cst.SENSORS in conf and conf[sens_cst.SENSORS] is not None:
|
|
224
|
+
sens_inp.check_sensors(conf, overloaded_conf, config_dir)
|
|
225
|
+
|
|
226
|
+
return overloaded_conf
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def check_geometry_plugin(conf_inputs, conf_geom_plugin):
|
|
230
|
+
"""
|
|
231
|
+
Check the geometry plugin with inputs
|
|
232
|
+
:param conf_geom_plugin: name of geometry plugin
|
|
233
|
+
:type conf_geom_plugin: str
|
|
234
|
+
:param conf_inputs: checked configuration of inputs
|
|
235
|
+
:type conf_inputs: type
|
|
236
|
+
|
|
237
|
+
:return: geometry plugin with dem
|
|
238
|
+
"""
|
|
239
|
+
if conf_geom_plugin is None:
|
|
240
|
+
conf_geom_plugin = "SharelocGeometry"
|
|
241
|
+
|
|
242
|
+
dem_path = conf_inputs[sens_cst.INITIAL_ELEVATION][sens_cst.DEM_PATH]
|
|
243
|
+
|
|
244
|
+
if dem_path is None:
|
|
245
|
+
return conf_geom_plugin, None
|
|
246
|
+
|
|
247
|
+
# Initialize a geometry plugin with elevation information
|
|
248
|
+
geom_plugin_with_dem_and_geoid = (
|
|
249
|
+
AbstractGeometry( # pylint: disable=abstract-class-instantiated
|
|
250
|
+
conf_geom_plugin,
|
|
251
|
+
dem=dem_path,
|
|
252
|
+
geoid=conf_inputs[sens_cst.INITIAL_ELEVATION][sens_cst.GEOID],
|
|
253
|
+
default_alt=sens_cst.CARS_DEFAULT_ALT,
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
return conf_geom_plugin, geom_plugin_with_dem_and_geoid
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def check_input_size(dsm, classif, color, mask):
|
|
261
|
+
"""
|
|
262
|
+
Check dsm, mask, color, classif given
|
|
263
|
+
|
|
264
|
+
Images must have same size
|
|
265
|
+
|
|
266
|
+
:param dsm: phased dsm path
|
|
267
|
+
:type dsm: str
|
|
268
|
+
:param classif: classif path
|
|
269
|
+
:type classif: str
|
|
270
|
+
:param color: color path
|
|
271
|
+
:type color: str
|
|
272
|
+
:param mask: mask path
|
|
273
|
+
:type mask: str
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
if inputs.rasterio_get_nb_bands(dsm) != 1:
|
|
277
|
+
raise RuntimeError("{} is not mono-band image".format(dsm))
|
|
278
|
+
|
|
279
|
+
for path in [mask, color, classif]:
|
|
280
|
+
if path is not None:
|
|
281
|
+
if inputs.rasterio_get_size(dsm) != inputs.rasterio_get_size(path):
|
|
282
|
+
raise RuntimeError(
|
|
283
|
+
"The image {} and {} "
|
|
284
|
+
"do not have the same size".format(dsm, path)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def modify_to_absolute_path(config_dir, overloaded_conf):
|
|
289
|
+
"""
|
|
290
|
+
Modify input file path to absolute path
|
|
291
|
+
|
|
292
|
+
:param config_dir: directory of the json configuration
|
|
293
|
+
:type config_dir: str
|
|
294
|
+
:param overloaded_conf: overloaded configuration json
|
|
295
|
+
:dict overloaded_conf: dict
|
|
296
|
+
"""
|
|
297
|
+
for dsm_key in overloaded_conf[dsm_cst.DSMS]:
|
|
298
|
+
dsms = overloaded_conf[dsm_cst.DSMS][dsm_key]
|
|
299
|
+
for tag in [
|
|
300
|
+
cst.INDEX_DSM_ALT,
|
|
301
|
+
cst.INDEX_DSM_CLASSIFICATION,
|
|
302
|
+
cst.INDEX_DSM_COLOR,
|
|
303
|
+
cst.INDEX_DSM_MASK,
|
|
304
|
+
]:
|
|
305
|
+
if dsms[tag] is not None:
|
|
306
|
+
dsms[tag] = make_relative_path_absolute(dsms[tag], config_dir)
|
|
307
|
+
|
|
308
|
+
if overloaded_conf[sens_cst.ROI] is not None:
|
|
309
|
+
if isinstance(overloaded_conf[sens_cst.ROI], str):
|
|
310
|
+
overloaded_conf[sens_cst.ROI] = make_relative_path_absolute(
|
|
311
|
+
overloaded_conf[sens_cst.ROI], config_dir
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def check_phasing(dsm_dict):
|
|
316
|
+
"""
|
|
317
|
+
Check if the dsm are phased, and if resolution and epsg code are equivalent
|
|
318
|
+
|
|
319
|
+
:param dsm_dict: list of phased dsm
|
|
320
|
+
:type dsm_dict: dict
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
ref_key = next(iter(dsm_dict))
|
|
324
|
+
ref_epsg = inputs.rasterio_get_epsg_code(dsm_dict[ref_key]["dsm"])
|
|
325
|
+
ref_profile = inputs.rasterio_get_profile(dsm_dict[ref_key]["dsm"])
|
|
326
|
+
ref_transform = list(ref_profile["transform"])
|
|
327
|
+
ref_res_x = ref_transform[0]
|
|
328
|
+
ref_res_y = ref_transform[4]
|
|
329
|
+
ref_bounds = inputs.rasterio_get_bounds(dsm_dict[ref_key]["dsm"])
|
|
330
|
+
|
|
331
|
+
for dsm_key in dsm_dict:
|
|
332
|
+
if dsm_key == ref_key:
|
|
333
|
+
continue
|
|
334
|
+
|
|
335
|
+
epsg = inputs.rasterio_get_epsg_code(dsm_dict[dsm_key]["dsm"])
|
|
336
|
+
profile = inputs.rasterio_get_profile(dsm_dict[ref_key]["dsm"])
|
|
337
|
+
transform = list(profile["transform"])
|
|
338
|
+
res_x = transform[0]
|
|
339
|
+
res_y = transform[4]
|
|
340
|
+
bounds = inputs.rasterio_get_bounds(dsm_dict[dsm_key]["dsm"])
|
|
341
|
+
|
|
342
|
+
if epsg != ref_epsg:
|
|
343
|
+
raise RuntimeError(
|
|
344
|
+
f"EPSG mismatch: DSM {dsm_key} has EPSG {epsg}, "
|
|
345
|
+
f"expected {ref_epsg}."
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if ref_res_x != res_x or ref_res_y != res_y:
|
|
349
|
+
raise RuntimeError(
|
|
350
|
+
f"Resolution mismatch: DSM {dsm_key} has resolution "
|
|
351
|
+
f"{(res_x, res_y)}, expected {(ref_res_x, ref_res_y)}."
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Compare the left_bottom corner
|
|
355
|
+
diff = ref_bounds[0:2] - bounds[0:2]
|
|
356
|
+
resolution = np.array([ref_res_x, -ref_res_y])
|
|
357
|
+
res_ratio = diff / resolution
|
|
358
|
+
|
|
359
|
+
if ~np.all(np.equal(res_ratio, res_ratio.astype(int))) and ~np.all(
|
|
360
|
+
np.equal(1 / res_ratio, (1 / res_ratio).astype(int))
|
|
361
|
+
):
|
|
362
|
+
raise RuntimeError(f"DSM {dsm_key} and {ref_key} are not phased")
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
# pylint: disable=too-many-positional-arguments
|
|
366
|
+
def merge_dsm_infos( # noqa: C901 function is too complex
|
|
367
|
+
dict_path,
|
|
368
|
+
orchestrator,
|
|
369
|
+
roi_poly,
|
|
370
|
+
terrain_tile_size,
|
|
371
|
+
dump_dir=None,
|
|
372
|
+
dsm_file_name=None,
|
|
373
|
+
color_file_name=None,
|
|
374
|
+
classif_file_name=None,
|
|
375
|
+
filling_file_name=None,
|
|
376
|
+
performance_map_file_name=None,
|
|
377
|
+
ambiguity_file_name=None,
|
|
378
|
+
contributing_pair_file_name=None,
|
|
379
|
+
):
|
|
380
|
+
"""
|
|
381
|
+
Merge all the dsms
|
|
382
|
+
|
|
383
|
+
:param dict_path: path of all variables from all dsms
|
|
384
|
+
:type dict_path: dict
|
|
385
|
+
:param orchestrator: orchestrator used
|
|
386
|
+
:param terrain_tile_size: tile size to use
|
|
387
|
+
:type terrain_tile_size: int
|
|
388
|
+
:param dump_dir: output path
|
|
389
|
+
:type dump_dir: str
|
|
390
|
+
:param dsm_file_name: name of the dsm output file
|
|
391
|
+
:type dsm_file_name: str
|
|
392
|
+
:param color_file_name: name of the color output file
|
|
393
|
+
:type color_file_name: str
|
|
394
|
+
:param classif_file_name: name of the classif output file
|
|
395
|
+
:type classif_file_name: str
|
|
396
|
+
:param filling_file_name: name of the filling output file
|
|
397
|
+
:type filling_file_name: str
|
|
398
|
+
:param performance_map_file_name: name of the performance_map output file
|
|
399
|
+
:type performance_map_file_name: str
|
|
400
|
+
:param ambiguity_file_name: name of the ambiguity output file
|
|
401
|
+
:type ambiguity_file_name: str
|
|
402
|
+
:param contributing_pair_file_name: name of contributing_pair output file
|
|
403
|
+
:type contributing_pair_file_name: str
|
|
404
|
+
|
|
405
|
+
:return: raster DSM. CarsDataset contains:
|
|
406
|
+
|
|
407
|
+
- Z x W Delayed tiles. \
|
|
408
|
+
Each tile will be a future xarray Dataset containing:
|
|
409
|
+
|
|
410
|
+
- data : with keys : "hgt", "img", "raster_msk",optional : \
|
|
411
|
+
"n_pts", "pts_in_cell", "hgt_mean", "hgt_stdev",\
|
|
412
|
+
"hgt_inf", "hgt_sup"
|
|
413
|
+
- attrs with keys: "epsg"
|
|
414
|
+
- attributes containing: None
|
|
415
|
+
|
|
416
|
+
:rtype : CarsDataset filled with xr.Dataset
|
|
417
|
+
"""
|
|
418
|
+
|
|
419
|
+
# Create CarsDataset
|
|
420
|
+
terrain_raster = cars_dataset.CarsDataset("arrays", name="rasterization")
|
|
421
|
+
|
|
422
|
+
# find the global bounds of the dataset
|
|
423
|
+
dsm_nodata = None
|
|
424
|
+
epsg = None
|
|
425
|
+
resolution = None
|
|
426
|
+
for index, path in enumerate(dict_path["dsm"]):
|
|
427
|
+
with rasterio.open(path) as src:
|
|
428
|
+
if index == 0:
|
|
429
|
+
bounds = src.bounds
|
|
430
|
+
global_bounds = bounds
|
|
431
|
+
profile = src.profile
|
|
432
|
+
transform = list(profile["transform"])
|
|
433
|
+
res_x = transform[0]
|
|
434
|
+
res_y = transform[4]
|
|
435
|
+
resolution = (res_y, res_x)
|
|
436
|
+
|
|
437
|
+
epsg = src.crs
|
|
438
|
+
|
|
439
|
+
dsm_nodata = src.nodata
|
|
440
|
+
else:
|
|
441
|
+
bounds = src.bounds
|
|
442
|
+
global_bounds = (
|
|
443
|
+
min(bounds[0], global_bounds[0]), # xmin
|
|
444
|
+
min(bounds[1], global_bounds[1]), # ymin
|
|
445
|
+
max(bounds[2], global_bounds[2]), # xmax
|
|
446
|
+
max(bounds[3], global_bounds[3]), # ymax
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
if roi_poly is not None:
|
|
450
|
+
global_bounds = preprocessing.crop_terrain_bounds_with_roi(
|
|
451
|
+
roi_poly,
|
|
452
|
+
global_bounds[0],
|
|
453
|
+
global_bounds[1],
|
|
454
|
+
global_bounds[2],
|
|
455
|
+
global_bounds[3],
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
# Tiling of the dataset
|
|
459
|
+
[xmin, ymin, xmax, ymax] = global_bounds
|
|
460
|
+
|
|
461
|
+
terrain_raster.tiling_grid = tiling.generate_tiling_grid(
|
|
462
|
+
xmin,
|
|
463
|
+
ymin,
|
|
464
|
+
xmax,
|
|
465
|
+
ymax,
|
|
466
|
+
terrain_tile_size,
|
|
467
|
+
terrain_tile_size,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
xsize, ysize = tiling.roi_to_start_and_size(global_bounds, resolution[1])[
|
|
471
|
+
2:
|
|
472
|
+
]
|
|
473
|
+
|
|
474
|
+
# build the tranform of the dataset
|
|
475
|
+
# Generate profile
|
|
476
|
+
geotransform = (
|
|
477
|
+
global_bounds[0],
|
|
478
|
+
resolution[1],
|
|
479
|
+
0.0,
|
|
480
|
+
global_bounds[3],
|
|
481
|
+
0.0,
|
|
482
|
+
-resolution[1],
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
transform = Affine.from_gdal(*geotransform)
|
|
486
|
+
raster_profile = collections.OrderedDict(
|
|
487
|
+
{
|
|
488
|
+
"height": ysize,
|
|
489
|
+
"width": xsize,
|
|
490
|
+
"driver": "GTiff",
|
|
491
|
+
"dtype": "float32",
|
|
492
|
+
"transform": transform,
|
|
493
|
+
"crs": "EPSG:{}".format(epsg),
|
|
494
|
+
"tiled": True,
|
|
495
|
+
"no_data": dsm_nodata,
|
|
496
|
+
}
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
# Get sources pc
|
|
500
|
+
full_sources_band_descriptions = None
|
|
501
|
+
if cst.DSM_SOURCE_PC in list(dict_path.keys()):
|
|
502
|
+
full_sources_band_descriptions = []
|
|
503
|
+
for source_pc in dict_path[cst.DSM_SOURCE_PC]:
|
|
504
|
+
full_sources_band_descriptions += list(
|
|
505
|
+
inputs.get_descriptions_bands(source_pc)
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
# remove copies
|
|
509
|
+
full_sources_band_descriptions = list(
|
|
510
|
+
dict.fromkeys(full_sources_band_descriptions)
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Setup dump directory
|
|
514
|
+
if dump_dir is not None:
|
|
515
|
+
out_dump_dir = dump_dir
|
|
516
|
+
safe_makedirs(out_dump_dir)
|
|
517
|
+
else:
|
|
518
|
+
out_dump_dir = orchestrator.out_dir
|
|
519
|
+
|
|
520
|
+
if dsm_file_name is not None:
|
|
521
|
+
safe_makedirs(os.path.dirname(dsm_file_name))
|
|
522
|
+
|
|
523
|
+
# Save all file that are in inputs
|
|
524
|
+
for key in dict_path.keys():
|
|
525
|
+
if key in (cst.DSM_ALT, cst.DSM_COLOR, cst.DSM_WEIGHTS_SUM):
|
|
526
|
+
option = False
|
|
527
|
+
else:
|
|
528
|
+
option = True
|
|
529
|
+
|
|
530
|
+
if key == cst.DSM_ALT and dsm_file_name is not None:
|
|
531
|
+
out_file_name = dsm_file_name
|
|
532
|
+
elif key == cst.DSM_COLOR and color_file_name is not None:
|
|
533
|
+
out_file_name = color_file_name
|
|
534
|
+
elif key == cst.DSM_CLASSIF and classif_file_name is not None:
|
|
535
|
+
out_file_name = classif_file_name
|
|
536
|
+
elif key == cst.DSM_FILLING and filling_file_name is not None:
|
|
537
|
+
out_file_name = filling_file_name
|
|
538
|
+
elif (
|
|
539
|
+
key == cst.DSM_PERFORMANCE_MAP
|
|
540
|
+
and performance_map_file_name is not None
|
|
541
|
+
):
|
|
542
|
+
out_file_name = performance_map_file_name
|
|
543
|
+
elif key == cst.DSM_AMBIGUITY and ambiguity_file_name is not None:
|
|
544
|
+
out_file_name = ambiguity_file_name
|
|
545
|
+
elif (
|
|
546
|
+
key == cst.DSM_SOURCE_PC and contributing_pair_file_name is not None
|
|
547
|
+
):
|
|
548
|
+
out_file_name = contributing_pair_file_name
|
|
549
|
+
else:
|
|
550
|
+
out_file_name = os.path.join(out_dump_dir, key + ".tif")
|
|
551
|
+
|
|
552
|
+
orchestrator.add_to_save_lists(
|
|
553
|
+
out_file_name,
|
|
554
|
+
key,
|
|
555
|
+
terrain_raster,
|
|
556
|
+
dtype=inputs.rasterio_get_dtype(dict_path[key][0]),
|
|
557
|
+
nodata=inputs.rasterio_get_nodata(dict_path[key][0]),
|
|
558
|
+
cars_ds_name=key,
|
|
559
|
+
optional_data=option,
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
[saving_info] = orchestrator.get_saving_infos([terrain_raster])
|
|
563
|
+
logging.info(
|
|
564
|
+
"Merge DSM info in {} x {} tiles".format(
|
|
565
|
+
terrain_raster.shape[0], terrain_raster.shape[1]
|
|
566
|
+
)
|
|
567
|
+
)
|
|
568
|
+
for col in range(terrain_raster.shape[1]):
|
|
569
|
+
for row in range(terrain_raster.shape[0]):
|
|
570
|
+
# update saving infos for potential replacement
|
|
571
|
+
full_saving_info = ocht.update_saving_infos(
|
|
572
|
+
saving_info, row=row, col=col
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
# Delayed call to dsm merging operations using all
|
|
576
|
+
terrain_raster[row, col] = orchestrator.cluster.create_task(
|
|
577
|
+
dsm_merging_wrapper, nout=1
|
|
578
|
+
)(
|
|
579
|
+
dict_path,
|
|
580
|
+
terrain_raster.tiling_grid[row, col],
|
|
581
|
+
resolution,
|
|
582
|
+
raster_profile,
|
|
583
|
+
full_saving_info,
|
|
584
|
+
full_sources_band_descriptions,
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
return terrain_raster
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def dsm_merging_wrapper( # pylint: disable=too-many-positional-arguments # noqa C901
|
|
591
|
+
dict_path,
|
|
592
|
+
tile_bounds,
|
|
593
|
+
resolution,
|
|
594
|
+
profile,
|
|
595
|
+
saving_info=None,
|
|
596
|
+
full_sources_band_descriptions=None,
|
|
597
|
+
):
|
|
598
|
+
"""
|
|
599
|
+
Merge all the variables
|
|
600
|
+
|
|
601
|
+
:param dict_path: path of all variables from all dsms
|
|
602
|
+
:type dict_path: dict
|
|
603
|
+
:param tile_bounds: list of tiles coordinates
|
|
604
|
+
:type tile_bounds: list
|
|
605
|
+
:param resolution: resolution of the dsms
|
|
606
|
+
:type resolution: list
|
|
607
|
+
:param profile: profile of the global dsm
|
|
608
|
+
:type profile: OrderedDict
|
|
609
|
+
:saving_info: the saving infos
|
|
610
|
+
"""
|
|
611
|
+
|
|
612
|
+
# create the tile dataset
|
|
613
|
+
x_value = np.arange(tile_bounds[0], tile_bounds[1], resolution[1])
|
|
614
|
+
y_value = np.arange(tile_bounds[2], tile_bounds[3], resolution[1])
|
|
615
|
+
height = len(y_value)
|
|
616
|
+
width = len(x_value)
|
|
617
|
+
|
|
618
|
+
dataset = xr.Dataset(
|
|
619
|
+
data_vars={},
|
|
620
|
+
coords={
|
|
621
|
+
"y": y_value,
|
|
622
|
+
"x": x_value,
|
|
623
|
+
},
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
# calculate the bounds intersection between each path
|
|
627
|
+
list_intersection = []
|
|
628
|
+
|
|
629
|
+
for path in dict_path["dsm"]:
|
|
630
|
+
with rasterio.open(path) as src:
|
|
631
|
+
intersect_bounds = (
|
|
632
|
+
max(tile_bounds[0], src.bounds.left), # xmin
|
|
633
|
+
max(tile_bounds[2], src.bounds.bottom), # ymin
|
|
634
|
+
min(tile_bounds[1], src.bounds.right), # xmax
|
|
635
|
+
min(tile_bounds[3], src.bounds.top), # ymax
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
if (
|
|
639
|
+
intersect_bounds[0] < intersect_bounds[2]
|
|
640
|
+
and intersect_bounds[1] < intersect_bounds[3]
|
|
641
|
+
):
|
|
642
|
+
list_intersection.append(intersect_bounds)
|
|
643
|
+
else:
|
|
644
|
+
list_intersection.append("no intersection")
|
|
645
|
+
|
|
646
|
+
# Update the data
|
|
647
|
+
for key in dict_path.keys():
|
|
648
|
+
# Choose the method regarding the variable
|
|
649
|
+
if key in [cst.DSM_NB_PTS, cst.DSM_NB_PTS_IN_CELL]:
|
|
650
|
+
method = "sum"
|
|
651
|
+
elif key in [
|
|
652
|
+
cst.DSM_FILLING,
|
|
653
|
+
cst.DSM_CLASSIF,
|
|
654
|
+
cst.DSM_SOURCE_PC,
|
|
655
|
+
]:
|
|
656
|
+
method = "bool"
|
|
657
|
+
else:
|
|
658
|
+
method = "basic"
|
|
659
|
+
|
|
660
|
+
# take band description information
|
|
661
|
+
band_descriptions = list(
|
|
662
|
+
inputs.get_descriptions_bands(dict_path[key][0])
|
|
663
|
+
)
|
|
664
|
+
nb_bands = inputs.rasterio_get_nb_bands(dict_path[key][0])
|
|
665
|
+
if len(band_descriptions) == 0:
|
|
666
|
+
band_descriptions = []
|
|
667
|
+
elif (
|
|
668
|
+
key
|
|
669
|
+
in [
|
|
670
|
+
cst.DSM_COLOR,
|
|
671
|
+
cst.DSM_SOURCE_PC,
|
|
672
|
+
cst.DSM_CLASSIF,
|
|
673
|
+
cst.DSM_FILLING,
|
|
674
|
+
]
|
|
675
|
+
and None in band_descriptions
|
|
676
|
+
):
|
|
677
|
+
band_descriptions = [
|
|
678
|
+
str(current_band) for current_band in range(nb_bands)
|
|
679
|
+
]
|
|
680
|
+
|
|
681
|
+
# Define the dimension of the data in the dataset
|
|
682
|
+
if key == cst.DSM_COLOR:
|
|
683
|
+
dataset.coords[cst.BAND_IM] = (cst.BAND_IM, band_descriptions)
|
|
684
|
+
dim = [cst.BAND_IM, cst.Y, cst.X]
|
|
685
|
+
elif key == cst.DSM_SOURCE_PC:
|
|
686
|
+
dataset.coords[cst.BAND_SOURCE_PC] = (
|
|
687
|
+
cst.BAND_SOURCE_PC,
|
|
688
|
+
full_sources_band_descriptions,
|
|
689
|
+
)
|
|
690
|
+
dim = [cst.BAND_SOURCE_PC, cst.Y, cst.X]
|
|
691
|
+
elif key == cst.DSM_CLASSIF:
|
|
692
|
+
dataset.coords[cst.BAND_CLASSIF] = (
|
|
693
|
+
cst.BAND_CLASSIF,
|
|
694
|
+
band_descriptions,
|
|
695
|
+
)
|
|
696
|
+
dim = [cst.BAND_CLASSIF, cst.Y, cst.X]
|
|
697
|
+
elif key == cst.DSM_FILLING:
|
|
698
|
+
dataset.coords[cst.BAND_FILLING] = (
|
|
699
|
+
cst.BAND_FILLING,
|
|
700
|
+
band_descriptions,
|
|
701
|
+
)
|
|
702
|
+
dim = [cst.BAND_FILLING, cst.Y, cst.X]
|
|
703
|
+
else:
|
|
704
|
+
dim = [cst.Y, cst.X]
|
|
705
|
+
|
|
706
|
+
# Update data
|
|
707
|
+
if key == cst.DSM_ALT:
|
|
708
|
+
# Update dsm_value and weights once
|
|
709
|
+
value, weights = assemblage(
|
|
710
|
+
dict_path[key],
|
|
711
|
+
dict_path[cst.DSM_WEIGHTS_SUM],
|
|
712
|
+
method,
|
|
713
|
+
list_intersection,
|
|
714
|
+
tile_bounds,
|
|
715
|
+
height,
|
|
716
|
+
width,
|
|
717
|
+
band_descriptions,
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
dataset[key] = (dim, value)
|
|
721
|
+
dataset[cst.DSM_WEIGHTS_SUM] = (dim, weights)
|
|
722
|
+
elif key == cst.DSM_SOURCE_PC:
|
|
723
|
+
value, _ = assemblage(
|
|
724
|
+
dict_path[key],
|
|
725
|
+
dict_path[cst.DSM_WEIGHTS_SUM],
|
|
726
|
+
method,
|
|
727
|
+
list_intersection,
|
|
728
|
+
tile_bounds,
|
|
729
|
+
height,
|
|
730
|
+
width,
|
|
731
|
+
full_sources_band_descriptions,
|
|
732
|
+
merge_sources=True,
|
|
733
|
+
)
|
|
734
|
+
dataset[key] = (dim, value)
|
|
735
|
+
elif key != cst.DSM_WEIGHTS_SUM:
|
|
736
|
+
# Update other variables
|
|
737
|
+
value, _ = assemblage(
|
|
738
|
+
dict_path[key],
|
|
739
|
+
dict_path[cst.DSM_WEIGHTS_SUM],
|
|
740
|
+
method,
|
|
741
|
+
list_intersection,
|
|
742
|
+
tile_bounds,
|
|
743
|
+
height,
|
|
744
|
+
width,
|
|
745
|
+
band_descriptions,
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
dataset[key] = (dim, value)
|
|
749
|
+
|
|
750
|
+
# add performance map classes
|
|
751
|
+
if key == cst.DSM_PERFORMANCE_MAP:
|
|
752
|
+
perf_map_classes = inputs.rasterio_get_tags(dict_path[key][0])[
|
|
753
|
+
"CLASSES"
|
|
754
|
+
]
|
|
755
|
+
dataset.attrs[cst.RIO_TAG_PERFORMANCE_MAP_CLASSES] = (
|
|
756
|
+
perf_map_classes
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
# Define the tile transform
|
|
760
|
+
bounds = [tile_bounds[0], tile_bounds[2], tile_bounds[1], tile_bounds[3]]
|
|
761
|
+
xstart, ystart, xsize, ysize = tiling.roi_to_start_and_size(
|
|
762
|
+
bounds, resolution[1]
|
|
763
|
+
)
|
|
764
|
+
transform = rasterio.Affine(*profile["transform"][0:6])
|
|
765
|
+
|
|
766
|
+
row_pix_pos, col_pix_pos = rasterio.transform.AffineTransformer(
|
|
767
|
+
transform
|
|
768
|
+
).rowcol(xstart, ystart)
|
|
769
|
+
window = [
|
|
770
|
+
row_pix_pos,
|
|
771
|
+
row_pix_pos + ysize,
|
|
772
|
+
col_pix_pos,
|
|
773
|
+
col_pix_pos + xsize,
|
|
774
|
+
]
|
|
775
|
+
|
|
776
|
+
window = cars_dataset.window_array_to_dict(window)
|
|
777
|
+
|
|
778
|
+
# Fill dataset
|
|
779
|
+
cars_dataset.fill_dataset(
|
|
780
|
+
dataset,
|
|
781
|
+
saving_info=saving_info,
|
|
782
|
+
window=window,
|
|
783
|
+
profile=profile,
|
|
784
|
+
overlaps=None,
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
return dataset
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
def assemblage( # pylint: disable=too-many-positional-arguments
|
|
791
|
+
out,
|
|
792
|
+
current_weights,
|
|
793
|
+
method,
|
|
794
|
+
intersect_bounds,
|
|
795
|
+
tile_bounds,
|
|
796
|
+
height,
|
|
797
|
+
width,
|
|
798
|
+
band_descriptions=None,
|
|
799
|
+
merge_sources=False,
|
|
800
|
+
):
|
|
801
|
+
"""
|
|
802
|
+
Update data
|
|
803
|
+
|
|
804
|
+
:param out: the data to update
|
|
805
|
+
:type out: list of path
|
|
806
|
+
:param current_weights: the current weights of the data
|
|
807
|
+
:type current_weights: list of path
|
|
808
|
+
:param method: the method used to update the data
|
|
809
|
+
:type method: str
|
|
810
|
+
:param intersect_bounds: the bounds intersection
|
|
811
|
+
:type intersect_bounds: list of bounds
|
|
812
|
+
:param height: the height of the tile
|
|
813
|
+
:type height: int
|
|
814
|
+
:param width: the width of the tile
|
|
815
|
+
:type width: int
|
|
816
|
+
:param band_descriptions: the band description of the data
|
|
817
|
+
:type band_descriptions: str of list
|
|
818
|
+
:param merge_sources: merge source pc, using full band_description
|
|
819
|
+
:type merge_sources: bool
|
|
820
|
+
|
|
821
|
+
"""
|
|
822
|
+
# Initialize the tile
|
|
823
|
+
if merge_sources:
|
|
824
|
+
nb_bands = len(band_descriptions)
|
|
825
|
+
else:
|
|
826
|
+
nb_bands = inputs.rasterio_get_nb_bands(out[0])
|
|
827
|
+
|
|
828
|
+
dtype = inputs.rasterio_get_dtype(out[0])
|
|
829
|
+
nodata = inputs.rasterio_get_nodata(out[0])
|
|
830
|
+
|
|
831
|
+
if band_descriptions[0] is not None:
|
|
832
|
+
tile = np.full((nb_bands, height, width), nodata, dtype=dtype)
|
|
833
|
+
else:
|
|
834
|
+
tile = np.full((height, width), nodata, dtype=dtype)
|
|
835
|
+
|
|
836
|
+
# Initialize the weights
|
|
837
|
+
weights = np.full((height, width), 0, dtype=dtype)
|
|
838
|
+
|
|
839
|
+
for idx, path in enumerate(out):
|
|
840
|
+
with (
|
|
841
|
+
rasterio.open(path) as src,
|
|
842
|
+
rasterio.open(current_weights[idx]) as drt,
|
|
843
|
+
):
|
|
844
|
+
if intersect_bounds[idx] != "no intersection":
|
|
845
|
+
# Build the window
|
|
846
|
+
window = from_bounds(
|
|
847
|
+
*intersect_bounds[idx], transform=src.transform
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
# Extract the data
|
|
851
|
+
current_nb_bands = src.count
|
|
852
|
+
if current_nb_bands > 1:
|
|
853
|
+
data = src.read(window=window)
|
|
854
|
+
_, rows, cols = data.shape
|
|
855
|
+
else:
|
|
856
|
+
data = src.read(1, window=window)
|
|
857
|
+
rows, cols = data.shape
|
|
858
|
+
|
|
859
|
+
indexes = list(range(current_nb_bands))
|
|
860
|
+
if merge_sources:
|
|
861
|
+
# Extract current band description
|
|
862
|
+
current_band_descriptions = list(src.descriptions)
|
|
863
|
+
# Get position
|
|
864
|
+
indexes = []
|
|
865
|
+
for current_band in current_band_descriptions:
|
|
866
|
+
indexes.append(band_descriptions.index(current_band))
|
|
867
|
+
|
|
868
|
+
current_weights_window = drt.read(1, window=window)
|
|
869
|
+
|
|
870
|
+
# Calculate the x and y offset because the current_data
|
|
871
|
+
# doesn't equal to the entire tile
|
|
872
|
+
x_offset = int(
|
|
873
|
+
(intersect_bounds[idx][0] - tile_bounds[0])
|
|
874
|
+
/ np.abs(src.res[0])
|
|
875
|
+
)
|
|
876
|
+
y_offset = int(
|
|
877
|
+
(tile_bounds[3] - intersect_bounds[idx][3])
|
|
878
|
+
/ np.abs(src.res[1])
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
if cols > 0 and rows > 0:
|
|
882
|
+
tab_x = np.arange(x_offset, x_offset + cols)
|
|
883
|
+
|
|
884
|
+
tab_y = np.arange(y_offset, y_offset + rows)
|
|
885
|
+
|
|
886
|
+
# Update data
|
|
887
|
+
if band_descriptions[0] is not None:
|
|
888
|
+
|
|
889
|
+
tile[np.ix_(indexes, tab_y, tab_x)] = np.reshape(
|
|
890
|
+
update_data(
|
|
891
|
+
tile[np.ix_(indexes, tab_y, tab_x)],
|
|
892
|
+
data,
|
|
893
|
+
current_weights_window,
|
|
894
|
+
weights[np.ix_(tab_y, tab_x)],
|
|
895
|
+
nodata,
|
|
896
|
+
method=method,
|
|
897
|
+
),
|
|
898
|
+
tile[np.ix_(indexes, tab_y, tab_x)].shape,
|
|
899
|
+
)
|
|
900
|
+
else:
|
|
901
|
+
tile[np.ix_(tab_y, tab_x)] = np.reshape(
|
|
902
|
+
update_data(
|
|
903
|
+
tile[np.ix_(tab_y, tab_x)],
|
|
904
|
+
data,
|
|
905
|
+
current_weights_window,
|
|
906
|
+
weights[np.ix_(tab_y, tab_x)],
|
|
907
|
+
nodata,
|
|
908
|
+
method=method,
|
|
909
|
+
),
|
|
910
|
+
tile[np.ix_(tab_y, tab_x)].shape,
|
|
911
|
+
)
|
|
912
|
+
|
|
913
|
+
# Update weights
|
|
914
|
+
weights[np.ix_(tab_y, tab_x)] = update_weights(
|
|
915
|
+
weights[np.ix_(tab_y, tab_x)], current_weights_window
|
|
916
|
+
)
|
|
917
|
+
|
|
918
|
+
return tile, weights
|