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,74 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
cars_dict module:
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CarsDict:
|
|
28
|
+
"""
|
|
29
|
+
CarsDict.
|
|
30
|
+
|
|
31
|
+
Internal CARS structure for dict representation
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, dict_data, attributes=None):
|
|
35
|
+
"""
|
|
36
|
+
Init function of CarsDict.
|
|
37
|
+
If a path is provided, restore CarsDataset saved on disk.
|
|
38
|
+
|
|
39
|
+
:param dict_data: dictrionary to store
|
|
40
|
+
:type dict_data: dict
|
|
41
|
+
:param attributes: attributes
|
|
42
|
+
:type attributes: dict
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
self.data = dict_data
|
|
47
|
+
self.attrs = attributes
|
|
48
|
+
if self.attrs is None:
|
|
49
|
+
self.attrs = {}
|
|
50
|
+
|
|
51
|
+
def __repr__(self):
|
|
52
|
+
"""
|
|
53
|
+
Repr function
|
|
54
|
+
:return: printable self CarsDataset
|
|
55
|
+
"""
|
|
56
|
+
return self.custom_print()
|
|
57
|
+
|
|
58
|
+
def __str__(self):
|
|
59
|
+
"""
|
|
60
|
+
Str function
|
|
61
|
+
:return: printable self CarsDataset
|
|
62
|
+
"""
|
|
63
|
+
return self.custom_print()
|
|
64
|
+
|
|
65
|
+
def custom_print(self):
|
|
66
|
+
"""
|
|
67
|
+
Return string of self
|
|
68
|
+
:return: printable self
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
res = str(self.__class__) + ": \n" "data: " + str(
|
|
72
|
+
self.data
|
|
73
|
+
) + "\n" + "attrs: " + str(self.attrs)
|
|
74
|
+
return res
|
|
@@ -0,0 +1,186 @@
|
|
|
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
|
+
Contains functions for array reconstructions and crop for multiple tiles
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Third party imports
|
|
27
|
+
import numpy as np
|
|
28
|
+
import xarray as xr
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def reconstruct_data(tiles, window, overlap): # noqa: C901
|
|
32
|
+
"""
|
|
33
|
+
Combine list of tiles (window, overlap, xr.Dataset) as
|
|
34
|
+
one full dataset
|
|
35
|
+
|
|
36
|
+
:param tiles: list of tiles
|
|
37
|
+
:type tiles: list(tuple)
|
|
38
|
+
:param window: window of base tile [row min, row max, col min col max]
|
|
39
|
+
:type window: list
|
|
40
|
+
:param overlap: overlap of base tile [row min, row max, col min col max]
|
|
41
|
+
:type overlap: list
|
|
42
|
+
|
|
43
|
+
:return: full dataset, row min of combined, col min of combined
|
|
44
|
+
:rtype: xr.Dataset, int, int
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
first_valid_tile = next(
|
|
49
|
+
(tile for tile in tiles if tile[2] is not None), None
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if first_valid_tile is None:
|
|
53
|
+
return None, None, None
|
|
54
|
+
|
|
55
|
+
list_tags = list(first_valid_tile[2].keys())
|
|
56
|
+
|
|
57
|
+
row_min, row_max, col_min, col_max = window
|
|
58
|
+
ol_row_min, ol_row_max, ol_col_min, ol_col_max = overlap
|
|
59
|
+
|
|
60
|
+
# find whole window and new overlaps
|
|
61
|
+
for tile_window, tile_overlap, _ in tiles:
|
|
62
|
+
if tile_window[0] < row_min:
|
|
63
|
+
row_min, ol_row_min = tile_window[0], tile_overlap[0]
|
|
64
|
+
if tile_window[1] > row_max:
|
|
65
|
+
row_max, ol_row_max = tile_window[1], tile_overlap[1]
|
|
66
|
+
if tile_window[2] < col_min:
|
|
67
|
+
col_min, ol_col_min = tile_window[2], tile_overlap[2]
|
|
68
|
+
if tile_window[3] > col_max:
|
|
69
|
+
col_max, ol_col_max = tile_window[3], tile_overlap[3]
|
|
70
|
+
|
|
71
|
+
# Generate new arr
|
|
72
|
+
|
|
73
|
+
# Compute full shape
|
|
74
|
+
nb_rows = int(row_max + ol_row_max - (row_min - ol_row_min))
|
|
75
|
+
nb_cols = int(col_max + ol_col_max - (col_min - ol_col_min))
|
|
76
|
+
|
|
77
|
+
new_coords = {}
|
|
78
|
+
for key in first_valid_tile[2].coords.keys():
|
|
79
|
+
if key == "row":
|
|
80
|
+
new_coords["row"] = range(
|
|
81
|
+
int(row_min - ol_row_min), int(row_max + ol_row_max)
|
|
82
|
+
)
|
|
83
|
+
elif key == "col":
|
|
84
|
+
new_coords["col"] = range(
|
|
85
|
+
int(col_min - ol_col_min), int(col_max + ol_col_max)
|
|
86
|
+
)
|
|
87
|
+
elif key == "y":
|
|
88
|
+
# Doesnt contain coordinates, but pixels position
|
|
89
|
+
# after reconstruction, only used in notebooks
|
|
90
|
+
new_coords["y"] = range(
|
|
91
|
+
int(row_min - ol_row_min), int(row_max + ol_row_max)
|
|
92
|
+
)
|
|
93
|
+
elif key == "x":
|
|
94
|
+
# Doesnt contain coordinates, but pixels position
|
|
95
|
+
# after reconstruction, only used in notebooks
|
|
96
|
+
new_coords["x"] = range(
|
|
97
|
+
int(col_min - ol_col_min), int(col_max + ol_col_max)
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
new_coords[key] = first_valid_tile[2].coords[key]
|
|
101
|
+
|
|
102
|
+
new_dataset = xr.Dataset(data_vars={}, coords=new_coords)
|
|
103
|
+
|
|
104
|
+
for tag in list_tags:
|
|
105
|
+
# reconstruct data
|
|
106
|
+
data_type = first_valid_tile[2][tag].dtype
|
|
107
|
+
data_shape = (nb_rows, nb_cols)
|
|
108
|
+
dims = first_valid_tile[2][tag].dims
|
|
109
|
+
if len(dims) == 3:
|
|
110
|
+
nb_bands = first_valid_tile[2][tag].values.shape[0]
|
|
111
|
+
data_shape = (nb_bands, nb_rows, nb_cols)
|
|
112
|
+
data = np.nan * np.zeros(data_shape)
|
|
113
|
+
|
|
114
|
+
for tile_window, tile_overlap, tile_ds in tiles:
|
|
115
|
+
# only use overlaps when on the border of full image
|
|
116
|
+
# row min
|
|
117
|
+
if row_min == tile_window[0]:
|
|
118
|
+
# is on border -> use overlap
|
|
119
|
+
real_row_min = int(tile_window[0])
|
|
120
|
+
getter_offset_row_min = int(0)
|
|
121
|
+
else:
|
|
122
|
+
real_row_min = int(tile_window[0] + ol_row_min)
|
|
123
|
+
getter_offset_row_min = int(tile_overlap[0])
|
|
124
|
+
|
|
125
|
+
# row max
|
|
126
|
+
if row_max == tile_window[1]:
|
|
127
|
+
# is on border -> use overlap
|
|
128
|
+
real_row_max = int(tile_window[1] + ol_row_max + ol_row_min)
|
|
129
|
+
getter_offset_row_max = int(0)
|
|
130
|
+
else:
|
|
131
|
+
real_row_max = int(tile_window[1] + ol_row_min)
|
|
132
|
+
getter_offset_row_max = int(tile_overlap[1])
|
|
133
|
+
|
|
134
|
+
# col min
|
|
135
|
+
if col_min == tile_window[2]:
|
|
136
|
+
# is on border -> use overlap
|
|
137
|
+
real_col_min = int(tile_window[2])
|
|
138
|
+
getter_offset_col_min = int(0)
|
|
139
|
+
else:
|
|
140
|
+
real_col_min = int(tile_window[2] + ol_col_min)
|
|
141
|
+
getter_offset_col_min = int(tile_overlap[2])
|
|
142
|
+
|
|
143
|
+
# col max
|
|
144
|
+
if col_max == tile_window[3]:
|
|
145
|
+
# is on border -> use overlap
|
|
146
|
+
real_col_max = int(tile_window[3] + ol_col_max + ol_col_min)
|
|
147
|
+
getter_offset_col_max = int(0)
|
|
148
|
+
else:
|
|
149
|
+
real_col_max = int(tile_window[3] + ol_col_min)
|
|
150
|
+
getter_offset_col_max = int(tile_overlap[3])
|
|
151
|
+
|
|
152
|
+
real_row_min = int(real_row_min - row_min)
|
|
153
|
+
real_row_max = int(real_row_max - row_min)
|
|
154
|
+
real_col_min = int(real_col_min - col_min)
|
|
155
|
+
real_col_max = int(real_col_max - col_min)
|
|
156
|
+
|
|
157
|
+
# Fill data
|
|
158
|
+
if tile_ds is not None:
|
|
159
|
+
tile_data = tile_ds[tag].values
|
|
160
|
+
|
|
161
|
+
if len(tile_data.shape) == 2:
|
|
162
|
+
data[
|
|
163
|
+
real_row_min:real_row_max, real_col_min:real_col_max
|
|
164
|
+
] = tile_data[
|
|
165
|
+
getter_offset_row_min : tile_data.shape[0]
|
|
166
|
+
- getter_offset_row_max,
|
|
167
|
+
getter_offset_col_min : tile_data.shape[1]
|
|
168
|
+
- getter_offset_col_max,
|
|
169
|
+
]
|
|
170
|
+
else:
|
|
171
|
+
data[
|
|
172
|
+
:, real_row_min:real_row_max, real_col_min:real_col_max
|
|
173
|
+
] = tile_data[
|
|
174
|
+
:,
|
|
175
|
+
getter_offset_row_min : tile_data.shape[1]
|
|
176
|
+
- getter_offset_row_max,
|
|
177
|
+
getter_offset_col_min : tile_data.shape[2]
|
|
178
|
+
- getter_offset_col_max,
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
# add arrays to data
|
|
182
|
+
new_dataset[tag] = xr.DataArray(
|
|
183
|
+
data,
|
|
184
|
+
dims=dims,
|
|
185
|
+
).astype(data_type)
|
|
186
|
+
return new_dataset, row_min - ol_row_min, col_min - ol_col_min
|
|
@@ -0,0 +1,185 @@
|
|
|
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
|
+
Contains function to convert the point cloud dataframe to laz format:
|
|
23
|
+
"""
|
|
24
|
+
import logging
|
|
25
|
+
import warnings
|
|
26
|
+
|
|
27
|
+
import laspy
|
|
28
|
+
import laspy.file
|
|
29
|
+
import laspy.header
|
|
30
|
+
import numpy as np
|
|
31
|
+
from pyproj import CRS
|
|
32
|
+
|
|
33
|
+
import cars.core.constants as cst
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def convert_pcl_to_laz(point_clouds, output_filename: str):
|
|
37
|
+
"""
|
|
38
|
+
Convert 3d point cloud to laz format
|
|
39
|
+
:param point_clouds: point_clouds dataframe
|
|
40
|
+
:param output_filename: output laz filename (with naming convention)
|
|
41
|
+
:return: the list of point cloud save in las format
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# get all layer : X, Y, Z and color
|
|
45
|
+
coordinates = ["X", "Y", "Z"]
|
|
46
|
+
las_color = ["red", "green", "blue"]
|
|
47
|
+
color_type = point_clouds.attrs["attributes"]["color_type"]
|
|
48
|
+
epsg = point_clouds.attrs["attributes"]["epsg"]
|
|
49
|
+
input_color = get_input_color(point_clouds)
|
|
50
|
+
laz_file_name = output_filename
|
|
51
|
+
arrays_pcl, arrays_color = extract_point_cloud(
|
|
52
|
+
point_clouds, coordinates, input_color, color_type
|
|
53
|
+
)
|
|
54
|
+
# generate laz
|
|
55
|
+
generate_laz(
|
|
56
|
+
laz_file_name, coordinates, las_color, arrays_pcl, arrays_color
|
|
57
|
+
)
|
|
58
|
+
# dump prj file
|
|
59
|
+
generate_prj_file(laz_file_name, epsg)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_input_color(point_clouds):
|
|
63
|
+
"""
|
|
64
|
+
Retrieve color index from point cloud
|
|
65
|
+
:param point_clouds: point clouds data
|
|
66
|
+
:return: input color list
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
input_color = ["color_R", "color_G", "color_B"]
|
|
70
|
+
color_names = [
|
|
71
|
+
name
|
|
72
|
+
for name in point_clouds.columns
|
|
73
|
+
if cst.POINT_CLOUD_CLR_KEY_ROOT in name
|
|
74
|
+
]
|
|
75
|
+
nb_color = len(color_names)
|
|
76
|
+
if nb_color == 1:
|
|
77
|
+
logging.warning("No color available for point cloud")
|
|
78
|
+
input_color = color_names
|
|
79
|
+
elif sorted(color_names[:3]) != sorted(input_color):
|
|
80
|
+
logging.warning(
|
|
81
|
+
"Descriptions of color bands {} does not conform to names "
|
|
82
|
+
"'R', 'G', 'B'".format(color_names[:3])
|
|
83
|
+
)
|
|
84
|
+
input_color = color_names[:3]
|
|
85
|
+
|
|
86
|
+
return input_color
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def extract_point_cloud(point_clouds, coordinates, input_color, color_type):
|
|
90
|
+
"""
|
|
91
|
+
Extract point cloud positions (x,y,z) and color layers
|
|
92
|
+
:param point_clouds: point cloud dataframe
|
|
93
|
+
:param coordinate: target coordinates key index
|
|
94
|
+
:param input_color: color key index according to input
|
|
95
|
+
:param color_type: type of color data
|
|
96
|
+
:param nb
|
|
97
|
+
:return: point cloud array location and color
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
nb_color = len(input_color)
|
|
101
|
+
arrays_pcl = None
|
|
102
|
+
arrays_color = None
|
|
103
|
+
for name in point_clouds.columns:
|
|
104
|
+
# get coordinates bands
|
|
105
|
+
if name in ["x", "y", "z"]:
|
|
106
|
+
array = point_clouds[name].to_numpy()
|
|
107
|
+
# first step : define np.ndarray to contains the arrays X,Y,Z
|
|
108
|
+
if arrays_pcl is None:
|
|
109
|
+
arrays_pcl = np.ndarray((3, array.reshape(-1).T.shape[0]))
|
|
110
|
+
# get only valid pixels
|
|
111
|
+
array = array.reshape(-1).T
|
|
112
|
+
# get layer into np.ndarray (laspy accept only XYZ in upper case)
|
|
113
|
+
arrays_pcl[coordinates.index(name.upper())] = array
|
|
114
|
+
elif name in input_color:
|
|
115
|
+
array = point_clouds[name].to_numpy()
|
|
116
|
+
if arrays_color is None:
|
|
117
|
+
arrays_color = np.ndarray((3, array.reshape(-1).T.shape[0]))
|
|
118
|
+
array = array.reshape(-1).T
|
|
119
|
+
maxi = 65535
|
|
120
|
+
if color_type:
|
|
121
|
+
if np.issubdtype(np.dtype(color_type), np.integer):
|
|
122
|
+
maxi = np.min([maxi, np.iinfo(np.dtype(color_type)).max])
|
|
123
|
+
array[array >= maxi] = maxi
|
|
124
|
+
array[array <= 0] = 0
|
|
125
|
+
|
|
126
|
+
arrays_color[input_color.index(name)] = array
|
|
127
|
+
if nb_color == 1:
|
|
128
|
+
arrays_color[1] = array
|
|
129
|
+
arrays_color[2] = array
|
|
130
|
+
return arrays_pcl, arrays_color
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def generate_prj_file(output_filename, epsg):
|
|
134
|
+
"""
|
|
135
|
+
Generate prj file associated to the laz file if projection is UTM or WGS84
|
|
136
|
+
:param output_filename: name of laz file
|
|
137
|
+
:param epsg: code of output epsg
|
|
138
|
+
"""
|
|
139
|
+
with warnings.catch_warnings():
|
|
140
|
+
# Ignore some crs warning
|
|
141
|
+
warnings.filterwarnings(
|
|
142
|
+
"ignore",
|
|
143
|
+
category=UserWarning,
|
|
144
|
+
message=".*You will likely lose important projection"
|
|
145
|
+
" information when converting to a PROJ string from "
|
|
146
|
+
"another format.*",
|
|
147
|
+
)
|
|
148
|
+
crs = CRS.from_epsg(epsg)
|
|
149
|
+
proj = crs.to_proj4()
|
|
150
|
+
if crs.is_geographic:
|
|
151
|
+
logging.warning(
|
|
152
|
+
"Coordinate system of point cloud is geographic: "
|
|
153
|
+
"Display of LAZ file may not work"
|
|
154
|
+
)
|
|
155
|
+
with open(output_filename + ".prj", "w", encoding="utf8") as file_prj:
|
|
156
|
+
file_prj.write(proj)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def generate_laz(
|
|
160
|
+
output_filename, coordinates, las_color, arrays_pcl, arrays_color
|
|
161
|
+
):
|
|
162
|
+
"""
|
|
163
|
+
Generate laz file from location and color arrays
|
|
164
|
+
"""
|
|
165
|
+
# Create laz image
|
|
166
|
+
header = laspy.LasHeader(point_format=2)
|
|
167
|
+
scale_factor = 0.01
|
|
168
|
+
header.scales = [scale_factor, scale_factor, scale_factor]
|
|
169
|
+
laz = laspy.LasData(header)
|
|
170
|
+
# fill X,Y,Z into laspy structure, convert to cm
|
|
171
|
+
scale_multiplicator = 1 / scale_factor
|
|
172
|
+
for layer_index in range(arrays_pcl.shape[0]):
|
|
173
|
+
setattr(
|
|
174
|
+
laz,
|
|
175
|
+
[k for i, k in enumerate(coordinates) if i == layer_index][0],
|
|
176
|
+
scale_multiplicator * arrays_pcl[layer_index],
|
|
177
|
+
)
|
|
178
|
+
if arrays_color is not None:
|
|
179
|
+
for color_index in range(arrays_color.shape[0]):
|
|
180
|
+
setattr(
|
|
181
|
+
laz,
|
|
182
|
+
[k for i, k in enumerate(las_color) if i == color_index][0],
|
|
183
|
+
arrays_color[color_index],
|
|
184
|
+
)
|
|
185
|
+
laz.write(output_filename)
|