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,38 @@
|
|
|
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
|
+
file contains all the constants used in rasterization module
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
RASTERIZATION_RUN_TAG = "rasterization"
|
|
26
|
+
|
|
27
|
+
# Params
|
|
28
|
+
METHOD = "method"
|
|
29
|
+
DSM_RADIUS = "dsm_radius"
|
|
30
|
+
SIGMA = "sigma"
|
|
31
|
+
GRID_POINTS_DIVISION_FACTOR = "grid_points_division_factor"
|
|
32
|
+
RESOLUTION = "resolution"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Run infos
|
|
36
|
+
EPSG_TAG = "epsg"
|
|
37
|
+
DSM_NO_DATA_TAG = "dsm_no_data"
|
|
38
|
+
TEXTURE_NO_DATA_TAG = "texture_no_data"
|
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
# pylint: disable=too-many-lines
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
This module is responsible for the rasterization step:
|
|
25
|
+
- it contains all functions related to 3D representation on a 2D raster grid
|
|
26
|
+
TODO: refactor in several files and remove too-many-lines
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Standard imports
|
|
30
|
+
import logging
|
|
31
|
+
from typing import List, Tuple
|
|
32
|
+
|
|
33
|
+
# Third party imports
|
|
34
|
+
import numpy as np
|
|
35
|
+
import pandas
|
|
36
|
+
|
|
37
|
+
# cars-rasterize
|
|
38
|
+
import xarray as xr
|
|
39
|
+
|
|
40
|
+
# CARS imports
|
|
41
|
+
from cars.core import constants as cst
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def compute_xy_starts_and_sizes(
|
|
45
|
+
resolution: float, cloud: pandas.DataFrame
|
|
46
|
+
) -> Tuple[float, float, int, int]:
|
|
47
|
+
"""
|
|
48
|
+
Compute xstart, ystart, xsize and ysize
|
|
49
|
+
of the rasterization grid from a set of points
|
|
50
|
+
|
|
51
|
+
:param resolution: Resolution of rasterized cells,
|
|
52
|
+
expressed in cloud CRS units
|
|
53
|
+
:param cloud: set of points as returned
|
|
54
|
+
by the create_combined_cloud function
|
|
55
|
+
:return: a tuple (xstart, ystart, xsize, ysize)
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
# Derive xstart
|
|
59
|
+
xmin = np.nanmin(cloud[cst.X].values)
|
|
60
|
+
xmax = np.nanmax(cloud[cst.X].values)
|
|
61
|
+
logging.debug("Points x coordinate range: [{},{}]".format(xmin, xmax))
|
|
62
|
+
|
|
63
|
+
# Clamp to a regular grid
|
|
64
|
+
x_start = np.floor(xmin / resolution) * resolution
|
|
65
|
+
|
|
66
|
+
# Derive ystart
|
|
67
|
+
ymin = np.nanmin(cloud[cst.Y].values)
|
|
68
|
+
ymax = np.nanmax(cloud[cst.Y].values)
|
|
69
|
+
logging.debug("Points y coordinate range: [{},{}]".format(ymin, ymax))
|
|
70
|
+
|
|
71
|
+
# Clamp to a regular grid
|
|
72
|
+
y_start = np.ceil(ymax / resolution) * resolution
|
|
73
|
+
|
|
74
|
+
x_size = int(1 + np.floor((xmax - x_start) / resolution))
|
|
75
|
+
y_size = int(1 + np.floor((y_start - ymin) / resolution))
|
|
76
|
+
|
|
77
|
+
return x_start, y_start, x_size, y_size
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def compute_values_1d(
|
|
81
|
+
x_start: float, y_start: float, x_size: int, y_size: int, resolution: float
|
|
82
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
83
|
+
"""
|
|
84
|
+
Compute the x and y values as 1d arrays
|
|
85
|
+
|
|
86
|
+
:param x_start: x start of the rasterization grid
|
|
87
|
+
:param y_start: y start of the rasterization grid
|
|
88
|
+
:param x_size: x size of the rasterization grid
|
|
89
|
+
:param y_size: y size of the rasterization grid
|
|
90
|
+
:param resolution: Resolution of rasterized cells,
|
|
91
|
+
in cloud CRS units or None.
|
|
92
|
+
:return: a tuple composed of the x and y 1d arrays
|
|
93
|
+
"""
|
|
94
|
+
x_values_1d = np.linspace(
|
|
95
|
+
x_start + 0.5 * resolution,
|
|
96
|
+
x_start + resolution * (x_size + 0.5),
|
|
97
|
+
x_size,
|
|
98
|
+
endpoint=False,
|
|
99
|
+
)
|
|
100
|
+
y_values_1d = np.linspace(
|
|
101
|
+
y_start - 0.5 * resolution,
|
|
102
|
+
y_start - resolution * (y_size + 0.5),
|
|
103
|
+
y_size,
|
|
104
|
+
endpoint=False,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return x_values_1d, y_values_1d
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def substring_in_list(src_list, substring):
|
|
111
|
+
"""
|
|
112
|
+
Check if the list contains substring
|
|
113
|
+
"""
|
|
114
|
+
res = list(filter(lambda x: substring in x, src_list))
|
|
115
|
+
return len(res) > 0
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def phased_dsm(start: float, phase: float, resolution: float):
|
|
119
|
+
"""
|
|
120
|
+
Phased the dsm
|
|
121
|
+
|
|
122
|
+
:param start: start of the roi
|
|
123
|
+
:param phase: the point for phasing
|
|
124
|
+
:param resolution: resolution of the dsm
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
div = np.abs(start - phase) / resolution
|
|
128
|
+
|
|
129
|
+
if phase > start:
|
|
130
|
+
start = phase - resolution * np.floor(div)
|
|
131
|
+
else:
|
|
132
|
+
start = resolution * np.floor(div) + phase
|
|
133
|
+
|
|
134
|
+
return start
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def find_indexes_in_point_cloud(
|
|
138
|
+
cloud: pandas.DataFrame, tag: str, list_computed_layers: List[str] = None
|
|
139
|
+
) -> List[str]:
|
|
140
|
+
"""
|
|
141
|
+
Find all indexes in point cloud that contains the key tag
|
|
142
|
+
if it needs to be computed
|
|
143
|
+
:param cloud: Combined cloud
|
|
144
|
+
:param tag: substring of desired columns in cloud
|
|
145
|
+
:param list_computed_layers: list of computed output data
|
|
146
|
+
"""
|
|
147
|
+
indexes = []
|
|
148
|
+
if list_computed_layers is None or substring_in_list(
|
|
149
|
+
list_computed_layers, tag
|
|
150
|
+
):
|
|
151
|
+
for key in cloud.columns:
|
|
152
|
+
if tag in key:
|
|
153
|
+
indexes.append(key)
|
|
154
|
+
return indexes
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# pylint: disable=too-many-positional-arguments
|
|
158
|
+
def create_raster_dataset( # noqa: C901
|
|
159
|
+
raster: np.ndarray,
|
|
160
|
+
weights_sum: np.ndarray,
|
|
161
|
+
x_start: float,
|
|
162
|
+
y_start: float,
|
|
163
|
+
x_size: int,
|
|
164
|
+
y_size: int,
|
|
165
|
+
resolution: float,
|
|
166
|
+
hgt_no_data: int,
|
|
167
|
+
texture_no_data: int,
|
|
168
|
+
msk_no_data: int,
|
|
169
|
+
epsg: int,
|
|
170
|
+
mean: np.ndarray,
|
|
171
|
+
stdev: np.ndarray,
|
|
172
|
+
n_pts: np.ndarray,
|
|
173
|
+
n_in_cell: np.ndarray,
|
|
174
|
+
msk: np.ndarray = None,
|
|
175
|
+
band_im: List[str] = None,
|
|
176
|
+
classif: np.ndarray = None,
|
|
177
|
+
band_classif: List[str] = None,
|
|
178
|
+
ambiguity: np.ndarray = None,
|
|
179
|
+
layers_inf_sup: np.ndarray = None,
|
|
180
|
+
layers_inf_sup_stat_index: List[int] = None,
|
|
181
|
+
layer_inf_sup_indexes: List[str] = None,
|
|
182
|
+
source_pc: np.ndarray = None,
|
|
183
|
+
source_pc_names: List[str] = None,
|
|
184
|
+
filling: np.ndarray = None,
|
|
185
|
+
band_filling: List[str] = None,
|
|
186
|
+
performance_map: np.ndarray = None,
|
|
187
|
+
performance_map_classified: np.ndarray = None,
|
|
188
|
+
performance_map_classified_index: list = None,
|
|
189
|
+
band_performance_map: List[str] = None,
|
|
190
|
+
) -> xr.Dataset:
|
|
191
|
+
"""
|
|
192
|
+
Create final raster xarray dataset
|
|
193
|
+
|
|
194
|
+
:param raster: height and colors
|
|
195
|
+
:param x_start: x start of the rasterization grid
|
|
196
|
+
:param y_start: y start of the rasterization grid
|
|
197
|
+
:param x_size: x size of the rasterization grid
|
|
198
|
+
:param y_size: y size of the rasterization grid
|
|
199
|
+
:param resolution: Resolution of rasterized cells,
|
|
200
|
+
expressed in cloud CRS units or None.
|
|
201
|
+
:param hgt_no_data: no data value to use for height
|
|
202
|
+
:param texture_no_data: no data value to use for color
|
|
203
|
+
:param msk_no_data: no data value to use for mask and classif
|
|
204
|
+
:param epsg: epsg code for the CRS of the final raster
|
|
205
|
+
:param mean: mean of height and colors
|
|
206
|
+
:param stdev: standard deviation of height and colors
|
|
207
|
+
:param n_pts: number of points that are stricty in a cell
|
|
208
|
+
:param n_in_cell: number of points which contribute to a cell
|
|
209
|
+
:param msk: raster msk
|
|
210
|
+
:param classif: raster classif
|
|
211
|
+
:param ambiguity: raster containing the ambiguity
|
|
212
|
+
:param layers_inf_sup: raster containing intervals inf and sup
|
|
213
|
+
:param layers_inf_sup_stat_index: list containing index of
|
|
214
|
+
intervals in mean and stdev rasters
|
|
215
|
+
:param layer_inf_sup_indexes: list of band names
|
|
216
|
+
:param source_pc: binary raster with source point cloud information
|
|
217
|
+
:param source_pc_names: list of names of point cloud before merging :
|
|
218
|
+
name of sensors pair or name of point cloud file
|
|
219
|
+
:param performance_map: raster containing the raw performance map
|
|
220
|
+
:param performance_map_classified: raster containing the classified
|
|
221
|
+
performance map
|
|
222
|
+
:param performance_map_classified_index: indexes of
|
|
223
|
+
performance_map_classified
|
|
224
|
+
:param band_performance_map: list of band names :
|
|
225
|
+
max 2 bands: risk / interval
|
|
226
|
+
:return: the raster xarray dataset
|
|
227
|
+
"""
|
|
228
|
+
raster_dims = (cst.Y, cst.X)
|
|
229
|
+
n_layers = raster.shape[0]
|
|
230
|
+
x_values_1d, y_values_1d = compute_values_1d(
|
|
231
|
+
x_start, y_start, x_size, y_size, resolution
|
|
232
|
+
)
|
|
233
|
+
raster_coords = {cst.X: x_values_1d, cst.Y: y_values_1d}
|
|
234
|
+
hgt = np.nan_to_num(raster[0], nan=hgt_no_data)
|
|
235
|
+
raster_out = xr.Dataset(
|
|
236
|
+
{
|
|
237
|
+
cst.RASTER_HGT: ([cst.Y, cst.X], hgt),
|
|
238
|
+
cst.RASTER_WEIGHTS_SUM: ([cst.Y, cst.X], weights_sum),
|
|
239
|
+
},
|
|
240
|
+
coords=raster_coords,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
if raster.shape[0] > 1: # rasterizer produced color output
|
|
244
|
+
color = np.nan_to_num(raster[1:], nan=texture_no_data)
|
|
245
|
+
for idx, band_name in enumerate(band_im):
|
|
246
|
+
band_im[idx] = band_name.replace(
|
|
247
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT + "_", ""
|
|
248
|
+
)
|
|
249
|
+
color_out = xr.Dataset(
|
|
250
|
+
{
|
|
251
|
+
cst.RASTER_COLOR_IMG: (
|
|
252
|
+
[cst.BAND_IM, cst.Y, cst.X],
|
|
253
|
+
color,
|
|
254
|
+
)
|
|
255
|
+
},
|
|
256
|
+
coords={**raster_coords, cst.BAND_IM: band_im},
|
|
257
|
+
)
|
|
258
|
+
# update raster output with classification data
|
|
259
|
+
raster_out = xr.merge((raster_out, color_out))
|
|
260
|
+
|
|
261
|
+
raster_out.attrs[cst.EPSG] = epsg
|
|
262
|
+
raster_out.attrs[cst.RESOLUTION] = resolution
|
|
263
|
+
|
|
264
|
+
# statistics layer for height output
|
|
265
|
+
raster_out[cst.RASTER_HGT_MEAN] = xr.DataArray(
|
|
266
|
+
mean[..., 0], coords=raster_coords, dims=raster_dims
|
|
267
|
+
)
|
|
268
|
+
raster_out[cst.RASTER_HGT_STD_DEV] = xr.DataArray(
|
|
269
|
+
stdev[..., 0], coords=raster_coords, dims=raster_dims
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# add each band statistics
|
|
273
|
+
for i_layer in range(1, n_layers):
|
|
274
|
+
raster_out["{}{}".format(cst.RASTER_BAND_MEAN, i_layer)] = xr.DataArray(
|
|
275
|
+
mean[..., i_layer],
|
|
276
|
+
coords=raster_coords,
|
|
277
|
+
dims=raster_dims,
|
|
278
|
+
)
|
|
279
|
+
raster_out["{}{}".format(cst.RASTER_BAND_STD_DEV, i_layer)] = (
|
|
280
|
+
xr.DataArray(
|
|
281
|
+
stdev[..., i_layer],
|
|
282
|
+
coords=raster_coords,
|
|
283
|
+
dims=raster_dims,
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
raster_out[cst.RASTER_NB_PTS] = xr.DataArray(n_pts, dims=raster_dims)
|
|
288
|
+
raster_out[cst.RASTER_NB_PTS_IN_CELL] = xr.DataArray(
|
|
289
|
+
n_in_cell, dims=raster_dims
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
if msk is not None: # rasterizer produced mask output
|
|
293
|
+
msk = np.nan_to_num(msk, nan=msk_no_data)
|
|
294
|
+
raster_out[cst.RASTER_MSK] = xr.DataArray(msk, dims=raster_dims)
|
|
295
|
+
|
|
296
|
+
if classif is not None: # rasterizer produced classif output
|
|
297
|
+
classif = np.nan_to_num(classif, nan=msk_no_data)
|
|
298
|
+
for idx, band_name in enumerate(band_classif):
|
|
299
|
+
band_classif[idx] = band_name.replace(
|
|
300
|
+
cst.POINT_CLOUD_CLASSIF_KEY_ROOT + "_", ""
|
|
301
|
+
)
|
|
302
|
+
classif_out = xr.Dataset(
|
|
303
|
+
{
|
|
304
|
+
cst.RASTER_CLASSIF: (
|
|
305
|
+
[cst.BAND_CLASSIF, cst.Y, cst.X],
|
|
306
|
+
classif,
|
|
307
|
+
)
|
|
308
|
+
},
|
|
309
|
+
coords={**raster_coords, cst.BAND_CLASSIF: band_classif},
|
|
310
|
+
)
|
|
311
|
+
# update raster output with classification data
|
|
312
|
+
raster_out = xr.merge((raster_out, classif_out))
|
|
313
|
+
|
|
314
|
+
if ambiguity is not None: # rasterizer produced color output
|
|
315
|
+
raster_out[cst.RASTER_AMBIGUITY] = xr.DataArray(
|
|
316
|
+
ambiguity[0], dims=raster_dims
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
if layers_inf_sup is not None:
|
|
320
|
+
# Get inf data
|
|
321
|
+
hgt_layers_list_inf = []
|
|
322
|
+
hgt_layers_list_sup = []
|
|
323
|
+
hgt_mean_layers_list_inf = []
|
|
324
|
+
hgt_mean_layers_list_sup = []
|
|
325
|
+
hgt_stdev_layers_list_inf = []
|
|
326
|
+
hgt_stdev_layers_list_sup = []
|
|
327
|
+
bands_sup = []
|
|
328
|
+
bands_inf = []
|
|
329
|
+
# Get Data
|
|
330
|
+
for current_layer, _ in enumerate(layers_inf_sup):
|
|
331
|
+
if "inf" in layer_inf_sup_indexes[current_layer]:
|
|
332
|
+
hgt_layers_list_inf.append(layers_inf_sup[current_layer])
|
|
333
|
+
hgt_mean_layers_list_inf.append(
|
|
334
|
+
mean[..., layers_inf_sup_stat_index[current_layer]]
|
|
335
|
+
)
|
|
336
|
+
hgt_stdev_layers_list_inf.append(
|
|
337
|
+
stdev[..., layers_inf_sup_stat_index[current_layer]]
|
|
338
|
+
)
|
|
339
|
+
bands_inf.append(layer_inf_sup_indexes[current_layer])
|
|
340
|
+
else:
|
|
341
|
+
hgt_layers_list_sup.append(layers_inf_sup[current_layer])
|
|
342
|
+
hgt_mean_layers_list_sup.append(
|
|
343
|
+
mean[..., layers_inf_sup_stat_index[current_layer]]
|
|
344
|
+
)
|
|
345
|
+
hgt_stdev_layers_list_sup.append(
|
|
346
|
+
stdev[..., layers_inf_sup_stat_index[current_layer]]
|
|
347
|
+
)
|
|
348
|
+
bands_sup.append(layer_inf_sup_indexes[current_layer])
|
|
349
|
+
|
|
350
|
+
for (
|
|
351
|
+
data_layer_list,
|
|
352
|
+
dataset_key,
|
|
353
|
+
band_key,
|
|
354
|
+
bands_name,
|
|
355
|
+
) in zip( # noqa: B905
|
|
356
|
+
[
|
|
357
|
+
hgt_layers_list_inf,
|
|
358
|
+
hgt_mean_layers_list_inf,
|
|
359
|
+
hgt_stdev_layers_list_inf,
|
|
360
|
+
hgt_layers_list_sup,
|
|
361
|
+
hgt_mean_layers_list_sup,
|
|
362
|
+
hgt_stdev_layers_list_sup,
|
|
363
|
+
],
|
|
364
|
+
[
|
|
365
|
+
cst.RASTER_HGT_INF,
|
|
366
|
+
cst.RASTER_HGT_INF_MEAN,
|
|
367
|
+
cst.RASTER_HGT_INF_STD_DEV,
|
|
368
|
+
cst.RASTER_HGT_SUP,
|
|
369
|
+
cst.RASTER_HGT_SUP_MEAN,
|
|
370
|
+
cst.RASTER_HGT_SUP_STD_DEV,
|
|
371
|
+
],
|
|
372
|
+
[
|
|
373
|
+
cst.BAND_LAYER_INF,
|
|
374
|
+
cst.BAND_LAYER_INF,
|
|
375
|
+
cst.BAND_LAYER_INF,
|
|
376
|
+
cst.BAND_LAYER_SUP,
|
|
377
|
+
cst.BAND_LAYER_SUP,
|
|
378
|
+
cst.BAND_LAYER_SUP,
|
|
379
|
+
],
|
|
380
|
+
[bands_inf, bands_inf, bands_inf, bands_sup, bands_sup, bands_sup],
|
|
381
|
+
):
|
|
382
|
+
# Stack data
|
|
383
|
+
data_layer = np.nan_to_num(
|
|
384
|
+
np.stack(data_layer_list, axis=0), nan=hgt_no_data
|
|
385
|
+
)
|
|
386
|
+
# Add to datasets
|
|
387
|
+
layer_out = xr.Dataset(
|
|
388
|
+
{
|
|
389
|
+
dataset_key: (
|
|
390
|
+
[band_key, cst.Y, cst.X],
|
|
391
|
+
data_layer,
|
|
392
|
+
)
|
|
393
|
+
},
|
|
394
|
+
coords={**raster_coords, band_key: bands_name},
|
|
395
|
+
)
|
|
396
|
+
# update raster output with filling information
|
|
397
|
+
raster_out = xr.merge((raster_out, layer_out))
|
|
398
|
+
|
|
399
|
+
if source_pc is not None and source_pc_names is not None:
|
|
400
|
+
source_pc = np.nan_to_num(source_pc, nan=msk_no_data)
|
|
401
|
+
source_pc_out = xr.Dataset(
|
|
402
|
+
{
|
|
403
|
+
cst.RASTER_SOURCE_PC: (
|
|
404
|
+
[cst.BAND_SOURCE_PC, cst.Y, cst.X],
|
|
405
|
+
source_pc,
|
|
406
|
+
)
|
|
407
|
+
},
|
|
408
|
+
coords={**raster_coords, cst.BAND_SOURCE_PC: source_pc_names},
|
|
409
|
+
)
|
|
410
|
+
# update raster output with classification data
|
|
411
|
+
raster_out = xr.merge((raster_out, source_pc_out))
|
|
412
|
+
|
|
413
|
+
if filling is not None: # rasterizer produced filling info output
|
|
414
|
+
filling = np.nan_to_num(filling, nan=msk_no_data)
|
|
415
|
+
for idx, band_name in enumerate(band_filling):
|
|
416
|
+
band_filling[idx] = band_name.replace(
|
|
417
|
+
cst.POINT_CLOUD_FILLING_KEY_ROOT + "_", ""
|
|
418
|
+
)
|
|
419
|
+
filling_out = xr.Dataset(
|
|
420
|
+
{
|
|
421
|
+
cst.RASTER_FILLING: (
|
|
422
|
+
[cst.BAND_FILLING, cst.Y, cst.X],
|
|
423
|
+
filling,
|
|
424
|
+
)
|
|
425
|
+
},
|
|
426
|
+
coords={**raster_coords, cst.BAND_FILLING: band_filling},
|
|
427
|
+
)
|
|
428
|
+
# update raster output with filling information
|
|
429
|
+
raster_out = xr.merge((raster_out, filling_out))
|
|
430
|
+
|
|
431
|
+
if performance_map is not None:
|
|
432
|
+
performance_map = np.nan_to_num(performance_map, nan=msk_no_data)
|
|
433
|
+
if len(performance_map.shape) == 3 and performance_map.shape[0] == 2:
|
|
434
|
+
# Has both performance from risk and intervals
|
|
435
|
+
perf_out = xr.Dataset(
|
|
436
|
+
{
|
|
437
|
+
cst.RASTER_PERFORMANCE_MAP_RAW: (
|
|
438
|
+
[cst.BAND_PERFORMANCE_MAP, cst.Y, cst.X],
|
|
439
|
+
performance_map,
|
|
440
|
+
)
|
|
441
|
+
},
|
|
442
|
+
coords={
|
|
443
|
+
**raster_coords,
|
|
444
|
+
cst.BAND_PERFORMANCE_MAP: band_performance_map,
|
|
445
|
+
},
|
|
446
|
+
)
|
|
447
|
+
# update raster output with performance information
|
|
448
|
+
raster_out = xr.merge((raster_out, perf_out))
|
|
449
|
+
|
|
450
|
+
else:
|
|
451
|
+
# Only one performance map
|
|
452
|
+
raster_out[cst.RASTER_PERFORMANCE_MAP_RAW] = xr.DataArray(
|
|
453
|
+
performance_map[0, :, :], dims=raster_dims
|
|
454
|
+
)
|
|
455
|
+
if performance_map_classified is not None:
|
|
456
|
+
if (
|
|
457
|
+
len(performance_map_classified.shape) == 3
|
|
458
|
+
and performance_map_classified.shape[0] == 2
|
|
459
|
+
):
|
|
460
|
+
# Has both performance from risk and intervals
|
|
461
|
+
perf_classified_out = xr.Dataset(
|
|
462
|
+
{
|
|
463
|
+
cst.RASTER_PERFORMANCE_MAP: (
|
|
464
|
+
[cst.BAND_PERFORMANCE_MAP, cst.Y, cst.X],
|
|
465
|
+
performance_map_classified,
|
|
466
|
+
)
|
|
467
|
+
},
|
|
468
|
+
coords={
|
|
469
|
+
**raster_coords,
|
|
470
|
+
cst.BAND_PERFORMANCE_MAP: band_performance_map,
|
|
471
|
+
},
|
|
472
|
+
)
|
|
473
|
+
# update raster output with performance information
|
|
474
|
+
raster_out = xr.merge((raster_out, perf_classified_out))
|
|
475
|
+
else:
|
|
476
|
+
# Only one performance map
|
|
477
|
+
raster_out[cst.RASTER_PERFORMANCE_MAP] = xr.DataArray(
|
|
478
|
+
performance_map_classified[0, :, :], dims=raster_dims
|
|
479
|
+
)
|
|
480
|
+
raster_out.attrs[cst.RIO_TAG_PERFORMANCE_MAP_CLASSES] = (
|
|
481
|
+
performance_map_classified_index
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
return raster_out
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def classify_performance_map(
|
|
488
|
+
performance_map_raw, performance_map_classes, msk_no_data
|
|
489
|
+
):
|
|
490
|
+
"""
|
|
491
|
+
Classify performance map with given classes
|
|
492
|
+
"""
|
|
493
|
+
if performance_map_classes[0] != 0:
|
|
494
|
+
performance_map_classes = [0] + performance_map_classes
|
|
495
|
+
if performance_map_classes[-1] != np.inf:
|
|
496
|
+
performance_map_classes.append(np.inf)
|
|
497
|
+
|
|
498
|
+
performance_map_classified_infos = {}
|
|
499
|
+
|
|
500
|
+
performance_map_classified = msk_no_data * np.ones(
|
|
501
|
+
performance_map_raw.shape, dtype=np.uint8
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
index_start, index_end = 0, 1
|
|
505
|
+
value = 0
|
|
506
|
+
while index_end < len(performance_map_classes):
|
|
507
|
+
current_class = (
|
|
508
|
+
performance_map_classes[index_start],
|
|
509
|
+
performance_map_classes[index_end],
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
# update information
|
|
513
|
+
performance_map_classified_infos[value] = current_class
|
|
514
|
+
|
|
515
|
+
# create classified performance map
|
|
516
|
+
performance_map_classified[
|
|
517
|
+
np.logical_and(
|
|
518
|
+
performance_map_raw >= current_class[0],
|
|
519
|
+
performance_map_raw < current_class[1],
|
|
520
|
+
)
|
|
521
|
+
] = value
|
|
522
|
+
|
|
523
|
+
# next class
|
|
524
|
+
index_start += 1
|
|
525
|
+
index_end += 1
|
|
526
|
+
value += 1
|
|
527
|
+
|
|
528
|
+
return performance_map_classified, performance_map_classified_infos
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def update_weights(old_weights, weights):
|
|
532
|
+
"""
|
|
533
|
+
Update weights
|
|
534
|
+
|
|
535
|
+
:param weights: current weights
|
|
536
|
+
:param old_weights: old weights
|
|
537
|
+
|
|
538
|
+
:return: updated weights
|
|
539
|
+
"""
|
|
540
|
+
|
|
541
|
+
new_weights = weights
|
|
542
|
+
if old_weights is not None:
|
|
543
|
+
current_nan = weights == 0
|
|
544
|
+
old_nan = old_weights == 0
|
|
545
|
+
weights[current_nan] = 0
|
|
546
|
+
old_weights[old_nan] = 0
|
|
547
|
+
new_weights = old_weights + weights
|
|
548
|
+
|
|
549
|
+
return new_weights
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def update_data( # pylint: disable=too-many-positional-arguments
|
|
553
|
+
old_data, current_data, weights, old_weights, nodata, method="basic"
|
|
554
|
+
):
|
|
555
|
+
"""
|
|
556
|
+
Update current data with old data and weigths
|
|
557
|
+
|
|
558
|
+
:param old_data: old data
|
|
559
|
+
:param current_data: current data
|
|
560
|
+
:param weights: current weights
|
|
561
|
+
:param old_weights: old weights
|
|
562
|
+
:param nodata: nodata associated to tag
|
|
563
|
+
|
|
564
|
+
:return: updated current data
|
|
565
|
+
"""
|
|
566
|
+
|
|
567
|
+
new_data = current_data
|
|
568
|
+
data = old_data
|
|
569
|
+
if old_data is not None:
|
|
570
|
+
old_data = np.squeeze(old_data)
|
|
571
|
+
old_weights = np.squeeze(old_weights)
|
|
572
|
+
shape = old_data.shape
|
|
573
|
+
if len(data.shape) == 3 and data.shape[0] > 1:
|
|
574
|
+
old_weights = np.repeat(
|
|
575
|
+
np.expand_dims(old_weights, axis=0), old_data.shape[0], axis=0
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
current_data = np.squeeze(current_data)
|
|
579
|
+
weights = np.squeeze(weights)
|
|
580
|
+
if len(new_data.shape) == 3 and new_data.shape[0] > 1:
|
|
581
|
+
weights = np.repeat(
|
|
582
|
+
np.expand_dims(weights, axis=0), current_data.shape[0], axis=0
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
# compute masks
|
|
586
|
+
current_valid = weights != 0
|
|
587
|
+
old_valid = old_weights != 0
|
|
588
|
+
|
|
589
|
+
both_valid = np.logical_and(current_valid, old_valid)
|
|
590
|
+
|
|
591
|
+
total_weights = np.zeros(shape)
|
|
592
|
+
|
|
593
|
+
total_weights[both_valid] = (
|
|
594
|
+
weights[both_valid] + old_weights[both_valid]
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
# current factor
|
|
598
|
+
current_factor = np.zeros(shape)
|
|
599
|
+
current_factor[current_valid] = 1
|
|
600
|
+
current_factor[both_valid] = (
|
|
601
|
+
weights[both_valid] / total_weights[both_valid]
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
# old factor
|
|
605
|
+
old_factor = np.zeros(shape)
|
|
606
|
+
old_factor[old_valid] = 1
|
|
607
|
+
old_factor[both_valid] = (
|
|
608
|
+
old_weights[both_valid] / total_weights[both_valid]
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
# assign old weights
|
|
612
|
+
new_data = np.zeros(shape)
|
|
613
|
+
if method == "basic":
|
|
614
|
+
new_data[old_valid] = old_data[old_valid] * old_factor[old_valid]
|
|
615
|
+
new_data[current_valid] += (
|
|
616
|
+
current_data[current_valid] * current_factor[current_valid]
|
|
617
|
+
)
|
|
618
|
+
elif method == "bool":
|
|
619
|
+
new_data[old_valid] = old_data[old_valid]
|
|
620
|
+
new_data[current_valid] = np.logical_or(
|
|
621
|
+
current_data[current_valid], new_data[current_valid]
|
|
622
|
+
)
|
|
623
|
+
elif method == "sum":
|
|
624
|
+
new_data[old_valid] = old_data[old_valid]
|
|
625
|
+
new_data[current_valid] += current_data[current_valid]
|
|
626
|
+
|
|
627
|
+
# round result if saved as integer
|
|
628
|
+
if np.issubdtype(current_data.dtype, np.integer):
|
|
629
|
+
new_data = np.round(new_data).astype(current_data.dtype)
|
|
630
|
+
|
|
631
|
+
# set nodata
|
|
632
|
+
all_nodata = (current_valid + old_valid) == 0
|
|
633
|
+
new_data[all_nodata] = nodata
|
|
634
|
+
return new_data
|