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,552 @@
|
|
|
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
|
+
This module is responsible for the transition between triangulation and
|
|
24
|
+
rasterization steps
|
|
25
|
+
"""
|
|
26
|
+
# pylint: disable=C0302
|
|
27
|
+
|
|
28
|
+
# Standard imports
|
|
29
|
+
import logging
|
|
30
|
+
from typing import List, Tuple, Union
|
|
31
|
+
|
|
32
|
+
# Third party imports
|
|
33
|
+
import numpy as np
|
|
34
|
+
import pandas as pd
|
|
35
|
+
import xarray as xr
|
|
36
|
+
|
|
37
|
+
from cars.applications.dense_matching import dense_matching_wrappers
|
|
38
|
+
|
|
39
|
+
# CARS imports
|
|
40
|
+
from cars.core import constants as cst
|
|
41
|
+
from cars.core import projection
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def filter_cloud_with_mask(crop_cloud, crop_terrain_tile_data_msk):
|
|
45
|
+
"""
|
|
46
|
+
Delete masked points with terrain tile mask
|
|
47
|
+
|
|
48
|
+
:param crop_cloud: the point cloud
|
|
49
|
+
:param crop_terrain_tile_data_msk: terrain tile mask
|
|
50
|
+
"""
|
|
51
|
+
crop_terrain_tile_data_msk = np.ravel(crop_terrain_tile_data_msk)
|
|
52
|
+
|
|
53
|
+
crop_terrain_tile_data_msk_pos = np.nonzero(~crop_terrain_tile_data_msk)
|
|
54
|
+
|
|
55
|
+
crop_cloud = np.delete(crop_cloud, crop_terrain_tile_data_msk_pos[0], 0)
|
|
56
|
+
|
|
57
|
+
return crop_cloud
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# pylint: disable=too-many-positional-arguments
|
|
61
|
+
def compute_terrain_msk(
|
|
62
|
+
dsm_epsg,
|
|
63
|
+
xmin,
|
|
64
|
+
xmax,
|
|
65
|
+
ymin,
|
|
66
|
+
ymax,
|
|
67
|
+
margin,
|
|
68
|
+
epsg,
|
|
69
|
+
point_cloud,
|
|
70
|
+
full_x,
|
|
71
|
+
full_y,
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Compute terrain tile msk bounds
|
|
75
|
+
|
|
76
|
+
If the point clouds are not in the same referential as the roi,
|
|
77
|
+
it is converted using the dsm_epsg
|
|
78
|
+
|
|
79
|
+
:param dsm_epsg: epsg code for the CRS of the final output raster
|
|
80
|
+
:param xmin: xmin of the rasterization grid
|
|
81
|
+
(if None, the whole clouds are combined)
|
|
82
|
+
:param xmax: xmax of the rasterization grid
|
|
83
|
+
(if None, the whole clouds are combined)
|
|
84
|
+
:param ymin: ymin of the rasterization grid
|
|
85
|
+
(if None, the whole clouds are combined)
|
|
86
|
+
:param ymax: ymax of the rasterization grid
|
|
87
|
+
(if None, the whole clouds are combined)
|
|
88
|
+
:param margin: Margin added for each tile, in meter or degree.
|
|
89
|
+
(default value: 0)
|
|
90
|
+
:param epsg: epsg code of the input cloud
|
|
91
|
+
:param point_cloud: the point cloud
|
|
92
|
+
:param full_x: point_cloud[X]
|
|
93
|
+
:param full_y: point_cloud[Y]
|
|
94
|
+
"""
|
|
95
|
+
if epsg != dsm_epsg:
|
|
96
|
+
(
|
|
97
|
+
full_x,
|
|
98
|
+
full_y,
|
|
99
|
+
) = projection.get_converted_xy_np_arrays_from_dataset(
|
|
100
|
+
point_cloud, dsm_epsg
|
|
101
|
+
)
|
|
102
|
+
msk_xmin = np.where(full_x > xmin - margin, True, False)
|
|
103
|
+
msk_xmax = np.where(full_x < xmax + margin, True, False)
|
|
104
|
+
msk_ymin = np.where(full_y > ymin - margin, True, False)
|
|
105
|
+
msk_ymax = np.where(full_y < ymax + margin, True, False)
|
|
106
|
+
terrain_tile_data_msk = np.logical_and(
|
|
107
|
+
msk_xmin,
|
|
108
|
+
np.logical_and(msk_xmax, np.logical_and(msk_ymin, msk_ymax)),
|
|
109
|
+
)
|
|
110
|
+
terrain_tile_data_msk_pos = terrain_tile_data_msk.astype(np.int8).nonzero()
|
|
111
|
+
|
|
112
|
+
return terrain_tile_data_msk, terrain_tile_data_msk_pos
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def create_point_cloud_index(cloud_sample):
|
|
116
|
+
"""
|
|
117
|
+
Create point cloud index from cloud list keys and color inputs
|
|
118
|
+
"""
|
|
119
|
+
cloud_indexes_with_types = {
|
|
120
|
+
cst.X: "float64",
|
|
121
|
+
cst.Y: "float64",
|
|
122
|
+
cst.Z: "float64",
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Add Z_inf Z_sup, and performance maps if computed
|
|
126
|
+
for key in list(cloud_sample.keys()):
|
|
127
|
+
if (
|
|
128
|
+
cst.POINT_CLOUD_LAYER_INF in key
|
|
129
|
+
or cst.POINT_CLOUD_LAYER_SUP in key
|
|
130
|
+
or cst.POINT_CLOUD_PERFORMANCE_MAP_ROOT in key
|
|
131
|
+
):
|
|
132
|
+
cloud_indexes_with_types[key] = "float32"
|
|
133
|
+
|
|
134
|
+
# Add mask index
|
|
135
|
+
if cst.EPI_MSK in cloud_sample:
|
|
136
|
+
cloud_indexes_with_types[cst.POINT_CLOUD_MSK] = "uint8"
|
|
137
|
+
|
|
138
|
+
# Add color indexes
|
|
139
|
+
if cst.EPI_TEXTURE in cloud_sample:
|
|
140
|
+
band_color = list(cloud_sample.coords[cst.BAND_IM].to_numpy())
|
|
141
|
+
color_type = "float32"
|
|
142
|
+
if "color_type" in cloud_sample.attrs:
|
|
143
|
+
color_type = cloud_sample.attrs["color_type"]
|
|
144
|
+
for band in band_color:
|
|
145
|
+
band_index = "{}_{}".format(cst.POINT_CLOUD_CLR_KEY_ROOT, band)
|
|
146
|
+
cloud_indexes_with_types[band_index] = color_type
|
|
147
|
+
|
|
148
|
+
# Add classif indexes
|
|
149
|
+
if cst.EPI_CLASSIFICATION in cloud_sample:
|
|
150
|
+
band_classif = list(cloud_sample.coords[cst.BAND_CLASSIF].to_numpy())
|
|
151
|
+
for band in band_classif:
|
|
152
|
+
band_index = "{}_{}".format(cst.POINT_CLOUD_CLASSIF_KEY_ROOT, band)
|
|
153
|
+
cloud_indexes_with_types[band_index] = "boolean"
|
|
154
|
+
|
|
155
|
+
# Add filling information indexes
|
|
156
|
+
if cst.EPI_FILLING in cloud_sample:
|
|
157
|
+
band_filling = list(cloud_sample.coords[cst.BAND_FILLING].to_numpy())
|
|
158
|
+
for band in band_filling:
|
|
159
|
+
band_index = "{}_{}".format(cst.POINT_CLOUD_FILLING_KEY_ROOT, band)
|
|
160
|
+
cloud_indexes_with_types[band_index] = "uint8"
|
|
161
|
+
|
|
162
|
+
# Add ambiguity information index
|
|
163
|
+
if cst.EPI_AMBIGUITY in cloud_sample:
|
|
164
|
+
cloud_indexes_with_types[cst.EPI_AMBIGUITY] = "float32"
|
|
165
|
+
|
|
166
|
+
return cloud_indexes_with_types
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# pylint: disable=too-many-positional-arguments
|
|
170
|
+
def add_information_to_cloud(
|
|
171
|
+
input_cloud, cloud_indexes, bbox, target_cloud, input_array, output_column
|
|
172
|
+
):
|
|
173
|
+
"""
|
|
174
|
+
Add color information for a current cloud_list item
|
|
175
|
+
|
|
176
|
+
:param cloud: source point cloud dataset
|
|
177
|
+
:type cloud: xr.Dataset
|
|
178
|
+
:param cloud_indexes: list of band data to extract
|
|
179
|
+
:type cloud_indexes: list[str]
|
|
180
|
+
:param bbox: bbox of interest
|
|
181
|
+
:type bbox: list[int]
|
|
182
|
+
:param crop_cloud: target flatten point cloud
|
|
183
|
+
:type crop_cloud: np.array[columns, points]
|
|
184
|
+
:param input_array: index of input to extract from cloud
|
|
185
|
+
:type input_array: str
|
|
186
|
+
:param output_column: index of crop_cloud to fill
|
|
187
|
+
:type input_array: str
|
|
188
|
+
"""
|
|
189
|
+
if input_array in input_cloud:
|
|
190
|
+
full_array = input_cloud[input_array]
|
|
191
|
+
if len(full_array.shape) == 3:
|
|
192
|
+
# Array with multiple bands
|
|
193
|
+
array = full_array[:, bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1]
|
|
194
|
+
for column_name in cloud_indexes:
|
|
195
|
+
if output_column in column_name:
|
|
196
|
+
band_name = column_name.replace(output_column + "_", "")
|
|
197
|
+
band = array.loc[band_name]
|
|
198
|
+
index = cloud_indexes.index(column_name)
|
|
199
|
+
target_cloud[index, :] = np.ravel(band.values)
|
|
200
|
+
elif len(full_array.shape) == 2:
|
|
201
|
+
# Array with single band
|
|
202
|
+
array = full_array[bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1]
|
|
203
|
+
index = cloud_indexes.index(output_column)
|
|
204
|
+
target_cloud[index, :] = np.ravel(array.values)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def get_color_type(clouds):
|
|
208
|
+
"""
|
|
209
|
+
Get color type of the tiles and if the same type.
|
|
210
|
+
|
|
211
|
+
:param cloud_list: list of clouds
|
|
212
|
+
:type cloud_list: xarray Dataset
|
|
213
|
+
|
|
214
|
+
:return: color type of the tiles list
|
|
215
|
+
:rtype: str
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
color_types = []
|
|
219
|
+
for cloud_id, cloud_item in enumerate(clouds):
|
|
220
|
+
if cst.EPI_TEXTURE in clouds[cloud_id]:
|
|
221
|
+
if "color_type" in cloud_item.attrs:
|
|
222
|
+
color_types.append(cloud_item.attrs["color_type"])
|
|
223
|
+
if color_types:
|
|
224
|
+
color_type_set = set(color_types)
|
|
225
|
+
if len(color_type_set) > 1:
|
|
226
|
+
logging.warning("The tiles colors don't have the same type.")
|
|
227
|
+
return color_types[0]
|
|
228
|
+
|
|
229
|
+
return None
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def filter_cloud(
|
|
233
|
+
cloud: pd.DataFrame,
|
|
234
|
+
index_elt_to_remove: List[int],
|
|
235
|
+
filtered_elt_pos: bool = False,
|
|
236
|
+
) -> Tuple[pd.DataFrame, Union[None, pd.DataFrame]]:
|
|
237
|
+
"""
|
|
238
|
+
Filter all points of the cloud DataFrame
|
|
239
|
+
which index is in the index_elt_to_remove list.
|
|
240
|
+
|
|
241
|
+
If filtered_elt_pos is set to True, the information of the removed elements
|
|
242
|
+
positions in their original epipolar images are returned.
|
|
243
|
+
|
|
244
|
+
To do so the cloud DataFrame has to be build
|
|
245
|
+
with the 'with_coords' option activated.
|
|
246
|
+
|
|
247
|
+
:param cloud: combined cloud
|
|
248
|
+
as returned by the create_combined_cloud function
|
|
249
|
+
:param index_elt_to_remove: indexes of lines
|
|
250
|
+
to filter in the cloud DataFrame
|
|
251
|
+
:param filtered_elt_pos: if filtered_elt_pos is set to True,
|
|
252
|
+
the removed points positions in their original epipolar images are
|
|
253
|
+
returned, otherwise it is set to None
|
|
254
|
+
:return: Tuple composed of the filtered cloud DataFrame and
|
|
255
|
+
the filtered elements epipolar position information
|
|
256
|
+
(or None for the latter if filtered_elt_pos is set to False
|
|
257
|
+
or if the cloud Dataframe has not been build with with_coords option)
|
|
258
|
+
"""
|
|
259
|
+
if filtered_elt_pos and not (
|
|
260
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_I in cloud.columns
|
|
261
|
+
and cst.POINT_CLOUD_COORD_EPI_GEOM_J in cloud.columns
|
|
262
|
+
and cst.POINT_CLOUD_ID_IM_EPI in cloud.columns
|
|
263
|
+
):
|
|
264
|
+
logging.warning(
|
|
265
|
+
"In filter_cloud: the filtered_elt_pos has been activated but "
|
|
266
|
+
"the cloud Datafram has not been build with option with_coords. "
|
|
267
|
+
"The positions cannot be retrieved."
|
|
268
|
+
)
|
|
269
|
+
filtered_elt_pos = False
|
|
270
|
+
|
|
271
|
+
# retrieve removed points position in their original epipolar images
|
|
272
|
+
if filtered_elt_pos:
|
|
273
|
+
labels = [
|
|
274
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_I,
|
|
275
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_J,
|
|
276
|
+
cst.POINT_CLOUD_ID_IM_EPI,
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
removed_elt_pos_infos = cloud.loc[
|
|
280
|
+
cloud.index.values[index_elt_to_remove], labels
|
|
281
|
+
].values
|
|
282
|
+
|
|
283
|
+
removed_elt_pos_infos = pd.DataFrame(
|
|
284
|
+
removed_elt_pos_infos, columns=labels
|
|
285
|
+
)
|
|
286
|
+
else:
|
|
287
|
+
removed_elt_pos_infos = None
|
|
288
|
+
|
|
289
|
+
# remove points from the cloud
|
|
290
|
+
cloud = cloud.drop(index=cloud.index.values[index_elt_to_remove])
|
|
291
|
+
|
|
292
|
+
return cloud, removed_elt_pos_infos
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# pylint: disable=too-many-positional-arguments
|
|
296
|
+
def depth_map_dataset_to_dataframe( # noqa: C901
|
|
297
|
+
cloud_dataset: xr.Dataset,
|
|
298
|
+
dsm_epsg: int,
|
|
299
|
+
xmin: float = None,
|
|
300
|
+
xmax: float = None,
|
|
301
|
+
ymin: int = None,
|
|
302
|
+
ymax: int = None,
|
|
303
|
+
margin: float = 0,
|
|
304
|
+
with_coords: bool = False,
|
|
305
|
+
) -> Tuple[pd.DataFrame, int]:
|
|
306
|
+
"""
|
|
307
|
+
Combine a list of clouds (and their colors) into a pandas dataframe
|
|
308
|
+
structured with the following labels:
|
|
309
|
+
|
|
310
|
+
- if no colors in input and no mask data present in cloud_list datasets:
|
|
311
|
+
labels=[cst.X, cst.Y, cst.Z] \
|
|
312
|
+
The combined cloud has x, y, z columns
|
|
313
|
+
|
|
314
|
+
- if no colors in input and mask data present in cloud_list datasets:
|
|
315
|
+
labels=[cst.X, cst.Y, cst.Z, cst.POINT_CLOUD_MSK]\
|
|
316
|
+
The mask values are added to the dataframe.
|
|
317
|
+
|
|
318
|
+
- if colors are set in input and mask data are present \
|
|
319
|
+
in the cloud_list datasets:
|
|
320
|
+
labels=[cst.X, cst.Y, cst.Z, cst.POINT_CLOUD_MSK,\
|
|
321
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT+"0",\
|
|
322
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT+"1",\
|
|
323
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT+"2"]\
|
|
324
|
+
Color channels information are added to the dataframe.
|
|
325
|
+
|
|
326
|
+
- if colors in input, mask data present in the cloud_list datasets and\
|
|
327
|
+
the with_coords option is activated:
|
|
328
|
+
labels=[cst.X, cst.Y, cst.Z, cst.POINT_CLOUD_MSK,\
|
|
329
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT+"0",\
|
|
330
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT+"1",\
|
|
331
|
+
cst.POINT_CLOUD_CLR_KEY_ROOT+"2"\
|
|
332
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_I,\
|
|
333
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_J,\
|
|
334
|
+
cst.POINT_CLOUD_ID_IM_EPI]\
|
|
335
|
+
The pixel position of the xyz point in the original epipolar\
|
|
336
|
+
image (coord_epi_geom_i, coord_epi_geom_j) are added\
|
|
337
|
+
to the dataframe along with the index of its original cloud\
|
|
338
|
+
in the cloud_list input.
|
|
339
|
+
- if confidence intervals on Z in input, then\
|
|
340
|
+
[cst.Z_INF, cst.Z_SUP] are also added to the labels
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
:param dsm_epsg: epsg code for the CRS of the final output raster
|
|
344
|
+
:param xmin: xmin of the rasterization grid
|
|
345
|
+
(if None, the whole clouds are combined)
|
|
346
|
+
:param xmax: xmax of the rasterization grid
|
|
347
|
+
(if None, the whole clouds are combined)
|
|
348
|
+
:param ymin: ymin of the rasterization grid
|
|
349
|
+
(if None, the whole clouds are combined)
|
|
350
|
+
:param ymax: ymax of the rasterization grid
|
|
351
|
+
(if None, the whole clouds are combined)
|
|
352
|
+
:param margin: Margin added for each tile, in meter or degree.
|
|
353
|
+
(default value: 0)
|
|
354
|
+
:param with_coords: Option enabling the adding to the combined cloud
|
|
355
|
+
of information of each point to retrieve their positions
|
|
356
|
+
in the original epipolar images
|
|
357
|
+
:return: Tuple formed with the combined clouds and color
|
|
358
|
+
in a single pandas dataframe and the epsg code
|
|
359
|
+
"""
|
|
360
|
+
epsg = int(cloud_dataset.attrs[cst.EPSG])
|
|
361
|
+
|
|
362
|
+
# Compute margin/roi and final number of data to add to the combined cloud
|
|
363
|
+
roi = (
|
|
364
|
+
xmin is not None
|
|
365
|
+
and xmax is not None
|
|
366
|
+
and ymin is not None
|
|
367
|
+
and ymax is not None
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
# Create point cloud index
|
|
371
|
+
cloud_indexes_with_types = create_point_cloud_index(cloud_dataset)
|
|
372
|
+
|
|
373
|
+
# Add coords
|
|
374
|
+
if with_coords:
|
|
375
|
+
cloud_indexes_with_types.update(
|
|
376
|
+
{
|
|
377
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_I: "uint16",
|
|
378
|
+
cst.POINT_CLOUD_COORD_EPI_GEOM_J: "uint16",
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
cloud_indexes = list(cloud_indexes_with_types.keys())
|
|
383
|
+
|
|
384
|
+
# crop point cloud if is not created from tif depth maps
|
|
385
|
+
if (
|
|
386
|
+
cst.EPI_MARGINS in cloud_dataset.attrs
|
|
387
|
+
and cst.ROI in cloud_dataset.attrs
|
|
388
|
+
):
|
|
389
|
+
ref_roi, _, _ = dense_matching_wrappers.compute_cropped_roi(
|
|
390
|
+
cloud_dataset.attrs[cst.EPI_MARGINS],
|
|
391
|
+
0,
|
|
392
|
+
cloud_dataset.attrs[cst.ROI],
|
|
393
|
+
cloud_dataset.sizes[cst.ROW],
|
|
394
|
+
cloud_dataset.sizes[cst.COL],
|
|
395
|
+
)
|
|
396
|
+
cloud_dataset = cloud_dataset.isel(
|
|
397
|
+
row=slice(ref_roi[1], ref_roi[3]),
|
|
398
|
+
col=slice(ref_roi[0], ref_roi[2]),
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
full_x = cloud_dataset[cst.X].values
|
|
402
|
+
full_y = cloud_dataset[cst.Y].values
|
|
403
|
+
full_z = cloud_dataset[cst.Z].values
|
|
404
|
+
|
|
405
|
+
# get mask of points inside the roi (plus margins)
|
|
406
|
+
if roi:
|
|
407
|
+
# Compute terrain tile bounds
|
|
408
|
+
# if the point clouds are not in the same referential as the roi,
|
|
409
|
+
# it is converted using the dsm_epsg
|
|
410
|
+
(
|
|
411
|
+
terrain_tile_data_msk,
|
|
412
|
+
terrain_tile_data_msk_pos,
|
|
413
|
+
) = compute_terrain_msk(
|
|
414
|
+
dsm_epsg,
|
|
415
|
+
xmin,
|
|
416
|
+
xmax,
|
|
417
|
+
ymin,
|
|
418
|
+
ymax,
|
|
419
|
+
margin,
|
|
420
|
+
epsg,
|
|
421
|
+
cloud_dataset,
|
|
422
|
+
full_x,
|
|
423
|
+
full_y,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
# if the point clouds are not in the same referential as the roi,
|
|
427
|
+
# retrieve the initial values
|
|
428
|
+
if epsg != dsm_epsg:
|
|
429
|
+
full_x = cloud_dataset[cst.X].values
|
|
430
|
+
full_y = cloud_dataset[cst.Y].values
|
|
431
|
+
|
|
432
|
+
# if no point is found, return Empty cloud
|
|
433
|
+
if terrain_tile_data_msk_pos[0].shape[0] == 0:
|
|
434
|
+
logging.error("No points found to transform")
|
|
435
|
+
return pd.DataFrame(columns=cloud_indexes), epsg
|
|
436
|
+
|
|
437
|
+
# get useful data bounding box
|
|
438
|
+
bbox = [
|
|
439
|
+
np.min(terrain_tile_data_msk_pos[0]),
|
|
440
|
+
np.min(terrain_tile_data_msk_pos[1]),
|
|
441
|
+
np.max(terrain_tile_data_msk_pos[0]),
|
|
442
|
+
np.max(terrain_tile_data_msk_pos[1]),
|
|
443
|
+
]
|
|
444
|
+
else:
|
|
445
|
+
bbox = [0, 0, full_y.shape[0] - 1, full_y.shape[1] - 1]
|
|
446
|
+
|
|
447
|
+
# add (x, y, z) information to the current cloud
|
|
448
|
+
crop_x = full_x[bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1]
|
|
449
|
+
crop_y = full_y[bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1]
|
|
450
|
+
crop_z = full_z[bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1]
|
|
451
|
+
|
|
452
|
+
flatten_cloud = np.zeros(
|
|
453
|
+
(
|
|
454
|
+
len(cloud_indexes),
|
|
455
|
+
(bbox[2] - bbox[0] + 1) * (bbox[3] - bbox[1] + 1),
|
|
456
|
+
)
|
|
457
|
+
)
|
|
458
|
+
flatten_cloud[cloud_indexes.index(cst.X), :] = np.ravel(crop_x)
|
|
459
|
+
flatten_cloud[cloud_indexes.index(cst.Y), :] = np.ravel(crop_y)
|
|
460
|
+
flatten_cloud[cloud_indexes.index(cst.Z), :] = np.ravel(crop_z)
|
|
461
|
+
|
|
462
|
+
# add additional information to point cloud
|
|
463
|
+
arrays_to_add_to_point_cloud = [
|
|
464
|
+
(cst.EPI_TEXTURE, cst.POINT_CLOUD_CLR_KEY_ROOT),
|
|
465
|
+
(cst.EPI_MSK, cst.POINT_CLOUD_MSK),
|
|
466
|
+
(cst.EPI_CLASSIFICATION, cst.POINT_CLOUD_CLASSIF_KEY_ROOT),
|
|
467
|
+
(cst.EPI_FILLING, cst.POINT_CLOUD_FILLING_KEY_ROOT),
|
|
468
|
+
]
|
|
469
|
+
|
|
470
|
+
# Add layer inf and sup
|
|
471
|
+
for array_name in cloud_dataset:
|
|
472
|
+
if cst.POINT_CLOUD_LAYER_SUP_OR_INF_ROOT in array_name:
|
|
473
|
+
arrays_to_add_to_point_cloud.append((array_name, array_name))
|
|
474
|
+
|
|
475
|
+
# add performance map
|
|
476
|
+
for array_name in cloud_dataset:
|
|
477
|
+
if cst.POINT_CLOUD_PERFORMANCE_MAP_ROOT in array_name:
|
|
478
|
+
arrays_to_add_to_point_cloud.append((array_name, array_name))
|
|
479
|
+
|
|
480
|
+
# add ambiguity layer, drop confidence_* layers
|
|
481
|
+
for array_name in cloud_dataset:
|
|
482
|
+
if (
|
|
483
|
+
cst.EPI_AMBIGUITY in array_name
|
|
484
|
+
and cst.EPI_CONFIDENCE_KEY_ROOT not in array_name
|
|
485
|
+
):
|
|
486
|
+
arrays_to_add_to_point_cloud.append((array_name, array_name))
|
|
487
|
+
|
|
488
|
+
# add denoising info layers
|
|
489
|
+
for array_name in cloud_dataset:
|
|
490
|
+
if cst.EPI_DENOISING_INFO_KEY_ROOT in array_name:
|
|
491
|
+
arrays_to_add_to_point_cloud.append((array_name, array_name))
|
|
492
|
+
|
|
493
|
+
for input_band, output_column in arrays_to_add_to_point_cloud:
|
|
494
|
+
add_information_to_cloud(
|
|
495
|
+
cloud_dataset,
|
|
496
|
+
cloud_indexes,
|
|
497
|
+
bbox,
|
|
498
|
+
flatten_cloud,
|
|
499
|
+
input_band,
|
|
500
|
+
output_column,
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
# add the original image coordinates information to the current cloud
|
|
504
|
+
if with_coords:
|
|
505
|
+
coords_line = np.linspace(bbox[0], bbox[2], bbox[2] - bbox[0] + 1)
|
|
506
|
+
coords_col = np.linspace(bbox[1], bbox[3], bbox[3] - bbox[1] + 1)
|
|
507
|
+
coords_col, coords_line = np.meshgrid(coords_col, coords_line)
|
|
508
|
+
|
|
509
|
+
flatten_cloud[
|
|
510
|
+
cloud_indexes.index(cst.POINT_CLOUD_COORD_EPI_GEOM_I), :
|
|
511
|
+
] = np.ravel(coords_line)
|
|
512
|
+
flatten_cloud[
|
|
513
|
+
cloud_indexes.index(cst.POINT_CLOUD_COORD_EPI_GEOM_J), :
|
|
514
|
+
] = np.ravel(coords_col)
|
|
515
|
+
|
|
516
|
+
# Transpose point cloud
|
|
517
|
+
flatten_cloud = flatten_cloud.transpose()
|
|
518
|
+
|
|
519
|
+
# remove masked data (pandora + out of the terrain tile points)
|
|
520
|
+
crop_terrain_tile_data_msk = (
|
|
521
|
+
cloud_dataset[cst.POINT_CLOUD_CORR_MSK].values[
|
|
522
|
+
bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1
|
|
523
|
+
]
|
|
524
|
+
== 255
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
if roi:
|
|
528
|
+
crop_terrain_tile_data_msk = np.logical_and(
|
|
529
|
+
crop_terrain_tile_data_msk,
|
|
530
|
+
terrain_tile_data_msk[bbox[0] : bbox[2] + 1, bbox[1] : bbox[3] + 1],
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
flatten_cloud = filter_cloud_with_mask(
|
|
534
|
+
flatten_cloud, crop_terrain_tile_data_msk
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
# Remove points with nan values on X, Y or Z
|
|
538
|
+
xyz_indexes = np.array(
|
|
539
|
+
[
|
|
540
|
+
cloud_indexes.index(cst.X),
|
|
541
|
+
cloud_indexes.index(cst.Y),
|
|
542
|
+
cloud_indexes.index(cst.Z),
|
|
543
|
+
]
|
|
544
|
+
)
|
|
545
|
+
flatten_cloud = flatten_cloud[
|
|
546
|
+
~np.any(np.isnan(flatten_cloud[:, xyz_indexes]), axis=1)
|
|
547
|
+
]
|
|
548
|
+
|
|
549
|
+
pd_cloud = pd.DataFrame(flatten_cloud, columns=cloud_indexes)
|
|
550
|
+
pd_cloud = pd_cloud.astype(cloud_indexes_with_types)
|
|
551
|
+
|
|
552
|
+
return pd_cloud, epsg
|