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.

Files changed (225) hide show
  1. cars/__init__.py +86 -0
  2. cars/applications/__init__.py +40 -0
  3. cars/applications/application.py +117 -0
  4. cars/applications/application_constants.py +29 -0
  5. cars/applications/application_template.py +146 -0
  6. cars/applications/auxiliary_filling/__init__.py +29 -0
  7. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
  10. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
  11. cars/applications/dem_generation/__init__.py +30 -0
  12. cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
  13. cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
  15. cars/applications/dem_generation/bulldozer_memory.py +55 -0
  16. cars/applications/dem_generation/dem_generation_algo.py +107 -0
  17. cars/applications/dem_generation/dem_generation_constants.py +32 -0
  18. cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
  19. cars/applications/dense_match_filling/__init__.py +30 -0
  20. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
  21. cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
  22. cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
  23. cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
  24. cars/applications/dense_match_filling/zero_padding_app.py +302 -0
  25. cars/applications/dense_matching/__init__.py +30 -0
  26. cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
  27. cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.dll.a +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
  31. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  32. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  33. cars/applications/dense_matching/cpp/meson.build +9 -0
  34. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  35. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  36. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  37. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  38. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  39. cars/applications/dense_matching/disparity_grid_algo.py +597 -0
  40. cars/applications/dense_matching/loaders/__init__.py +23 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  46. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  47. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  48. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  49. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  50. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  51. cars/applications/dsm_filling/__init__.py +32 -0
  52. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  53. cars/applications/dsm_filling/border_interpolation_app.py +278 -0
  54. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  55. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  56. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  57. cars/applications/dsm_merging/__init__.py +28 -0
  58. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  59. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  60. cars/applications/grid_correction/__init__.py +30 -0
  61. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  62. cars/applications/grid_correction/grid_correction_app.py +557 -0
  63. cars/applications/grid_generation/__init__.py +30 -0
  64. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  65. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  66. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  67. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  68. cars/applications/grid_generation/transform_grid.py +88 -0
  69. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  70. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  71. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  72. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  73. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  74. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  76. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  77. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  78. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  79. cars/applications/rasterization/__init__.py +30 -0
  80. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  81. cars/applications/rasterization/rasterization_algo.py +534 -0
  82. cars/applications/rasterization/rasterization_constants.py +38 -0
  83. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  84. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  85. cars/applications/resampling/__init__.py +28 -0
  86. cars/applications/resampling/abstract_resampling_app.py +187 -0
  87. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  88. cars/applications/resampling/resampling_algo.py +590 -0
  89. cars/applications/resampling/resampling_constants.py +36 -0
  90. cars/applications/resampling/resampling_wrappers.py +309 -0
  91. cars/applications/sensors_subsampling/__init__.py +32 -0
  92. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  93. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  94. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  95. cars/applications/sparse_matching/__init__.py +30 -0
  96. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  97. cars/applications/sparse_matching/sift_app.py +724 -0
  98. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  99. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  100. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  101. cars/applications/triangulation/__init__.py +32 -0
  102. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  103. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  104. cars/applications/triangulation/pc_transform.py +552 -0
  105. cars/applications/triangulation/triangulation_algo.py +371 -0
  106. cars/applications/triangulation/triangulation_constants.py +38 -0
  107. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  108. cars/bundleadjustment.py +750 -0
  109. cars/cars.py +179 -0
  110. cars/conf/__init__.py +23 -0
  111. cars/conf/geoid/egm96.grd +0 -0
  112. cars/conf/geoid/egm96.grd.hdr +15 -0
  113. cars/conf/input_parameters.py +156 -0
  114. cars/conf/mask_cst.py +35 -0
  115. cars/core/__init__.py +23 -0
  116. cars/core/cars_logging.py +402 -0
  117. cars/core/constants.py +191 -0
  118. cars/core/constants_disparity.py +50 -0
  119. cars/core/datasets.py +140 -0
  120. cars/core/geometry/__init__.py +27 -0
  121. cars/core/geometry/abstract_geometry.py +1119 -0
  122. cars/core/geometry/shareloc_geometry.py +598 -0
  123. cars/core/inputs.py +568 -0
  124. cars/core/outputs.py +176 -0
  125. cars/core/preprocessing.py +722 -0
  126. cars/core/projection.py +843 -0
  127. cars/core/roi_tools.py +215 -0
  128. cars/core/tiling.py +774 -0
  129. cars/core/utils.py +164 -0
  130. cars/data_structures/__init__.py +23 -0
  131. cars/data_structures/cars_dataset.py +1544 -0
  132. cars/data_structures/cars_dict.py +74 -0
  133. cars/data_structures/corresponding_tiles_tools.py +186 -0
  134. cars/data_structures/dataframe_converter.py +185 -0
  135. cars/data_structures/format_transformation.py +297 -0
  136. cars/devibrate.py +689 -0
  137. cars/extractroi.py +264 -0
  138. cars/orchestrator/__init__.py +23 -0
  139. cars/orchestrator/achievement_tracker.py +125 -0
  140. cars/orchestrator/cluster/__init__.py +37 -0
  141. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  142. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  143. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  144. cars/orchestrator/cluster/dask_config/README.md +94 -0
  145. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  146. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  147. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  152. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  153. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  154. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  155. cars/orchestrator/cluster/log_wrapper.py +728 -0
  156. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  160. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  162. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  163. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  164. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  165. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  166. cars/orchestrator/memory_tools.py +47 -0
  167. cars/orchestrator/orchestrator.py +755 -0
  168. cars/orchestrator/orchestrator_constants.py +29 -0
  169. cars/orchestrator/registry/__init__.py +23 -0
  170. cars/orchestrator/registry/abstract_registry.py +143 -0
  171. cars/orchestrator/registry/compute_registry.py +106 -0
  172. cars/orchestrator/registry/id_generator.py +116 -0
  173. cars/orchestrator/registry/replacer_registry.py +213 -0
  174. cars/orchestrator/registry/saver_registry.py +363 -0
  175. cars/orchestrator/registry/unseen_registry.py +118 -0
  176. cars/orchestrator/tiles_profiler.py +279 -0
  177. cars/pipelines/__init__.py +26 -0
  178. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  179. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  180. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  181. cars/pipelines/default/__init__.py +26 -0
  182. cars/pipelines/default/default_pipeline.py +1088 -0
  183. cars/pipelines/filling/__init__.py +26 -0
  184. cars/pipelines/filling/filling.py +981 -0
  185. cars/pipelines/formatting/__init__.py +26 -0
  186. cars/pipelines/formatting/formatting.py +186 -0
  187. cars/pipelines/merging/__init__.py +26 -0
  188. cars/pipelines/merging/merging.py +439 -0
  189. cars/pipelines/parameters/__init__.py +0 -0
  190. cars/pipelines/parameters/advanced_parameters.py +256 -0
  191. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  192. cars/pipelines/parameters/application_parameters.py +72 -0
  193. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  194. cars/pipelines/parameters/dsm_inputs.py +349 -0
  195. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  196. cars/pipelines/parameters/output_constants.py +52 -0
  197. cars/pipelines/parameters/output_parameters.py +438 -0
  198. cars/pipelines/parameters/sensor_inputs.py +859 -0
  199. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  200. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  202. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  204. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  206. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  207. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  208. cars/pipelines/pipeline.py +119 -0
  209. cars/pipelines/pipeline_constants.py +38 -0
  210. cars/pipelines/pipeline_template.py +135 -0
  211. cars/pipelines/subsampling/__init__.py +26 -0
  212. cars/pipelines/subsampling/subsampling.py +358 -0
  213. cars/pipelines/surface_modeling/__init__.py +26 -0
  214. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  215. cars/pipelines/tie_points/__init__.py +26 -0
  216. cars/pipelines/tie_points/tie_points.py +536 -0
  217. cars/starter.py +167 -0
  218. cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
  219. cars-1.0.0rc2.dist-info/METADATA +289 -0
  220. cars-1.0.0rc2.dist-info/RECORD +225 -0
  221. cars-1.0.0rc2.dist-info/WHEEL +4 -0
  222. cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
  223. cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
  224. cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
  225. 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))