cars 1.0.0rc2__cp312-cp312-win_amd64.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 +86 -0
- cars/applications/__init__.py +40 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +597 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +278 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
- cars/applications/dsm_merging/__init__.py +28 -0
- cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
- cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
- cars/applications/grid_correction/__init__.py +30 -0
- cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
- cars/applications/grid_correction/grid_correction_app.py +557 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +639 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +760 -0
- cars/applications/resampling/resampling_algo.py +590 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sensors_subsampling/__init__.py +32 -0
- cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
- cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
- cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
- cars/applications/sparse_matching/sift_app.py +724 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +750 -0
- cars/cars.py +179 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +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 +1544 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +250 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +728 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/memory_tools.py +47 -0
- cars/orchestrator/orchestrator.py +755 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +1088 -0
- cars/pipelines/filling/__init__.py +26 -0
- cars/pipelines/filling/filling.py +981 -0
- cars/pipelines/formatting/__init__.py +26 -0
- cars/pipelines/formatting/formatting.py +186 -0
- cars/pipelines/merging/__init__.py +26 -0
- cars/pipelines/merging/merging.py +439 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +256 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
- cars/pipelines/parameters/application_parameters.py +72 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +349 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +438 -0
- cars/pipelines/parameters/sensor_inputs.py +859 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +38 -0
- cars/pipelines/pipeline_template.py +135 -0
- cars/pipelines/subsampling/__init__.py +26 -0
- cars/pipelines/subsampling/subsampling.py +358 -0
- cars/pipelines/surface_modeling/__init__.py +26 -0
- cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
- cars/pipelines/tie_points/__init__.py +26 -0
- cars/pipelines/tie_points/tie_points.py +536 -0
- cars/starter.py +167 -0
- cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
- cars-1.0.0rc2.dist-info/METADATA +289 -0
- cars-1.0.0rc2.dist-info/RECORD +225 -0
- cars-1.0.0rc2.dist-info/WHEEL +4 -0
- cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
- cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
- cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
- cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
cars/core/inputs.py
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
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
|
+
Inputs module:
|
|
23
|
+
contains some CARS global shared general purpose inputs functions
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
|
|
28
|
+
# Standard imports
|
|
29
|
+
import os
|
|
30
|
+
import warnings
|
|
31
|
+
from typing import Dict, Tuple
|
|
32
|
+
|
|
33
|
+
# Third party imports
|
|
34
|
+
import fiona
|
|
35
|
+
import numpy as np
|
|
36
|
+
import rasterio as rio
|
|
37
|
+
import xarray as xr
|
|
38
|
+
from affine import Affine
|
|
39
|
+
from json_checker import Checker
|
|
40
|
+
from pyproj import CRS
|
|
41
|
+
from rasterio.warp import Resampling, calculate_default_transform, reproject
|
|
42
|
+
from rasterio.windows import Window
|
|
43
|
+
from shapely.geometry import shape
|
|
44
|
+
|
|
45
|
+
# CARS imports
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Filter rasterio warning when image is not georeferenced
|
|
49
|
+
warnings.filterwarnings("ignore", category=rio.errors.NotGeoreferencedWarning)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def read_vector(path_to_file):
|
|
53
|
+
"""
|
|
54
|
+
Read vector file and returns the corresponding polygon
|
|
55
|
+
|
|
56
|
+
:raise Exception when the input file is unreadable
|
|
57
|
+
|
|
58
|
+
:param path_to_file: path to the file to open
|
|
59
|
+
:type path_to_file: str
|
|
60
|
+
:return: a shapely polygon
|
|
61
|
+
:rtype: tuple (polygon, epsg)
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
polys = []
|
|
65
|
+
with fiona.open(path_to_file) as vec_file:
|
|
66
|
+
_, epsg = vec_file.crs["init"].split(":")
|
|
67
|
+
for feat in vec_file:
|
|
68
|
+
polys.append(shape(feat["geometry"]))
|
|
69
|
+
except BaseException as base_except:
|
|
70
|
+
raise FileNotFoundError(
|
|
71
|
+
"Impossible to read {} file".format(path_to_file)
|
|
72
|
+
) from base_except
|
|
73
|
+
|
|
74
|
+
if len(polys) == 1:
|
|
75
|
+
return polys[0], int(epsg)
|
|
76
|
+
|
|
77
|
+
if len(polys) > 1:
|
|
78
|
+
logging.info(
|
|
79
|
+
"Multi features files are not supported, "
|
|
80
|
+
"the first feature of {} will be used".format(path_to_file)
|
|
81
|
+
)
|
|
82
|
+
return polys[0], int(epsg)
|
|
83
|
+
|
|
84
|
+
logging.info("No feature is present in the {} file".format(path_to_file))
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def rasterio_get_values(raster_file: str, x_list, y_list, proj_function):
|
|
89
|
+
"""
|
|
90
|
+
Get the z position of corresponding x and y as lon lat
|
|
91
|
+
|
|
92
|
+
:param raster_file: Image file
|
|
93
|
+
:param x_list: list of x position
|
|
94
|
+
:type x_list: np array
|
|
95
|
+
:param y_list: list of y position
|
|
96
|
+
:type y_list: np array
|
|
97
|
+
:param proj_function: projection function to use
|
|
98
|
+
|
|
99
|
+
:return: The corresponding z position
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
103
|
+
file_espg = descriptor.crs.to_epsg()
|
|
104
|
+
|
|
105
|
+
nodata_value = descriptor.nodata
|
|
106
|
+
# convert point to epsg
|
|
107
|
+
cloud_in = np.stack([x_list, y_list], axis=1)
|
|
108
|
+
cloud_out = proj_function(cloud_in, 4326, file_espg)
|
|
109
|
+
|
|
110
|
+
# get the transform and inverse
|
|
111
|
+
aff_tr = rasterio_get_transform(raster_file)
|
|
112
|
+
np_tr = np.array(
|
|
113
|
+
[
|
|
114
|
+
[aff_tr[0], aff_tr[1], aff_tr[2]],
|
|
115
|
+
[aff_tr[3], aff_tr[4], aff_tr[5]],
|
|
116
|
+
[0, 0, 1],
|
|
117
|
+
]
|
|
118
|
+
)
|
|
119
|
+
inv_tr = np.linalg.inv(np_tr)
|
|
120
|
+
|
|
121
|
+
# convert sensor to pixel coordinates
|
|
122
|
+
pix_pos = np.hstack([cloud_out, np.ones((len(cloud_out), 1))])
|
|
123
|
+
pix_pos = inv_tr @ pix_pos.T
|
|
124
|
+
pix_pos = pix_pos.T[:, [1, 0]].astype(
|
|
125
|
+
int
|
|
126
|
+
) # convention (row, col) i.e. (y, x)
|
|
127
|
+
|
|
128
|
+
# crop to dem bounds
|
|
129
|
+
ul_corner = np.array([0, 0])
|
|
130
|
+
lr_corner = np.array([descriptor.height, descriptor.width])
|
|
131
|
+
pix_pos_clipped = np.clip(pix_pos, ul_corner, lr_corner)
|
|
132
|
+
out_of_bounds_pix = np.any(pix_pos != pix_pos_clipped, axis=1)
|
|
133
|
+
pix_pos = pix_pos_clipped
|
|
134
|
+
|
|
135
|
+
# get the data needed
|
|
136
|
+
min_pt = pix_pos.min(axis=0)
|
|
137
|
+
max_pt = pix_pos.max(axis=0)
|
|
138
|
+
|
|
139
|
+
height = max_pt[0] - min_pt[0] + 1
|
|
140
|
+
width = max_pt[1] - min_pt[1] + 1
|
|
141
|
+
window = Window(min_pt[1], min_pt[0], width, height)
|
|
142
|
+
|
|
143
|
+
data = descriptor.read(1, window=window)
|
|
144
|
+
if data.size == 0:
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
# read the data for all points
|
|
148
|
+
max_sampled_pos = np.array(data.shape)[:2] - 1
|
|
149
|
+
pix_pos -= min_pt
|
|
150
|
+
pix_pos[:, 0] = np.clip(pix_pos[:, 0], 0, max_sampled_pos[0])
|
|
151
|
+
pix_pos[:, 1] = np.clip(pix_pos[:, 1], 0, max_sampled_pos[1])
|
|
152
|
+
|
|
153
|
+
z_list = data[pix_pos[:, 0], pix_pos[:, 1]].astype(float)
|
|
154
|
+
|
|
155
|
+
if nodata_value is not None:
|
|
156
|
+
z_list[z_list == nodata_value] = np.nan
|
|
157
|
+
z_list[out_of_bounds_pix] = np.nan
|
|
158
|
+
|
|
159
|
+
return z_list
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def rasterio_get_nb_bands(raster_file: str) -> int:
|
|
163
|
+
"""
|
|
164
|
+
Get the number of bands in an image file
|
|
165
|
+
|
|
166
|
+
:param raster_file: Image file
|
|
167
|
+
:return: The number of bands
|
|
168
|
+
"""
|
|
169
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
170
|
+
return descriptor.count
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def rasterio_get_classif_values(raster_file: str) -> int:
|
|
174
|
+
"""
|
|
175
|
+
Get the number of bands in an image file
|
|
176
|
+
|
|
177
|
+
:param raster_file: Image file
|
|
178
|
+
:return: The number of bands
|
|
179
|
+
"""
|
|
180
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
181
|
+
max_value = int(descriptor.stats()[0].max)
|
|
182
|
+
if max_value <= 10:
|
|
183
|
+
logging.info("Max value of classif is {}")
|
|
184
|
+
values = list(range(max_value + 1))
|
|
185
|
+
logging.info("Classes are {}".format(values))
|
|
186
|
+
return values
|
|
187
|
+
logging.warning(
|
|
188
|
+
"Input classif has classes over 10"
|
|
189
|
+
"Classification file will be read to determine exact values"
|
|
190
|
+
)
|
|
191
|
+
array = descriptor.read()
|
|
192
|
+
values = list(map(int, np.unique(array)))
|
|
193
|
+
logging.info("Classes are {}".format(values))
|
|
194
|
+
return values
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def rasterio_get_tags(raster_file: str) -> dict:
|
|
198
|
+
"""
|
|
199
|
+
Get the tags in an image file
|
|
200
|
+
|
|
201
|
+
:param raster_file: Image file
|
|
202
|
+
:return: The metadata
|
|
203
|
+
"""
|
|
204
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
205
|
+
return descriptor.tags()
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def rasterio_get_image_type(raster_file: str) -> list:
|
|
209
|
+
"""
|
|
210
|
+
Get the image type
|
|
211
|
+
|
|
212
|
+
:param raster_file: Image file
|
|
213
|
+
:return: The image type
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
image_types = None
|
|
217
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
218
|
+
image_types = descriptor.dtypes
|
|
219
|
+
|
|
220
|
+
# Check if each color bands have the same type
|
|
221
|
+
image_type_set = set(image_types)
|
|
222
|
+
if len(image_type_set) > 1:
|
|
223
|
+
logging.warning("The image bands don't the same types.")
|
|
224
|
+
|
|
225
|
+
image_type = image_types[0]
|
|
226
|
+
|
|
227
|
+
return image_type
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def rasterio_get_nbits(raster_file):
|
|
231
|
+
"""
|
|
232
|
+
Get the band nbits list
|
|
233
|
+
|
|
234
|
+
:param raster_file: Image file
|
|
235
|
+
:return: The band nbits list
|
|
236
|
+
"""
|
|
237
|
+
nbits = []
|
|
238
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
239
|
+
for bidx in range(1, descriptor.count + 1):
|
|
240
|
+
img_structurre_band = descriptor.tags(
|
|
241
|
+
ns="IMAGE_STRUCTURE", bidx=bidx
|
|
242
|
+
)
|
|
243
|
+
if "NBITS" in img_structurre_band:
|
|
244
|
+
nbits.append(int(img_structurre_band["NBITS"]))
|
|
245
|
+
|
|
246
|
+
return nbits
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def rasterio_get_size(raster_file: str) -> Tuple[int, int]:
|
|
250
|
+
"""
|
|
251
|
+
Get the size of an image (file)
|
|
252
|
+
|
|
253
|
+
:param raster_file: Image file
|
|
254
|
+
:return: The size (width, height)
|
|
255
|
+
"""
|
|
256
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
257
|
+
return (descriptor.width, descriptor.height)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def rasterio_get_nodata(raster_file: str) -> Tuple[int, int]:
|
|
261
|
+
"""
|
|
262
|
+
Get the no data value
|
|
263
|
+
|
|
264
|
+
:param raster_file: Image file
|
|
265
|
+
:return: the no data value
|
|
266
|
+
"""
|
|
267
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
268
|
+
return descriptor.nodata
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def rasterio_get_dtype(raster_file: str) -> Tuple[int, int]:
|
|
272
|
+
"""
|
|
273
|
+
Get the dtype of an image (file)
|
|
274
|
+
|
|
275
|
+
:param raster_file: Image file
|
|
276
|
+
:return: The dtype
|
|
277
|
+
"""
|
|
278
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
279
|
+
return descriptor.dtypes[0]
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def rasterio_get_pixel_points(raster_file: str, terrain_points) -> list:
|
|
283
|
+
"""
|
|
284
|
+
Get pixel point coordinates of terrain points
|
|
285
|
+
|
|
286
|
+
:param raster_file: Image file
|
|
287
|
+
:param terrain_points: points in terrain
|
|
288
|
+
:return: pixel points
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
pixel_points = []
|
|
292
|
+
|
|
293
|
+
for row in range(terrain_points.shape[0]):
|
|
294
|
+
pixel_points.append(
|
|
295
|
+
rio.transform.rowcol(
|
|
296
|
+
rasterio_get_transform(raster_file),
|
|
297
|
+
terrain_points[row, 0],
|
|
298
|
+
terrain_points[row, 1],
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
return np.array(pixel_points)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def rasterio_get_resolution(raster_file: str) -> Tuple[float, float]:
|
|
306
|
+
"""
|
|
307
|
+
Get the resolution of raster_file
|
|
308
|
+
|
|
309
|
+
:param raster_file: Image file
|
|
310
|
+
:return: The resolution (res_x, res_y)
|
|
311
|
+
:rtype: tuple
|
|
312
|
+
"""
|
|
313
|
+
transform = list(rasterio_get_transform(raster_file))
|
|
314
|
+
res_x = transform[0]
|
|
315
|
+
res_y = transform[4]
|
|
316
|
+
return (abs(res_x), abs(res_y))
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def rasterio_get_bounds(
|
|
320
|
+
raster_file: str, apply_resolution_sign=False
|
|
321
|
+
) -> Tuple[int, int]:
|
|
322
|
+
"""
|
|
323
|
+
Get the bounds of an image (file)
|
|
324
|
+
|
|
325
|
+
:param raster_file: Image file
|
|
326
|
+
:return: The size (width, height)
|
|
327
|
+
"""
|
|
328
|
+
|
|
329
|
+
# get sign of resolution
|
|
330
|
+
if apply_resolution_sign:
|
|
331
|
+
transform = list(rasterio_get_transform(raster_file))
|
|
332
|
+
res_x = transform[0]
|
|
333
|
+
res_y = transform[4]
|
|
334
|
+
res_x /= abs(res_x)
|
|
335
|
+
res_y /= abs(res_y)
|
|
336
|
+
res_signs = np.array([res_x, res_y, res_x, res_y])
|
|
337
|
+
else:
|
|
338
|
+
res_signs = np.array([1, 1, 1, 1])
|
|
339
|
+
|
|
340
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
341
|
+
return np.array(list(descriptor.bounds)) * res_signs
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def rasterio_get_epsg_code(
|
|
345
|
+
raster_file: str,
|
|
346
|
+
) -> Tuple[int, int]:
|
|
347
|
+
"""
|
|
348
|
+
Get the epsg code of an image (file)
|
|
349
|
+
|
|
350
|
+
:param raster_file: Image file
|
|
351
|
+
:return: epsg code
|
|
352
|
+
"""
|
|
353
|
+
|
|
354
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
355
|
+
epsg_code = descriptor.crs
|
|
356
|
+
return epsg_code
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def rasterio_get_list_min_max(raster_file: str) -> Tuple[int, int]:
|
|
360
|
+
"""
|
|
361
|
+
Get the stats of an image (file)
|
|
362
|
+
|
|
363
|
+
:param raster_file: Image file
|
|
364
|
+
:return: The list min max
|
|
365
|
+
"""
|
|
366
|
+
min_list = []
|
|
367
|
+
max_list = []
|
|
368
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
369
|
+
for k in range(1, descriptor.count + 1):
|
|
370
|
+
stat = descriptor.statistics(k)
|
|
371
|
+
min_list.append(stat.min)
|
|
372
|
+
max_list.append(stat.max)
|
|
373
|
+
return min_list, max_list
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def rasterio_read_as_array(
|
|
377
|
+
raster_file: str, window: rio.windows.Window = None
|
|
378
|
+
) -> Tuple[np.ndarray, dict]:
|
|
379
|
+
"""
|
|
380
|
+
Get the data of an image file, and its profile
|
|
381
|
+
|
|
382
|
+
:param raster_file: Image file
|
|
383
|
+
:param window: Window to get data from
|
|
384
|
+
:return: The array, its profile
|
|
385
|
+
"""
|
|
386
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
387
|
+
if descriptor.count == 1:
|
|
388
|
+
data = descriptor.read(1, window=window)
|
|
389
|
+
else:
|
|
390
|
+
data = descriptor.read(window=window)
|
|
391
|
+
|
|
392
|
+
return data, descriptor.profile
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def rasterio_get_profile(raster_file: str) -> Dict:
|
|
396
|
+
"""
|
|
397
|
+
Get the profile of an image file
|
|
398
|
+
|
|
399
|
+
:param raster_file: Image file
|
|
400
|
+
:return: The profile of the given image
|
|
401
|
+
"""
|
|
402
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
403
|
+
return descriptor.profile
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def rasterio_get_transform(raster_file: str, convention: str = None) -> Dict:
|
|
407
|
+
"""
|
|
408
|
+
Get the transform of an image file
|
|
409
|
+
|
|
410
|
+
:param raster_file: Image file
|
|
411
|
+
:param convention: The convention to follow: None, "north" or "south"
|
|
412
|
+
:return: The transform of the given image
|
|
413
|
+
"""
|
|
414
|
+
with rio.open(raster_file, "r") as dsc:
|
|
415
|
+
src_tr = dsc.transform
|
|
416
|
+
|
|
417
|
+
if convention == "north" and src_tr.e < 0:
|
|
418
|
+
src_tr = Affine(
|
|
419
|
+
src_tr.a, src_tr.b, src_tr.c, -src_tr.d, -src_tr.e, -src_tr.f
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
elif convention == "south" and src_tr.e > 0:
|
|
423
|
+
src_tr = Affine(
|
|
424
|
+
src_tr.a, src_tr.b, src_tr.c, -src_tr.d, -src_tr.e, -src_tr.f
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
return src_tr
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def rasterio_get_epsg(raster_file: str) -> int:
|
|
431
|
+
"""
|
|
432
|
+
Get the epsg of an image file
|
|
433
|
+
|
|
434
|
+
:param raster_file: Image file
|
|
435
|
+
:return: The epsg of the given image
|
|
436
|
+
"""
|
|
437
|
+
epsg = None
|
|
438
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
439
|
+
epsg = descriptor.crs.to_epsg()
|
|
440
|
+
|
|
441
|
+
return epsg
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def rasterio_get_crs(raster_file: str) -> CRS:
|
|
445
|
+
"""
|
|
446
|
+
Get the crs of an image file
|
|
447
|
+
|
|
448
|
+
:param raster_file: Image file
|
|
449
|
+
:return: The crs of the given image
|
|
450
|
+
"""
|
|
451
|
+
crs = None
|
|
452
|
+
with rio.open(raster_file, "r") as descriptor:
|
|
453
|
+
crs = descriptor.crs
|
|
454
|
+
|
|
455
|
+
return crs
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def rasterio_transform_epsg(file_name, new_epsg):
|
|
459
|
+
"""
|
|
460
|
+
Modify epsg of raster file
|
|
461
|
+
|
|
462
|
+
:param file_name: Image file
|
|
463
|
+
:param new_epsg: new epsg
|
|
464
|
+
"""
|
|
465
|
+
|
|
466
|
+
reprojected_file_name = file_name + "_reprojected.tif"
|
|
467
|
+
|
|
468
|
+
# Create reprojected copy
|
|
469
|
+
with rio.open(file_name) as src:
|
|
470
|
+
transform, width, height = calculate_default_transform(
|
|
471
|
+
src.crs, new_epsg, src.width, src.height, *src.bounds
|
|
472
|
+
)
|
|
473
|
+
kwargs = src.meta.copy()
|
|
474
|
+
kwargs.update(
|
|
475
|
+
{
|
|
476
|
+
"crs": new_epsg,
|
|
477
|
+
"transform": transform,
|
|
478
|
+
"width": width,
|
|
479
|
+
"height": height,
|
|
480
|
+
}
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
with rio.open(reprojected_file_name, "w", **kwargs) as dst:
|
|
484
|
+
for i in range(1, src.count + 1):
|
|
485
|
+
reproject(
|
|
486
|
+
source=rio.band(src, i),
|
|
487
|
+
destination=rio.band(dst, i),
|
|
488
|
+
src_transform=rasterio_get_transform(file_name),
|
|
489
|
+
src_crs=src.crs,
|
|
490
|
+
dst_transform=transform,
|
|
491
|
+
dst_crs=new_epsg,
|
|
492
|
+
resampling=Resampling.nearest,
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# Replace file with the reprojected one
|
|
496
|
+
os.rename(reprojected_file_name, file_name)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def rasterio_can_open(raster_file: str) -> bool:
|
|
500
|
+
"""
|
|
501
|
+
Test if a file can be open by rasterio
|
|
502
|
+
|
|
503
|
+
:param raster_file: File to test
|
|
504
|
+
:return: True if rasterio can open file and False otherwise
|
|
505
|
+
"""
|
|
506
|
+
try:
|
|
507
|
+
rio.open(raster_file)
|
|
508
|
+
return True
|
|
509
|
+
except Exception as read_error:
|
|
510
|
+
logging.warning(
|
|
511
|
+
"Impossible to read file {}: {}".format(raster_file, read_error)
|
|
512
|
+
)
|
|
513
|
+
return False
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def ncdf_can_open(file_path):
|
|
517
|
+
"""
|
|
518
|
+
Checks if the given file can be opened by NetCDF
|
|
519
|
+
:param file_path: file path.
|
|
520
|
+
:type file_path: str
|
|
521
|
+
:return: True if it can be opened, False otherwise.
|
|
522
|
+
:rtype: bool
|
|
523
|
+
"""
|
|
524
|
+
try:
|
|
525
|
+
with xr.open_dataset(file_path) as _:
|
|
526
|
+
return True
|
|
527
|
+
except Exception as read_error:
|
|
528
|
+
logging.warning(
|
|
529
|
+
"Exception caught while trying to read file {}: {}".format(
|
|
530
|
+
file_path, read_error
|
|
531
|
+
)
|
|
532
|
+
)
|
|
533
|
+
return False
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
def check_json(conf, schema):
|
|
537
|
+
"""
|
|
538
|
+
Check a dictionary with respect to a schema
|
|
539
|
+
|
|
540
|
+
:param conf: The dictionary to check
|
|
541
|
+
:type conf: dict
|
|
542
|
+
:param schema: The schema to use
|
|
543
|
+
:type schema: dict
|
|
544
|
+
|
|
545
|
+
:return: conf if check succeeds (else raises CheckerError)
|
|
546
|
+
:rtype: dict
|
|
547
|
+
"""
|
|
548
|
+
schema_validator = Checker(schema)
|
|
549
|
+
checked_conf = schema_validator.validate(conf)
|
|
550
|
+
return checked_conf
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def get_descriptions_bands(sensor) -> Dict:
|
|
554
|
+
"""
|
|
555
|
+
Get the descriptions bands of an image file
|
|
556
|
+
|
|
557
|
+
:param raster_file: Image file
|
|
558
|
+
:type sensor: str or dict
|
|
559
|
+
:return: The descriptions list of the given image
|
|
560
|
+
"""
|
|
561
|
+
if isinstance(sensor, str):
|
|
562
|
+
with rio.open(sensor, "r") as descriptor:
|
|
563
|
+
return descriptor.descriptions
|
|
564
|
+
elif isinstance(sensor, dict):
|
|
565
|
+
if "values" in sensor:
|
|
566
|
+
return list(map(str, sensor["values"]))
|
|
567
|
+
raise RuntimeError("Sensor {} cannot be read".format(sensor))
|
|
568
|
+
raise TypeError("Sensor {} is not str or dict".format(sensor))
|