cars 1.0.0rc1__cp312-cp312-manylinux_2_17_i686.manylinux2014_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-312-i386-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 +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 +200 -0
- cars-1.0.0rc1.dist-info/WHEEL +6 -0
- cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
this module contains tools checking bulldozer parameter used for memory
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
import shutil
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def can_allocate_shared_memory(nb_go=0.8):
|
|
30
|
+
"""
|
|
31
|
+
Check if can allocate shared memory
|
|
32
|
+
"""
|
|
33
|
+
# TODO remove when Eoascale not in bulldozer anymore
|
|
34
|
+
try:
|
|
35
|
+
# 1 Go = 1024 * 1024 * 1024 octets
|
|
36
|
+
shm_stats = shutil.disk_usage("/dev/shm")
|
|
37
|
+
available_bytes = shm_stats.free
|
|
38
|
+
required_bytes = nb_go * 1024 * 1024 * 1024
|
|
39
|
+
|
|
40
|
+
if available_bytes > required_bytes:
|
|
41
|
+
log_message = "Can allocate shared memory."
|
|
42
|
+
return True, log_message
|
|
43
|
+
|
|
44
|
+
log_message = (
|
|
45
|
+
"Cannot allocate shared memory: {} Go available"
|
|
46
|
+
"If CARS runs on docker, use --shm-size option "
|
|
47
|
+
"on docker run command. For instance: --shm-size=10Go".format(
|
|
48
|
+
int(available_bytes / (1024 * 1024 * 1024))
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
return False, log_message
|
|
52
|
+
except Exception:
|
|
53
|
+
# Possibly on windows
|
|
54
|
+
log_message = "Crash on shared memory check."
|
|
55
|
+
return True, log_message
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
this module contains tools for the dem generation
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import contextlib
|
|
26
|
+
import logging
|
|
27
|
+
|
|
28
|
+
# Standard imports
|
|
29
|
+
import os
|
|
30
|
+
|
|
31
|
+
# Third party imports
|
|
32
|
+
import yaml
|
|
33
|
+
from bulldozer.pipeline.bulldozer_pipeline import dsm_to_dtm
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def launch_bulldozer(
|
|
37
|
+
input_dem,
|
|
38
|
+
output_dir,
|
|
39
|
+
cars_orchestrator,
|
|
40
|
+
max_object_size,
|
|
41
|
+
):
|
|
42
|
+
"""
|
|
43
|
+
Launch bulldozer on a DEM to smooth it
|
|
44
|
+
|
|
45
|
+
:param input_dem: path of DEM to reverse
|
|
46
|
+
:type input_dem: str
|
|
47
|
+
:param output_dir: directory where bulldozer output is dumped
|
|
48
|
+
:type output_dir: str
|
|
49
|
+
:param cars_orchestrator: orchestrator of the whole pipeline
|
|
50
|
+
(used to get number of workers)
|
|
51
|
+
:type cars_orchestrator: Orchestrator
|
|
52
|
+
:param max_object_size: bulldozer parameter "max_object_size"
|
|
53
|
+
:type max_object_size: int
|
|
54
|
+
"""
|
|
55
|
+
bull_conf_path = os.path.join(
|
|
56
|
+
os.path.dirname(__file__), "bulldozer_config/base_config.yaml"
|
|
57
|
+
)
|
|
58
|
+
with open(bull_conf_path, "r", encoding="utf8") as bull_conf_file:
|
|
59
|
+
bull_conf = yaml.safe_load(bull_conf_file)
|
|
60
|
+
|
|
61
|
+
bull_conf["dsm_path"] = input_dem
|
|
62
|
+
bull_conf["output_dir"] = output_dir
|
|
63
|
+
if cars_orchestrator is not None:
|
|
64
|
+
if (
|
|
65
|
+
cars_orchestrator.get_conf()["mode"] == "multiprocessing"
|
|
66
|
+
or cars_orchestrator.get_conf()["mode"] == "local_dask"
|
|
67
|
+
):
|
|
68
|
+
bull_conf["nb_max_workers"] = cars_orchestrator.get_conf()[
|
|
69
|
+
"nb_workers"
|
|
70
|
+
]
|
|
71
|
+
else:
|
|
72
|
+
bull_conf["nb_max_workers"] = 4
|
|
73
|
+
bull_conf["max_object_size"] = max_object_size
|
|
74
|
+
|
|
75
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
76
|
+
bull_conf_path = os.path.join(output_dir, "bulldozer_config.yaml")
|
|
77
|
+
with open(bull_conf_path, "w", encoding="utf8") as bull_conf_file:
|
|
78
|
+
yaml.dump(bull_conf, bull_conf_file)
|
|
79
|
+
|
|
80
|
+
output_dem = os.path.join(bull_conf["output_dir"], "dtm.tif")
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
try:
|
|
84
|
+
# suppress prints in bulldozer by redirecting stdout&stderr
|
|
85
|
+
with open(os.devnull, "w", encoding="utf8") as devnull:
|
|
86
|
+
with (
|
|
87
|
+
contextlib.redirect_stdout(devnull),
|
|
88
|
+
contextlib.redirect_stderr(devnull),
|
|
89
|
+
):
|
|
90
|
+
dsm_to_dtm(bull_conf_path)
|
|
91
|
+
except Exception:
|
|
92
|
+
logging.info("Bulldozer failed on its first execution. Retrying")
|
|
93
|
+
# suppress prints in bulldozer by redirecting stdout&stderr
|
|
94
|
+
with open(os.devnull, "w", encoding="utf8") as devnull:
|
|
95
|
+
with (
|
|
96
|
+
contextlib.redirect_stdout(devnull),
|
|
97
|
+
contextlib.redirect_stderr(devnull),
|
|
98
|
+
):
|
|
99
|
+
dsm_to_dtm(bull_conf_path)
|
|
100
|
+
except Exception:
|
|
101
|
+
logging.error(
|
|
102
|
+
"Bulldozer failed on its second execution."
|
|
103
|
+
+ " The DSM could not be smoothed."
|
|
104
|
+
)
|
|
105
|
+
output_dem = None
|
|
106
|
+
|
|
107
|
+
return output_dem
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
this module contains the dem generation constants.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
DEM_MEDIAN = "dem_median"
|
|
27
|
+
DEM_MIN = "dem_min"
|
|
28
|
+
DEM_MAX = "dem_max"
|
|
29
|
+
|
|
30
|
+
DEM_MEDIAN_PATH = "dem_median_path"
|
|
31
|
+
DEM_MIN_PATH = "dem_min_path"
|
|
32
|
+
DEM_MAX_PATH = "dem_max_path"
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
this module contains tools for the dem generation
|
|
23
|
+
"""
|
|
24
|
+
import contextlib
|
|
25
|
+
import logging
|
|
26
|
+
import os
|
|
27
|
+
|
|
28
|
+
import numpy as np
|
|
29
|
+
import rasterio as rio
|
|
30
|
+
import xdem
|
|
31
|
+
|
|
32
|
+
# Third-party imports
|
|
33
|
+
from affine import Affine
|
|
34
|
+
from rasterio.coords import BoundingBox
|
|
35
|
+
from rasterio.enums import Resampling
|
|
36
|
+
from rasterio.warp import calculate_default_transform, reproject
|
|
37
|
+
from scipy.ndimage import median_filter
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def fit_initial_elevation_on_dem_median(
|
|
41
|
+
dem_to_fit_path: str, dem_ref_path: str, dem_out_path: str
|
|
42
|
+
):
|
|
43
|
+
"""
|
|
44
|
+
Coregistrates the two DEMs given then saves the result.
|
|
45
|
+
The initial elevation will be cropped to reduce computation costs.
|
|
46
|
+
Returns the transformation applied.
|
|
47
|
+
|
|
48
|
+
:param dem_to_fit_path: Path to the dem to be fitted
|
|
49
|
+
:type dem_to_fit_path: str
|
|
50
|
+
:param dem_ref_path: Path to the dem to fit onto
|
|
51
|
+
:type dem_ref_path: str
|
|
52
|
+
:param dem_out_path: Path to save the resulting dem into
|
|
53
|
+
:type dem_out_path: str
|
|
54
|
+
|
|
55
|
+
:return: coregistration transformation applied
|
|
56
|
+
:rtype: dict
|
|
57
|
+
"""
|
|
58
|
+
# suppress all outputs of xdem
|
|
59
|
+
with open(os.devnull, "w", encoding="utf8") as devnull:
|
|
60
|
+
with (
|
|
61
|
+
contextlib.redirect_stdout(devnull),
|
|
62
|
+
contextlib.redirect_stderr(devnull),
|
|
63
|
+
):
|
|
64
|
+
|
|
65
|
+
# load DEMs
|
|
66
|
+
dem_to_fit = xdem.DEM(dem_to_fit_path)
|
|
67
|
+
dem_ref = xdem.DEM(dem_ref_path)
|
|
68
|
+
|
|
69
|
+
# get the crs needed to reproject the data
|
|
70
|
+
crs_out = dem_ref.crs
|
|
71
|
+
crs_metric = dem_ref.get_metric_crs()
|
|
72
|
+
|
|
73
|
+
# Crop dem_to_fit with dem_ref to reduce
|
|
74
|
+
# computation costs.
|
|
75
|
+
bbox = dem_ref.bounds
|
|
76
|
+
bbox = add_margin(bbox)
|
|
77
|
+
dem_to_fit = dem_to_fit.crop(bbox).reproject(crs=crs_metric)
|
|
78
|
+
# Reproject dem_ref to dem_to_fit resolution to reduce
|
|
79
|
+
# computation costs
|
|
80
|
+
dem_ref = dem_ref.reproject(dem_to_fit)
|
|
81
|
+
bbox = dem_ref.bounds
|
|
82
|
+
bbox = add_margin(bbox)
|
|
83
|
+
|
|
84
|
+
coreg_pipeline = xdem.coreg.NuthKaab()
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
# fit dem_to_fit onto dem_ref, crop it, then reproject it
|
|
88
|
+
# set a random state to always get the same results
|
|
89
|
+
fit_dem = (
|
|
90
|
+
coreg_pipeline.fit_and_apply(
|
|
91
|
+
dem_ref, dem_to_fit, random_state=0
|
|
92
|
+
)
|
|
93
|
+
.crop(bbox)
|
|
94
|
+
.reproject(crs=crs_out)
|
|
95
|
+
)
|
|
96
|
+
# save the results
|
|
97
|
+
fit_dem.save(dem_out_path)
|
|
98
|
+
coreg_offsets = coreg_pipeline.meta["outputs"]["affine"]
|
|
99
|
+
except (ValueError, AssertionError, TypeError):
|
|
100
|
+
logging.warning(
|
|
101
|
+
"xDEM coregistration failed. This can happen when sensor "
|
|
102
|
+
"images are too small. No shift will be applied on DEM"
|
|
103
|
+
)
|
|
104
|
+
coreg_offsets = None
|
|
105
|
+
|
|
106
|
+
return coreg_offsets
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def add_margin(bbox, ratio=1):
|
|
110
|
+
"""
|
|
111
|
+
Add margin to a bounding box
|
|
112
|
+
:param bbox: input bounding box
|
|
113
|
+
:type bbox: rasterio.coords.BoundingBox
|
|
114
|
+
:param ratio: factor of bbox size to add to each side of bbox
|
|
115
|
+
:type ratio: float
|
|
116
|
+
|
|
117
|
+
:return: bounding box with margins
|
|
118
|
+
:rtype: rasterio.coords.BoundingBox
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
assert bbox.left < bbox.right
|
|
122
|
+
assert bbox.bottom < bbox.top
|
|
123
|
+
width = bbox.right - bbox.left
|
|
124
|
+
height = bbox.top - bbox.bottom
|
|
125
|
+
new_left = bbox.left - ratio * width
|
|
126
|
+
new_right = bbox.right + ratio * width
|
|
127
|
+
new_bottom = bbox.bottom - ratio * height
|
|
128
|
+
new_top = bbox.top + ratio * height
|
|
129
|
+
new_bbox = BoundingBox(new_left, new_bottom, new_right, new_top)
|
|
130
|
+
except AssertionError:
|
|
131
|
+
logging.warning("Bounding box {} cannot be read".format(bbox))
|
|
132
|
+
new_bbox = bbox
|
|
133
|
+
return new_bbox
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def compute_stats(diff):
|
|
137
|
+
"""
|
|
138
|
+
Compute and display statistics of difference between two DEM :
|
|
139
|
+
Minimum, median, percentiles and maximum
|
|
140
|
+
|
|
141
|
+
:param diff: altimetric difference between two DEM
|
|
142
|
+
:type diff: numpy.array
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
mini = ("Min", np.nanmin(diff))
|
|
146
|
+
median = ("Median", np.nanmedian(diff))
|
|
147
|
+
p90 = ("p90", np.nanpercentile(diff, 90))
|
|
148
|
+
p95 = ("p95", np.nanpercentile(diff, 95))
|
|
149
|
+
p99 = ("p99", np.nanpercentile(diff, 99))
|
|
150
|
+
maxi = ("Max", np.nanmax(diff))
|
|
151
|
+
logging.info( # pylint: disable=logging-fstring-interpolation
|
|
152
|
+
f"| {mini[0]:6} | {median[0]:6} | {p90[0]:6} | "
|
|
153
|
+
f"{p95[0]:6} | {p99[0]:6} | {maxi[0]:6} |"
|
|
154
|
+
)
|
|
155
|
+
logging.info( # pylint: disable=logging-fstring-interpolation
|
|
156
|
+
f"| {mini[1]:6.2f} | {median[1]:6.2f} | {p90[1]:6.2f} | "
|
|
157
|
+
f"{p95[1]:6.2f} | {p99[1]:6.2f} | {maxi[1]:6.2f} |"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def edit_transform(input_dem, resolution=None, transform=None):
|
|
162
|
+
"""
|
|
163
|
+
Change transform of an image
|
|
164
|
+
:param input_res: path of image
|
|
165
|
+
:type input_dem: str
|
|
166
|
+
:param resolution: image resolution for new transform to apply
|
|
167
|
+
:type resolution: float
|
|
168
|
+
:param transform: new transform to apply if resolution is not given
|
|
169
|
+
:type transform: affine.Affine
|
|
170
|
+
"""
|
|
171
|
+
if resolution is not None:
|
|
172
|
+
if transform is None:
|
|
173
|
+
transform = Affine.from_gdal(0, resolution, 0, 0, 0, resolution)
|
|
174
|
+
else:
|
|
175
|
+
raise ValueError(
|
|
176
|
+
"Function edit_transform take resolution or "
|
|
177
|
+
"transform as parameter but not both"
|
|
178
|
+
)
|
|
179
|
+
with rio.open(input_dem, "r+") as in_dem:
|
|
180
|
+
previous_transform = in_dem.transform
|
|
181
|
+
in_dem.transform = transform
|
|
182
|
+
return previous_transform
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def reverse_dem(input_dem):
|
|
186
|
+
"""
|
|
187
|
+
Compute the opposite of a DEM :
|
|
188
|
+
Altitudes sign is changed
|
|
189
|
+
|
|
190
|
+
:param input_dem: path of DEM to reverse
|
|
191
|
+
:type input_dem: str
|
|
192
|
+
"""
|
|
193
|
+
with rio.open(input_dem, "r") as in_dem:
|
|
194
|
+
data = in_dem.read()
|
|
195
|
+
metadata = in_dem.meta
|
|
196
|
+
nodata = in_dem.nodata
|
|
197
|
+
with rio.open(input_dem, "w", **metadata) as out_dem:
|
|
198
|
+
out_dem.write(-data)
|
|
199
|
+
out_dem.nodata = -nodata
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def downsample_dem(
|
|
203
|
+
input_dem,
|
|
204
|
+
scale,
|
|
205
|
+
interpolator,
|
|
206
|
+
median_filter_size=None,
|
|
207
|
+
default_alt=0,
|
|
208
|
+
):
|
|
209
|
+
"""
|
|
210
|
+
Downsample median DEM with median resampling
|
|
211
|
+
|
|
212
|
+
:param input_dem: path of DEM to downsample (only one band)
|
|
213
|
+
:type input_dem: str
|
|
214
|
+
"""
|
|
215
|
+
with rio.open(input_dem) as in_dem:
|
|
216
|
+
data = in_dem.read(1)
|
|
217
|
+
metadata = in_dem.meta
|
|
218
|
+
src_transform = in_dem.transform
|
|
219
|
+
width = in_dem.width
|
|
220
|
+
height = in_dem.height
|
|
221
|
+
crs = in_dem.crs
|
|
222
|
+
nodata = in_dem.nodata
|
|
223
|
+
|
|
224
|
+
dst_transform = src_transform * Affine.scale(scale)
|
|
225
|
+
dst_height = int(height // scale) + 1
|
|
226
|
+
dst_width = int(width // scale) + 1
|
|
227
|
+
metadata["transform"] = dst_transform
|
|
228
|
+
metadata["height"] = dst_height
|
|
229
|
+
metadata["width"] = dst_width
|
|
230
|
+
dem_data = np.zeros((dst_height, dst_width))
|
|
231
|
+
interpolator_dict = {
|
|
232
|
+
"min": Resampling.min,
|
|
233
|
+
"median": Resampling.med,
|
|
234
|
+
"max": Resampling.max,
|
|
235
|
+
"nearest": Resampling.nearest,
|
|
236
|
+
}
|
|
237
|
+
interpolator = interpolator_dict[interpolator]
|
|
238
|
+
reproject(
|
|
239
|
+
data,
|
|
240
|
+
dem_data,
|
|
241
|
+
src_transform=src_transform,
|
|
242
|
+
src_crs=crs,
|
|
243
|
+
dst_transform=dst_transform,
|
|
244
|
+
dst_crs=crs,
|
|
245
|
+
dst_nodata=nodata,
|
|
246
|
+
resampling=interpolator,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Post-processing
|
|
250
|
+
|
|
251
|
+
# Median filter
|
|
252
|
+
if median_filter_size is not None:
|
|
253
|
+
dem_data = median_filter(dem_data, size=median_filter_size)
|
|
254
|
+
|
|
255
|
+
# Fill nodata
|
|
256
|
+
dem_data = rio.fill.fillnodata(
|
|
257
|
+
dem_data,
|
|
258
|
+
mask=~(dem_data == nodata),
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
dem_data[dem_data == nodata] = default_alt
|
|
262
|
+
|
|
263
|
+
with rio.open(input_dem, "w", **metadata) as dst:
|
|
264
|
+
dst.write(dem_data, 1)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def modify_terrain_bounds(terrain_bounds, linear_margin, constant_margin):
|
|
268
|
+
"""
|
|
269
|
+
Modify the terrain bounds
|
|
270
|
+
|
|
271
|
+
:param terrain_bounds: Input region of interest for DEM
|
|
272
|
+
:type terrain_bounds: list
|
|
273
|
+
:param margin: Margin of the output ROI in meters
|
|
274
|
+
:type margin: int
|
|
275
|
+
"""
|
|
276
|
+
xsize = terrain_bounds[2] - terrain_bounds[0]
|
|
277
|
+
ysize = terrain_bounds[3] - terrain_bounds[1]
|
|
278
|
+
xmin = terrain_bounds[0] - linear_margin * xsize - constant_margin
|
|
279
|
+
ymin = terrain_bounds[1] - linear_margin * ysize - constant_margin
|
|
280
|
+
xmax = terrain_bounds[2] + linear_margin * xsize + constant_margin
|
|
281
|
+
ymax = terrain_bounds[3] + linear_margin * ysize + constant_margin
|
|
282
|
+
|
|
283
|
+
terrain_bounds = [xmin, ymin, xmax, ymax]
|
|
284
|
+
|
|
285
|
+
return terrain_bounds
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def reproject_dem(dsm_file_name, epsg_out, out_file_name):
|
|
289
|
+
"""
|
|
290
|
+
Reproject the DEM
|
|
291
|
+
|
|
292
|
+
:param dsm_file_name: the path to dsm
|
|
293
|
+
:type dsm_file_name: str
|
|
294
|
+
:param epsg_out: the epsg code
|
|
295
|
+
:type epsg_out: int
|
|
296
|
+
:param out_file_name: the out path file
|
|
297
|
+
:type out_file_name: str
|
|
298
|
+
"""
|
|
299
|
+
with rio.open(dsm_file_name) as src:
|
|
300
|
+
transform, width, height = calculate_default_transform(
|
|
301
|
+
src.crs, epsg_out, src.width, src.height, *src.bounds
|
|
302
|
+
)
|
|
303
|
+
kwargs = src.meta.copy()
|
|
304
|
+
kwargs.update(
|
|
305
|
+
{
|
|
306
|
+
"crs": epsg_out,
|
|
307
|
+
"transform": transform,
|
|
308
|
+
"width": width,
|
|
309
|
+
"height": height,
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
with rio.open(out_file_name, "w", **kwargs) as dst:
|
|
314
|
+
for i in range(1, src.count + 1):
|
|
315
|
+
reproject(
|
|
316
|
+
source=rio.band(src, i),
|
|
317
|
+
destination=rio.band(dst, i),
|
|
318
|
+
src_transform=src.transform,
|
|
319
|
+
src_crs=src.crs,
|
|
320
|
+
dst_transform=transform,
|
|
321
|
+
dst_crs=epsg_out,
|
|
322
|
+
resampling=Resampling.nearest,
|
|
323
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
CARS core fill disparity map module init file
|
|
23
|
+
"""
|
|
24
|
+
# flake8: noqa: F401
|
|
25
|
+
|
|
26
|
+
from cars.applications.dense_match_filling.abstract_dense_match_filling_app import ( # pylint: disable=C0301
|
|
27
|
+
DenseMatchFilling,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from . import zero_padding_app
|