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,590 @@
|
|
|
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
|
+
Resampling module:
|
|
23
|
+
contains functions used for epipolar resampling
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# Standard imports
|
|
27
|
+
import math
|
|
28
|
+
|
|
29
|
+
# Third party imports
|
|
30
|
+
import numpy as np
|
|
31
|
+
import rasterio as rio
|
|
32
|
+
import resample as cresample
|
|
33
|
+
from rasterio.windows import Window, bounds
|
|
34
|
+
|
|
35
|
+
from cars.conf import mask_cst as msk_cst
|
|
36
|
+
|
|
37
|
+
# CARS imports
|
|
38
|
+
from cars.core import constants as cst
|
|
39
|
+
from cars.core import datasets, inputs, tiling
|
|
40
|
+
from cars.core.geometry import abstract_geometry
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def epipolar_rectify_images( # pylint: disable=too-many-positional-arguments
|
|
44
|
+
left_imgs,
|
|
45
|
+
right_imgs,
|
|
46
|
+
grid1,
|
|
47
|
+
grid2,
|
|
48
|
+
region,
|
|
49
|
+
margins,
|
|
50
|
+
epipolar_size_x,
|
|
51
|
+
epipolar_size_y,
|
|
52
|
+
interpolator_image="bicubic",
|
|
53
|
+
interpolator_classif="nearest",
|
|
54
|
+
interpolator_mask="nearest",
|
|
55
|
+
step=None,
|
|
56
|
+
mask1=None,
|
|
57
|
+
mask2=None,
|
|
58
|
+
left_classifs=None,
|
|
59
|
+
right_classifs=None,
|
|
60
|
+
nodata1=0,
|
|
61
|
+
nodata2=0,
|
|
62
|
+
add_classif=True,
|
|
63
|
+
):
|
|
64
|
+
"""
|
|
65
|
+
Resample left and right images
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# Force region to be float
|
|
69
|
+
region = [int(x) for x in region]
|
|
70
|
+
|
|
71
|
+
# Apply margins to left image
|
|
72
|
+
# TODO: tiled region should be given in parameter
|
|
73
|
+
# TODO: keep only rectification here (keep functional unitary approach)
|
|
74
|
+
left_region = region.copy()
|
|
75
|
+
left_margins = margins["left_margin"].data
|
|
76
|
+
left_roi = tiling.crop(
|
|
77
|
+
left_region, [0, 0, epipolar_size_x, epipolar_size_y]
|
|
78
|
+
)
|
|
79
|
+
left_region = tiling.crop(
|
|
80
|
+
tiling.pad(left_region, left_margins),
|
|
81
|
+
[0, 0, epipolar_size_x, epipolar_size_y],
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
left_margins = margins["left_margin"].data
|
|
85
|
+
# Get actual margin taking cropping into account
|
|
86
|
+
left_margins[0] = left_region[0] - left_roi[0]
|
|
87
|
+
left_margins[1] = left_region[1] - left_roi[1]
|
|
88
|
+
left_margins[2] = left_region[2] - left_roi[2]
|
|
89
|
+
left_margins[3] = left_region[3] - left_roi[3]
|
|
90
|
+
|
|
91
|
+
# Apply margins to right image
|
|
92
|
+
right_region = region.copy()
|
|
93
|
+
right_margins = margins["right_margin"].data
|
|
94
|
+
right_roi = tiling.crop(
|
|
95
|
+
right_region, [0, 0, epipolar_size_x, epipolar_size_y]
|
|
96
|
+
)
|
|
97
|
+
right_region = tiling.crop(
|
|
98
|
+
tiling.pad(right_region, right_margins),
|
|
99
|
+
[0, 0, epipolar_size_x, epipolar_size_y],
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Get actual margin taking cropping into account
|
|
103
|
+
right_margins[0] = right_region[0] - right_roi[0]
|
|
104
|
+
right_margins[1] = right_region[1] - right_roi[1]
|
|
105
|
+
right_margins[2] = right_region[2] - right_roi[2]
|
|
106
|
+
right_margins[3] = right_region[3] - right_roi[3]
|
|
107
|
+
|
|
108
|
+
# Resample left images
|
|
109
|
+
left_img_transform = inputs.rasterio_get_transform(
|
|
110
|
+
next(iter(left_imgs)), convention="north"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
left_dataset = resample_image(
|
|
114
|
+
left_imgs,
|
|
115
|
+
grid1,
|
|
116
|
+
[epipolar_size_x, epipolar_size_y],
|
|
117
|
+
step=step,
|
|
118
|
+
region=left_region,
|
|
119
|
+
nodata=nodata1,
|
|
120
|
+
mask=mask1,
|
|
121
|
+
band_coords=cst.BAND_IM,
|
|
122
|
+
interpolator_img=interpolator_image,
|
|
123
|
+
interpolator_mask=interpolator_mask,
|
|
124
|
+
img_transform=left_img_transform,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Update attributes
|
|
128
|
+
left_dataset.attrs[cst.ROI] = np.array(left_roi)
|
|
129
|
+
left_dataset.attrs[cst.ROI_WITH_MARGINS] = np.array(left_region)
|
|
130
|
+
# Remove region key as it duplicates roi_with_margins key
|
|
131
|
+
# left_dataset.attrs.pop("region", None)
|
|
132
|
+
left_dataset.attrs[cst.EPI_MARGINS] = np.array(left_margins)
|
|
133
|
+
if "disp_min" in margins.attrs:
|
|
134
|
+
left_dataset.attrs[cst.EPI_DISP_MIN] = margins.attrs["disp_min"]
|
|
135
|
+
if "disp_max" in margins.attrs:
|
|
136
|
+
left_dataset.attrs[cst.EPI_DISP_MAX] = margins.attrs["disp_max"]
|
|
137
|
+
|
|
138
|
+
# Resample right image
|
|
139
|
+
right_img_transform = inputs.rasterio_get_transform(next(iter(right_imgs)))
|
|
140
|
+
right_dataset = resample_image(
|
|
141
|
+
right_imgs,
|
|
142
|
+
grid2,
|
|
143
|
+
[epipolar_size_x, epipolar_size_y],
|
|
144
|
+
step=step,
|
|
145
|
+
region=right_region,
|
|
146
|
+
nodata=nodata2,
|
|
147
|
+
mask=mask2,
|
|
148
|
+
band_coords=cst.BAND_IM,
|
|
149
|
+
interpolator_img=interpolator_image,
|
|
150
|
+
interpolator_mask=interpolator_mask,
|
|
151
|
+
img_transform=right_img_transform,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Update attributes
|
|
155
|
+
right_dataset.attrs[cst.ROI] = np.array(right_roi)
|
|
156
|
+
right_dataset.attrs[cst.ROI_WITH_MARGINS] = np.array(right_region)
|
|
157
|
+
# Remove region key as it duplicates roi_with_margins key
|
|
158
|
+
# right_dataset.attrs.pop("region", None)
|
|
159
|
+
right_dataset.attrs[cst.EPI_MARGINS] = np.array(right_margins)
|
|
160
|
+
if "disp_min" in margins.attrs:
|
|
161
|
+
right_dataset.attrs[cst.EPI_DISP_MIN] = margins.attrs["disp_min"]
|
|
162
|
+
if "disp_max" in margins.attrs:
|
|
163
|
+
right_dataset.attrs[cst.EPI_DISP_MAX] = margins.attrs["disp_max"]
|
|
164
|
+
|
|
165
|
+
# Resample classifications
|
|
166
|
+
left_classif_dataset = None
|
|
167
|
+
right_classif_dataset = None
|
|
168
|
+
if add_classif:
|
|
169
|
+
if left_classifs:
|
|
170
|
+
left_classif_dataset = resample_image(
|
|
171
|
+
left_classifs,
|
|
172
|
+
grid1,
|
|
173
|
+
[epipolar_size_x, epipolar_size_y],
|
|
174
|
+
region=left_region,
|
|
175
|
+
band_coords=cst.BAND_CLASSIF,
|
|
176
|
+
interpolator_img=interpolator_classif,
|
|
177
|
+
interpolator_mask=interpolator_mask,
|
|
178
|
+
img_transform=left_img_transform,
|
|
179
|
+
)
|
|
180
|
+
if right_classifs:
|
|
181
|
+
right_classif_dataset = resample_image(
|
|
182
|
+
right_classifs,
|
|
183
|
+
grid2,
|
|
184
|
+
[epipolar_size_x, epipolar_size_y],
|
|
185
|
+
region=right_region,
|
|
186
|
+
band_coords=cst.BAND_CLASSIF,
|
|
187
|
+
interpolator_img=interpolator_classif,
|
|
188
|
+
interpolator_mask=interpolator_mask,
|
|
189
|
+
img_transform=right_img_transform,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
left_dataset,
|
|
194
|
+
right_dataset,
|
|
195
|
+
left_classif_dataset,
|
|
196
|
+
right_classif_dataset,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# pylint: disable=too-many-positional-arguments
|
|
201
|
+
def resample_image( # noqa: C901
|
|
202
|
+
imgs,
|
|
203
|
+
grid,
|
|
204
|
+
largest_size,
|
|
205
|
+
step=None,
|
|
206
|
+
region=None,
|
|
207
|
+
nodata=None,
|
|
208
|
+
mask=None,
|
|
209
|
+
band_coords=False,
|
|
210
|
+
interpolator_img="bicubic",
|
|
211
|
+
interpolator_mask="nearest",
|
|
212
|
+
img_transform=None,
|
|
213
|
+
):
|
|
214
|
+
"""
|
|
215
|
+
Resample image according to grid and largest size.
|
|
216
|
+
|
|
217
|
+
:param img: Path to the image to resample
|
|
218
|
+
:type img: string
|
|
219
|
+
:param grid: rectification grid dict
|
|
220
|
+
:type grid: dict
|
|
221
|
+
:param largest_size: Size of full output image
|
|
222
|
+
:type largest_size: list of two int
|
|
223
|
+
:param step: horizontal step of resampling (useful for strip resampling)
|
|
224
|
+
:type step: int
|
|
225
|
+
:param region: A subset of the output image to produce
|
|
226
|
+
:type region: None (full output is produced) or array of four floats
|
|
227
|
+
[xmin,ymin,xmax,ymax]
|
|
228
|
+
:param nodata: Nodata value to use (both for input and output)
|
|
229
|
+
:type nodata: None or float
|
|
230
|
+
:param mask: Mask to resample as well
|
|
231
|
+
:type mask: None or path to mask image
|
|
232
|
+
:param band_coords: Force bands coordinate in output dataset
|
|
233
|
+
:type band_coords: boolean
|
|
234
|
+
:param interpolator: interpolator type (bicubic (default) or nearest)
|
|
235
|
+
:type interpolator: str ("nearest" "linear" "bco")
|
|
236
|
+
:rtype: xarray.Dataset with resampled image and mask
|
|
237
|
+
"""
|
|
238
|
+
img_sample = next(iter(imgs))
|
|
239
|
+
# Handle region is None
|
|
240
|
+
if region is None:
|
|
241
|
+
region = [0, 0, largest_size[0], largest_size[1]]
|
|
242
|
+
else:
|
|
243
|
+
region = [
|
|
244
|
+
int(math.floor(region[0])),
|
|
245
|
+
int(math.floor(region[1])),
|
|
246
|
+
int(math.ceil(region[2])),
|
|
247
|
+
int(math.ceil(region[3])),
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
if img_transform is None:
|
|
251
|
+
img_transform = inputs.rasterio_get_transform(
|
|
252
|
+
img_sample, convention="north"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Convert largest_size to int if needed
|
|
256
|
+
largest_size = [int(x) for x in largest_size]
|
|
257
|
+
|
|
258
|
+
# Localize blocks of the tile to resample
|
|
259
|
+
if step is None:
|
|
260
|
+
step = region[2] - region[0]
|
|
261
|
+
|
|
262
|
+
xmin_of_blocks = np.arange(region[0], region[2], step)
|
|
263
|
+
xmax_of_blocks = np.append(
|
|
264
|
+
np.arange(region[0] + step, region[2], step), region[2]
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
ymin_of_blocks = np.arange(region[1], region[3], step)
|
|
268
|
+
ymax_of_blocks = np.append(
|
|
269
|
+
np.arange(region[1] + step, region[3], step), region[3]
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
resampled_images_list = []
|
|
273
|
+
resampled_masks_list = []
|
|
274
|
+
band_names = []
|
|
275
|
+
data_types = []
|
|
276
|
+
nodata_msk = msk_cst.NO_DATA_IN_EPIPOLAR_RECTIFICATION
|
|
277
|
+
for img in imgs:
|
|
278
|
+
bands = imgs[img]
|
|
279
|
+
if "band_id" in bands:
|
|
280
|
+
nb_bands = len(bands["band_id"])
|
|
281
|
+
elif "values" in bands:
|
|
282
|
+
nb_bands = len(bands["values"])
|
|
283
|
+
else:
|
|
284
|
+
raise ValueError(
|
|
285
|
+
"File {} not recognised as an image or classif file".format(
|
|
286
|
+
bands
|
|
287
|
+
)
|
|
288
|
+
)
|
|
289
|
+
# Initialize outputs of the entire tile
|
|
290
|
+
resamp = np.empty(
|
|
291
|
+
(nb_bands, region[3] - region[1], region[2] - region[0]),
|
|
292
|
+
dtype=np.float32,
|
|
293
|
+
)
|
|
294
|
+
msk = np.empty(
|
|
295
|
+
(nb_bands, region[3] - region[1], region[2] - region[0]),
|
|
296
|
+
dtype=np.float32,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
ystart = 0
|
|
300
|
+
with rio.open(grid["path"]) as grid_reader, rio.open(img) as img_reader:
|
|
301
|
+
for ymin, ymax in zip(ymin_of_blocks, ymax_of_blocks): # noqa: B905
|
|
302
|
+
ysize = ymax - ymin
|
|
303
|
+
xstart = 0
|
|
304
|
+
for xmin, xmax in zip( # noqa: B905
|
|
305
|
+
xmin_of_blocks, xmax_of_blocks
|
|
306
|
+
):
|
|
307
|
+
block_region = [xmin, ymin, xmax, ymax]
|
|
308
|
+
xsize = xmax - xmin
|
|
309
|
+
resamp, msk = oversampling_func(
|
|
310
|
+
grid_reader,
|
|
311
|
+
img_reader,
|
|
312
|
+
img_transform,
|
|
313
|
+
block_region,
|
|
314
|
+
interpolator_img,
|
|
315
|
+
band_coords,
|
|
316
|
+
nb_bands,
|
|
317
|
+
bands,
|
|
318
|
+
resamp,
|
|
319
|
+
nodata,
|
|
320
|
+
msk,
|
|
321
|
+
mask,
|
|
322
|
+
nodata_msk,
|
|
323
|
+
interpolator_mask,
|
|
324
|
+
ysize,
|
|
325
|
+
xsize,
|
|
326
|
+
ystart,
|
|
327
|
+
xstart,
|
|
328
|
+
)
|
|
329
|
+
xstart += xsize
|
|
330
|
+
|
|
331
|
+
ystart += ysize
|
|
332
|
+
if "band_id" in bands:
|
|
333
|
+
band_names += bands["band_name"]
|
|
334
|
+
elif "values" in bands:
|
|
335
|
+
band_names += list(map(str, bands["values"]))
|
|
336
|
+
else:
|
|
337
|
+
raise ValueError(
|
|
338
|
+
"File {} not recognised as an image or classif file".format(
|
|
339
|
+
bands
|
|
340
|
+
)
|
|
341
|
+
)
|
|
342
|
+
data_types += [inputs.rasterio_get_image_type(img)] * nb_bands
|
|
343
|
+
resampled_images_list.append(resamp)
|
|
344
|
+
resampled_masks_list.append(msk)
|
|
345
|
+
|
|
346
|
+
resamp_final = np.concatenate(resampled_images_list, axis=0)
|
|
347
|
+
msk_final = np.concatenate(resampled_masks_list, axis=0)
|
|
348
|
+
dataset = datasets.create_im_dataset(
|
|
349
|
+
resamp_final,
|
|
350
|
+
region,
|
|
351
|
+
largest_size,
|
|
352
|
+
img_sample,
|
|
353
|
+
band_coords,
|
|
354
|
+
band_names,
|
|
355
|
+
data_types,
|
|
356
|
+
msk_final,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
return dataset
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def oversampling_func( # pylint: disable=too-many-positional-arguments
|
|
363
|
+
grid_reader,
|
|
364
|
+
img_reader,
|
|
365
|
+
img_transform,
|
|
366
|
+
block_region,
|
|
367
|
+
interpolator_img,
|
|
368
|
+
band_coords,
|
|
369
|
+
nb_bands,
|
|
370
|
+
bands,
|
|
371
|
+
resamp,
|
|
372
|
+
nodata,
|
|
373
|
+
msk,
|
|
374
|
+
mask,
|
|
375
|
+
nodata_msk,
|
|
376
|
+
interpolator_mask,
|
|
377
|
+
ysize,
|
|
378
|
+
xsize,
|
|
379
|
+
ystart,
|
|
380
|
+
xstart,
|
|
381
|
+
):
|
|
382
|
+
"""
|
|
383
|
+
Do the resampling calculus
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
xmin = block_region[0]
|
|
387
|
+
ymin = block_region[1]
|
|
388
|
+
xmax = block_region[2]
|
|
389
|
+
ymax = block_region[3]
|
|
390
|
+
|
|
391
|
+
# Build rectification pipelines for images
|
|
392
|
+
res_x, res_y = grid_reader.res
|
|
393
|
+
assert res_x == res_y
|
|
394
|
+
oversampling = int(res_x)
|
|
395
|
+
assert res_x == oversampling
|
|
396
|
+
|
|
397
|
+
grid_origin_x = grid_reader.transform[2]
|
|
398
|
+
grid_origin_y = grid_reader.transform[5]
|
|
399
|
+
assert grid_origin_x == grid_origin_y
|
|
400
|
+
grid_margin = int(-grid_origin_x / oversampling - 0.5)
|
|
401
|
+
|
|
402
|
+
grid_margin = int(grid_margin)
|
|
403
|
+
|
|
404
|
+
# Convert resampled region to grid region with oversampling
|
|
405
|
+
grid_region = np.array(
|
|
406
|
+
[
|
|
407
|
+
math.floor(xmin / oversampling),
|
|
408
|
+
math.floor(ymin / oversampling),
|
|
409
|
+
math.ceil(xmax / oversampling),
|
|
410
|
+
math.ceil(ymax / oversampling),
|
|
411
|
+
]
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
# Out region of epipolar image
|
|
415
|
+
out_region = oversampling * grid_region
|
|
416
|
+
# Grid region
|
|
417
|
+
grid_region += grid_margin
|
|
418
|
+
|
|
419
|
+
grid_window = Window.from_slices(
|
|
420
|
+
(grid_region[1], grid_region[3] + 1),
|
|
421
|
+
(grid_region[0], grid_region[2] + 1),
|
|
422
|
+
)
|
|
423
|
+
grid_as_array = grid_reader.read(window=grid_window)
|
|
424
|
+
grid_as_array = grid_as_array.astype(np.float32)
|
|
425
|
+
grid_as_array = grid_as_array.astype(np.float64)
|
|
426
|
+
|
|
427
|
+
# get needed source bounding box
|
|
428
|
+
left = math.floor(np.amin(grid_as_array[0, ...]))
|
|
429
|
+
right = math.ceil(np.amax(grid_as_array[0, ...]))
|
|
430
|
+
top = math.floor(np.amin(grid_as_array[1, ...]))
|
|
431
|
+
bottom = math.ceil(np.amax(grid_as_array[1, ...]))
|
|
432
|
+
|
|
433
|
+
transform = rio.Affine(*np.abs(img_transform))
|
|
434
|
+
# transform xmin and xmax positions to index
|
|
435
|
+
(top, bottom, left, right) = abstract_geometry.min_max_to_index_min_max(
|
|
436
|
+
left, right, top, bottom, transform
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
# filter margin for bicubic = 2
|
|
440
|
+
filter_margin = 2
|
|
441
|
+
top -= filter_margin
|
|
442
|
+
bottom += filter_margin
|
|
443
|
+
left -= filter_margin
|
|
444
|
+
right += filter_margin
|
|
445
|
+
|
|
446
|
+
left, right = list(np.clip([left, right], 0, img_reader.shape[0]))
|
|
447
|
+
top, bottom = list(np.clip([top, bottom], 0, img_reader.shape[1]))
|
|
448
|
+
|
|
449
|
+
img_window = Window.from_slices([left, right], [top, bottom])
|
|
450
|
+
|
|
451
|
+
in_sensor = True
|
|
452
|
+
if right - left == 0 or bottom - top == 0:
|
|
453
|
+
in_sensor = False
|
|
454
|
+
|
|
455
|
+
# round window
|
|
456
|
+
img_window = img_window.round_offsets()
|
|
457
|
+
img_window = img_window.round_lengths()
|
|
458
|
+
|
|
459
|
+
# compute offset
|
|
460
|
+
res_x = float(abs(transform[0]))
|
|
461
|
+
res_y = float(abs(transform[4]))
|
|
462
|
+
tile_bounds = list(bounds(img_window, transform))
|
|
463
|
+
|
|
464
|
+
x_offset = min(tile_bounds[0], tile_bounds[2])
|
|
465
|
+
y_offset = min(tile_bounds[1], tile_bounds[3])
|
|
466
|
+
|
|
467
|
+
if in_sensor:
|
|
468
|
+
# get sensor data
|
|
469
|
+
if "band_id" in bands:
|
|
470
|
+
# image
|
|
471
|
+
img_as_array = img_reader.read(bands["band_id"], window=img_window)
|
|
472
|
+
elif "values" in bands:
|
|
473
|
+
# classification
|
|
474
|
+
img_as_array = img_reader.read([1], window=img_window)
|
|
475
|
+
else:
|
|
476
|
+
raise ValueError(
|
|
477
|
+
"File {} not recognised as an image or classif file".format(
|
|
478
|
+
bands
|
|
479
|
+
)
|
|
480
|
+
)
|
|
481
|
+
# get the nodata mask before blurring
|
|
482
|
+
img_nan_mask = img_as_array == nodata
|
|
483
|
+
|
|
484
|
+
# set the nodata values back
|
|
485
|
+
if nodata is not None:
|
|
486
|
+
img_as_array[img_nan_mask] = nodata
|
|
487
|
+
|
|
488
|
+
# shift grid regarding the img extraction
|
|
489
|
+
grid_as_array[0, ...] -= x_offset
|
|
490
|
+
grid_as_array[1, ...] -= y_offset
|
|
491
|
+
|
|
492
|
+
# apply input resolution
|
|
493
|
+
grid_as_array[0, ...] /= res_x
|
|
494
|
+
grid_as_array[1, ...] /= res_y
|
|
495
|
+
|
|
496
|
+
block_resamp = cresample.grid(
|
|
497
|
+
img_as_array,
|
|
498
|
+
grid_as_array,
|
|
499
|
+
oversampling,
|
|
500
|
+
interpolator=interpolator_img,
|
|
501
|
+
nodata=0,
|
|
502
|
+
).astype(np.float32)
|
|
503
|
+
|
|
504
|
+
if interpolator_img == "bicubic" and band_coords == cst.BAND_CLASSIF:
|
|
505
|
+
block_resamp = np.where(
|
|
506
|
+
block_resamp >= 0.5,
|
|
507
|
+
1,
|
|
508
|
+
np.where(block_resamp < 0.5, 0, block_resamp),
|
|
509
|
+
).astype(int)
|
|
510
|
+
|
|
511
|
+
# extract exact region
|
|
512
|
+
ext_region = block_region - out_region
|
|
513
|
+
block_resamp = block_resamp[
|
|
514
|
+
...,
|
|
515
|
+
ext_region[1] : ext_region[3] - 1,
|
|
516
|
+
ext_region[0] : ext_region[2] - 1,
|
|
517
|
+
]
|
|
518
|
+
|
|
519
|
+
if "values" in bands:
|
|
520
|
+
# Extract binary bands from mono-band classification
|
|
521
|
+
multiband_block_resamp = np.zeros(
|
|
522
|
+
(
|
|
523
|
+
nb_bands,
|
|
524
|
+
block_region[3] - block_region[1],
|
|
525
|
+
block_region[2] - block_region[0],
|
|
526
|
+
)
|
|
527
|
+
)
|
|
528
|
+
for band_id, value in enumerate(bands["values"]):
|
|
529
|
+
multiband_block_resamp[band_id] = block_resamp == value
|
|
530
|
+
block_resamp = multiband_block_resamp
|
|
531
|
+
|
|
532
|
+
else:
|
|
533
|
+
block_resamp = np.zeros(
|
|
534
|
+
(
|
|
535
|
+
nb_bands,
|
|
536
|
+
block_region[3] - block_region[1],
|
|
537
|
+
block_region[2] - block_region[0],
|
|
538
|
+
)
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
resamp[:, ystart : ystart + ysize, xstart : xstart + xsize] = block_resamp
|
|
542
|
+
|
|
543
|
+
# create msk
|
|
544
|
+
if in_sensor:
|
|
545
|
+
# get mask in source geometry
|
|
546
|
+
if mask is not None:
|
|
547
|
+
with rio.open(mask) as msk_reader:
|
|
548
|
+
msk_as_array = msk_reader.read(1, window=img_window)
|
|
549
|
+
msk_as_array = np.array([msk_as_array] * img_as_array.shape[0])
|
|
550
|
+
else:
|
|
551
|
+
msk_as_array = np.zeros(img_as_array.shape)
|
|
552
|
+
|
|
553
|
+
if nodata is not None:
|
|
554
|
+
nodata_index = img_as_array == nodata
|
|
555
|
+
msk_as_array[nodata_index] = nodata_msk
|
|
556
|
+
|
|
557
|
+
# resample mask
|
|
558
|
+
block_msk = cresample.grid(
|
|
559
|
+
msk_as_array,
|
|
560
|
+
grid_as_array,
|
|
561
|
+
oversampling,
|
|
562
|
+
interpolator=interpolator_mask,
|
|
563
|
+
nodata=nodata_msk,
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
if interpolator_mask == "bicubic":
|
|
567
|
+
block_msk = np.where(
|
|
568
|
+
block_msk >= 0.5,
|
|
569
|
+
1,
|
|
570
|
+
np.where(block_msk < 0.5, 0, block_msk),
|
|
571
|
+
).astype(int)
|
|
572
|
+
|
|
573
|
+
block_msk = block_msk[
|
|
574
|
+
...,
|
|
575
|
+
ext_region[1] : ext_region[3] - 1,
|
|
576
|
+
ext_region[0] : ext_region[2] - 1,
|
|
577
|
+
]
|
|
578
|
+
else:
|
|
579
|
+
block_msk = np.full(
|
|
580
|
+
(
|
|
581
|
+
nb_bands,
|
|
582
|
+
block_region[3] - block_region[1],
|
|
583
|
+
block_region[2] - block_region[0],
|
|
584
|
+
),
|
|
585
|
+
fill_value=nodata_msk,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
msk[:, ystart : ystart + ysize, xstart : xstart + xsize] = block_msk
|
|
589
|
+
|
|
590
|
+
return resamp, msk
|
|
@@ -0,0 +1,36 @@
|
|
|
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 constants of resampling.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# USED VARIABLES
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
RESAMPLING_RUN_TAG = "resampling"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# PARAMS
|
|
33
|
+
METHOD = "method"
|
|
34
|
+
EPI_TILE_SIZE = "epi_tile_size"
|
|
35
|
+
|
|
36
|
+
# INFOS
|