cars 1.0.0rc1__cp312-cp312-manylinux_2_17_i686.manylinux2014_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.

Files changed (200) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +37 -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 +104 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -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 +655 -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 +1460 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-312-i386-linux-gnu.so +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  31. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  32. cars/applications/dense_matching/cpp/meson.build +9 -0
  33. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  34. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  35. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  36. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  37. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  38. cars/applications/dense_matching/disparity_grid_algo.py +588 -0
  39. cars/applications/dense_matching/loaders/__init__.py +23 -0
  40. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  46. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  47. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  48. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  49. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  50. cars/applications/dsm_filling/__init__.py +32 -0
  51. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  52. cars/applications/dsm_filling/border_interpolation_app.py +270 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
  56. cars/applications/grid_generation/__init__.py +30 -0
  57. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  58. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  59. cars/applications/grid_generation/grid_correction_app.py +496 -0
  60. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  61. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  62. cars/applications/grid_generation/transform_grid.py +88 -0
  63. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  64. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  65. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  66. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  67. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  68. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  69. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  70. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  71. cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
  72. cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
  73. cars/applications/rasterization/__init__.py +30 -0
  74. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  75. cars/applications/rasterization/rasterization_algo.py +534 -0
  76. cars/applications/rasterization/rasterization_constants.py +38 -0
  77. cars/applications/rasterization/rasterization_wrappers.py +634 -0
  78. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  79. cars/applications/resampling/__init__.py +28 -0
  80. cars/applications/resampling/abstract_resampling_app.py +187 -0
  81. cars/applications/resampling/bicubic_resampling_app.py +762 -0
  82. cars/applications/resampling/resampling_algo.py +614 -0
  83. cars/applications/resampling/resampling_constants.py +36 -0
  84. cars/applications/resampling/resampling_wrappers.py +309 -0
  85. cars/applications/sparse_matching/__init__.py +30 -0
  86. cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
  87. cars/applications/sparse_matching/sift_app.py +735 -0
  88. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  89. cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
  90. cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
  91. cars/applications/triangulation/__init__.py +32 -0
  92. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  93. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  94. cars/applications/triangulation/pc_transform.py +552 -0
  95. cars/applications/triangulation/triangulation_algo.py +371 -0
  96. cars/applications/triangulation/triangulation_constants.py +38 -0
  97. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  98. cars/bundleadjustment.py +757 -0
  99. cars/cars.py +177 -0
  100. cars/conf/__init__.py +23 -0
  101. cars/conf/geoid/egm96.grd +0 -0
  102. cars/conf/geoid/egm96.grd.hdr +15 -0
  103. cars/conf/input_parameters.py +156 -0
  104. cars/conf/mask_cst.py +35 -0
  105. cars/core/__init__.py +23 -0
  106. cars/core/cars_logging.py +402 -0
  107. cars/core/constants.py +191 -0
  108. cars/core/constants_disparity.py +50 -0
  109. cars/core/datasets.py +140 -0
  110. cars/core/geometry/__init__.py +27 -0
  111. cars/core/geometry/abstract_geometry.py +1119 -0
  112. cars/core/geometry/shareloc_geometry.py +598 -0
  113. cars/core/inputs.py +568 -0
  114. cars/core/outputs.py +176 -0
  115. cars/core/preprocessing.py +722 -0
  116. cars/core/projection.py +843 -0
  117. cars/core/roi_tools.py +215 -0
  118. cars/core/tiling.py +774 -0
  119. cars/core/utils.py +164 -0
  120. cars/data_structures/__init__.py +23 -0
  121. cars/data_structures/cars_dataset.py +1541 -0
  122. cars/data_structures/cars_dict.py +74 -0
  123. cars/data_structures/corresponding_tiles_tools.py +186 -0
  124. cars/data_structures/dataframe_converter.py +185 -0
  125. cars/data_structures/format_transformation.py +297 -0
  126. cars/devibrate.py +689 -0
  127. cars/extractroi.py +264 -0
  128. cars/orchestrator/__init__.py +23 -0
  129. cars/orchestrator/achievement_tracker.py +125 -0
  130. cars/orchestrator/cluster/__init__.py +37 -0
  131. cars/orchestrator/cluster/abstract_cluster.py +244 -0
  132. cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
  133. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  134. cars/orchestrator/cluster/dask_config/README.md +94 -0
  135. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  136. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  137. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  138. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  139. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  140. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  141. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  142. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  143. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  144. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  145. cars/orchestrator/cluster/log_wrapper.py +1075 -0
  146. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  147. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  148. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  149. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  150. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  151. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
  152. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  153. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  154. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  155. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  156. cars/orchestrator/orchestrator.py +905 -0
  157. cars/orchestrator/orchestrator_constants.py +29 -0
  158. cars/orchestrator/registry/__init__.py +23 -0
  159. cars/orchestrator/registry/abstract_registry.py +143 -0
  160. cars/orchestrator/registry/compute_registry.py +106 -0
  161. cars/orchestrator/registry/id_generator.py +116 -0
  162. cars/orchestrator/registry/replacer_registry.py +213 -0
  163. cars/orchestrator/registry/saver_registry.py +363 -0
  164. cars/orchestrator/registry/unseen_registry.py +118 -0
  165. cars/orchestrator/tiles_profiler.py +279 -0
  166. cars/pipelines/__init__.py +26 -0
  167. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  168. cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
  169. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  170. cars/pipelines/default/__init__.py +26 -0
  171. cars/pipelines/default/default_pipeline.py +786 -0
  172. cars/pipelines/parameters/__init__.py +0 -0
  173. cars/pipelines/parameters/advanced_parameters.py +417 -0
  174. cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
  175. cars/pipelines/parameters/application_parameters.py +71 -0
  176. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  177. cars/pipelines/parameters/dsm_inputs.py +918 -0
  178. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  179. cars/pipelines/parameters/output_constants.py +52 -0
  180. cars/pipelines/parameters/output_parameters.py +454 -0
  181. cars/pipelines/parameters/sensor_inputs.py +842 -0
  182. cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
  183. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  184. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  185. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  186. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  187. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  188. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  189. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  190. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  191. cars/pipelines/pipeline.py +119 -0
  192. cars/pipelines/pipeline_constants.py +31 -0
  193. cars/pipelines/pipeline_template.py +139 -0
  194. cars/pipelines/unit/__init__.py +26 -0
  195. cars/pipelines/unit/unit_pipeline.py +2850 -0
  196. cars/starter.py +167 -0
  197. cars-1.0.0rc1.dist-info/METADATA +292 -0
  198. cars-1.0.0rc1.dist-info/RECORD +200 -0
  199. cars-1.0.0rc1.dist-info/WHEEL +6 -0
  200. cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,614 @@
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
+ Resampling module:
23
+ contains functions used for epipolar resampling
24
+ """
25
+
26
+ # Standard imports
27
+ import math
28
+
29
+ # Third party imports
30
+ import numpy as np
31
+ import rasterio as rio
32
+ import resample as cresample
33
+ from rasterio.windows import Window, bounds
34
+ from scipy.fft import fft2, fftshift, ifft2, ifftshift
35
+
36
+ from cars.conf import mask_cst as msk_cst
37
+
38
+ # CARS imports
39
+ from cars.core import constants as cst
40
+ from cars.core import datasets, inputs, tiling
41
+ from cars.core.geometry import abstract_geometry
42
+
43
+
44
+ def epipolar_rectify_images( # pylint: disable=too-many-positional-arguments
45
+ left_imgs,
46
+ right_imgs,
47
+ grid1,
48
+ grid2,
49
+ region,
50
+ margins,
51
+ epipolar_size_x,
52
+ epipolar_size_y,
53
+ interpolator_image="bicubic",
54
+ interpolator_classif="nearest",
55
+ interpolator_mask="nearest",
56
+ step=None,
57
+ resolution=1,
58
+ mask1=None,
59
+ mask2=None,
60
+ left_classifs=None,
61
+ right_classifs=None,
62
+ nodata1=0,
63
+ nodata2=0,
64
+ add_classif=True,
65
+ ):
66
+ """
67
+ Resample left and right images
68
+ """
69
+
70
+ # Force region to be float
71
+ region = [int(x) for x in region]
72
+
73
+ # Apply margins to left image
74
+ # TODO: tiled region should be given in parameter
75
+ # TODO: keep only rectification here (keep functional unitary approach)
76
+ left_region = region.copy()
77
+ left_margins = margins["left_margin"].data
78
+ left_roi = tiling.crop(
79
+ left_region, [0, 0, epipolar_size_x, epipolar_size_y]
80
+ )
81
+ left_region = tiling.crop(
82
+ tiling.pad(left_region, left_margins),
83
+ [0, 0, epipolar_size_x, epipolar_size_y],
84
+ )
85
+
86
+ left_margins = margins["left_margin"].data
87
+ # Get actual margin taking cropping into account
88
+ left_margins[0] = left_region[0] - left_roi[0]
89
+ left_margins[1] = left_region[1] - left_roi[1]
90
+ left_margins[2] = left_region[2] - left_roi[2]
91
+ left_margins[3] = left_region[3] - left_roi[3]
92
+
93
+ # Apply margins to right image
94
+ right_region = region.copy()
95
+ right_margins = margins["right_margin"].data
96
+ right_roi = tiling.crop(
97
+ right_region, [0, 0, epipolar_size_x, epipolar_size_y]
98
+ )
99
+ right_region = tiling.crop(
100
+ tiling.pad(right_region, right_margins),
101
+ [0, 0, epipolar_size_x, epipolar_size_y],
102
+ )
103
+
104
+ # Get actual margin taking cropping into account
105
+ right_margins[0] = right_region[0] - right_roi[0]
106
+ right_margins[1] = right_region[1] - right_roi[1]
107
+ right_margins[2] = right_region[2] - right_roi[2]
108
+ right_margins[3] = right_region[3] - right_roi[3]
109
+
110
+ # Resample left images
111
+ left_img_transform = inputs.rasterio_get_transform(
112
+ next(iter(left_imgs)), convention="north"
113
+ )
114
+
115
+ left_dataset = resample_image(
116
+ left_imgs,
117
+ grid1,
118
+ [epipolar_size_x, epipolar_size_y],
119
+ step=step,
120
+ resolution=resolution,
121
+ region=left_region,
122
+ nodata=nodata1,
123
+ mask=mask1,
124
+ band_coords=cst.BAND_IM,
125
+ interpolator_img=interpolator_image,
126
+ interpolator_mask=interpolator_mask,
127
+ img_transform=left_img_transform,
128
+ )
129
+
130
+ # Update attributes
131
+ left_dataset.attrs[cst.ROI] = np.array(left_roi)
132
+ left_dataset.attrs[cst.ROI_WITH_MARGINS] = np.array(left_region)
133
+ # Remove region key as it duplicates roi_with_margins key
134
+ # left_dataset.attrs.pop("region", None)
135
+ left_dataset.attrs[cst.EPI_MARGINS] = np.array(left_margins)
136
+ if "disp_min" in margins.attrs:
137
+ left_dataset.attrs[cst.EPI_DISP_MIN] = margins.attrs["disp_min"]
138
+ if "disp_max" in margins.attrs:
139
+ left_dataset.attrs[cst.EPI_DISP_MAX] = margins.attrs["disp_max"]
140
+
141
+ # Resample right image
142
+ right_img_transform = inputs.rasterio_get_transform(next(iter(right_imgs)))
143
+ right_dataset = resample_image(
144
+ right_imgs,
145
+ grid2,
146
+ [epipolar_size_x, epipolar_size_y],
147
+ step=step,
148
+ resolution=resolution,
149
+ region=right_region,
150
+ nodata=nodata2,
151
+ mask=mask2,
152
+ band_coords=cst.BAND_IM,
153
+ interpolator_img=interpolator_image,
154
+ interpolator_mask=interpolator_mask,
155
+ img_transform=right_img_transform,
156
+ )
157
+
158
+ # Update attributes
159
+ right_dataset.attrs[cst.ROI] = np.array(right_roi)
160
+ right_dataset.attrs[cst.ROI_WITH_MARGINS] = np.array(right_region)
161
+ # Remove region key as it duplicates roi_with_margins key
162
+ # right_dataset.attrs.pop("region", None)
163
+ right_dataset.attrs[cst.EPI_MARGINS] = np.array(right_margins)
164
+ if "disp_min" in margins.attrs:
165
+ right_dataset.attrs[cst.EPI_DISP_MIN] = margins.attrs["disp_min"]
166
+ if "disp_max" in margins.attrs:
167
+ right_dataset.attrs[cst.EPI_DISP_MAX] = margins.attrs["disp_max"]
168
+
169
+ # Resample classifications
170
+ left_classif_dataset = None
171
+ right_classif_dataset = None
172
+ if add_classif:
173
+ if left_classifs:
174
+ left_classif_dataset = resample_image(
175
+ left_classifs,
176
+ grid1,
177
+ [epipolar_size_x, epipolar_size_y],
178
+ resolution=resolution,
179
+ region=left_region,
180
+ band_coords=cst.BAND_CLASSIF,
181
+ interpolator_img=interpolator_classif,
182
+ interpolator_mask=interpolator_mask,
183
+ img_transform=left_img_transform,
184
+ )
185
+ if right_classifs:
186
+ right_classif_dataset = resample_image(
187
+ right_classifs,
188
+ grid2,
189
+ [epipolar_size_x, epipolar_size_y],
190
+ resolution=resolution,
191
+ region=right_region,
192
+ band_coords=cst.BAND_CLASSIF,
193
+ interpolator_img=interpolator_classif,
194
+ interpolator_mask=interpolator_mask,
195
+ img_transform=right_img_transform,
196
+ )
197
+
198
+ return (
199
+ left_dataset,
200
+ right_dataset,
201
+ left_classif_dataset,
202
+ right_classif_dataset,
203
+ )
204
+
205
+
206
+ # pylint: disable=too-many-positional-arguments
207
+ def resample_image( # noqa: C901
208
+ imgs,
209
+ grid,
210
+ largest_size,
211
+ step=None,
212
+ resolution=1,
213
+ region=None,
214
+ nodata=None,
215
+ mask=None,
216
+ band_coords=False,
217
+ interpolator_img="bicubic",
218
+ interpolator_mask="nearest",
219
+ img_transform=None,
220
+ ):
221
+ """
222
+ Resample image according to grid and largest size.
223
+
224
+ :param img: Path to the image to resample
225
+ :type img: string
226
+ :param grid: rectification grid dict
227
+ :type grid: dict
228
+ :param largest_size: Size of full output image
229
+ :type largest_size: list of two int
230
+ :param step: horizontal step of resampling (useful for strip resampling)
231
+ :type step: int
232
+ :param region: A subset of the output image to produce
233
+ :type region: None (full output is produced) or array of four floats
234
+ [xmin,ymin,xmax,ymax]
235
+ :param nodata: Nodata value to use (both for input and output)
236
+ :type nodata: None or float
237
+ :param mask: Mask to resample as well
238
+ :type mask: None or path to mask image
239
+ :param band_coords: Force bands coordinate in output dataset
240
+ :type band_coords: boolean
241
+ :param interpolator: interpolator type (bicubic (default) or nearest)
242
+ :type interpolator: str ("nearest" "linear" "bco")
243
+ :rtype: xarray.Dataset with resampled image and mask
244
+ """
245
+ img_sample = next(iter(imgs))
246
+ # Handle region is None
247
+ if region is None:
248
+ region = [0, 0, largest_size[0], largest_size[1]]
249
+ else:
250
+ region = [
251
+ int(math.floor(region[0])),
252
+ int(math.floor(region[1])),
253
+ int(math.ceil(region[2])),
254
+ int(math.ceil(region[3])),
255
+ ]
256
+
257
+ if img_transform is None:
258
+ img_transform = inputs.rasterio_get_transform(
259
+ img_sample, convention="north"
260
+ )
261
+
262
+ # Convert largest_size to int if needed
263
+ largest_size = [int(x) for x in largest_size]
264
+
265
+ # Localize blocks of the tile to resample
266
+ if step is None:
267
+ step = region[2] - region[0]
268
+
269
+ xmin_of_blocks = np.arange(region[0], region[2], step)
270
+ xmax_of_blocks = np.append(
271
+ np.arange(region[0] + step, region[2], step), region[2]
272
+ )
273
+
274
+ ymin_of_blocks = np.arange(region[1], region[3], step)
275
+ ymax_of_blocks = np.append(
276
+ np.arange(region[1] + step, region[3], step), region[3]
277
+ )
278
+
279
+ resampled_images_list = []
280
+ resampled_masks_list = []
281
+ band_names = []
282
+ data_types = []
283
+ nodata_msk = msk_cst.NO_DATA_IN_EPIPOLAR_RECTIFICATION
284
+ for img in imgs:
285
+ bands = imgs[img]
286
+ if "band_id" in bands:
287
+ nb_bands = len(bands["band_id"])
288
+ elif "values" in bands:
289
+ nb_bands = len(bands["values"])
290
+ else:
291
+ raise ValueError(
292
+ "File {} not recognised as an image or classif file".format(
293
+ bands
294
+ )
295
+ )
296
+ # Initialize outputs of the entire tile
297
+ resamp = np.empty(
298
+ (nb_bands, region[3] - region[1], region[2] - region[0]),
299
+ dtype=np.float32,
300
+ )
301
+ msk = np.empty(
302
+ (nb_bands, region[3] - region[1], region[2] - region[0]),
303
+ dtype=np.float32,
304
+ )
305
+
306
+ ystart = 0
307
+ with rio.open(grid["path"]) as grid_reader, rio.open(img) as img_reader:
308
+ for ymin, ymax in zip(ymin_of_blocks, ymax_of_blocks): # noqa: B905
309
+ ysize = ymax - ymin
310
+ xstart = 0
311
+ for xmin, xmax in zip( # noqa: B905
312
+ xmin_of_blocks, xmax_of_blocks
313
+ ):
314
+ block_region = [xmin, ymin, xmax, ymax]
315
+ xsize = xmax - xmin
316
+ resamp, msk = oversampling_func(
317
+ grid_reader,
318
+ img_reader,
319
+ img_transform,
320
+ block_region,
321
+ resolution,
322
+ interpolator_img,
323
+ band_coords,
324
+ nb_bands,
325
+ bands,
326
+ resamp,
327
+ nodata,
328
+ msk,
329
+ mask,
330
+ nodata_msk,
331
+ interpolator_mask,
332
+ ysize,
333
+ xsize,
334
+ ystart,
335
+ xstart,
336
+ )
337
+ xstart += xsize
338
+
339
+ ystart += ysize
340
+ if "band_id" in bands:
341
+ band_names += bands["band_name"]
342
+ elif "values" in bands:
343
+ band_names += list(map(str, bands["values"]))
344
+ else:
345
+ raise ValueError(
346
+ "File {} not recognised as an image or classif file".format(
347
+ bands
348
+ )
349
+ )
350
+ data_types += [inputs.rasterio_get_image_type(img)] * nb_bands
351
+ resampled_images_list.append(resamp)
352
+ resampled_masks_list.append(msk)
353
+
354
+ resamp_final = np.concatenate(resampled_images_list, axis=0)
355
+ msk_final = np.concatenate(resampled_masks_list, axis=0)
356
+ dataset = datasets.create_im_dataset(
357
+ resamp_final,
358
+ region,
359
+ largest_size,
360
+ img_sample,
361
+ band_coords,
362
+ band_names,
363
+ data_types,
364
+ msk_final,
365
+ )
366
+
367
+ return dataset
368
+
369
+
370
+ def oversampling_func( # pylint: disable=too-many-positional-arguments
371
+ grid_reader,
372
+ img_reader,
373
+ img_transform,
374
+ block_region,
375
+ resolution,
376
+ interpolator_img,
377
+ band_coords,
378
+ nb_bands,
379
+ bands,
380
+ resamp,
381
+ nodata,
382
+ msk,
383
+ mask,
384
+ nodata_msk,
385
+ interpolator_mask,
386
+ ysize,
387
+ xsize,
388
+ ystart,
389
+ xstart,
390
+ ):
391
+ """
392
+ Do the resampling calculus
393
+ """
394
+
395
+ xmin = block_region[0]
396
+ ymin = block_region[1]
397
+ xmax = block_region[2]
398
+ ymax = block_region[3]
399
+
400
+ # Build rectification pipelines for images
401
+ res_x, res_y = grid_reader.res
402
+ assert res_x == res_y
403
+ oversampling = int(res_x)
404
+ assert res_x == oversampling
405
+
406
+ grid_origin_x = grid_reader.transform[2]
407
+ grid_origin_y = grid_reader.transform[5]
408
+ assert grid_origin_x == grid_origin_y
409
+ grid_margin = int(-grid_origin_x / oversampling - 0.5)
410
+
411
+ grid_margin = int(grid_margin)
412
+
413
+ # Convert resampled region to grid region with oversampling
414
+ grid_region = np.array(
415
+ [
416
+ math.floor(xmin / oversampling),
417
+ math.floor(ymin / oversampling),
418
+ math.ceil(xmax / oversampling),
419
+ math.ceil(ymax / oversampling),
420
+ ]
421
+ )
422
+
423
+ # Out region of epipolar image
424
+ out_region = oversampling * grid_region
425
+ # Grid region
426
+ grid_region += grid_margin
427
+
428
+ grid_window = Window.from_slices(
429
+ (grid_region[1], grid_region[3] + 1),
430
+ (grid_region[0], grid_region[2] + 1),
431
+ )
432
+ grid_as_array = grid_reader.read(window=grid_window)
433
+ grid_as_array = grid_as_array.astype(np.float32)
434
+ grid_as_array = grid_as_array.astype(np.float64)
435
+
436
+ # get needed source bounding box
437
+ left = math.floor(np.amin(grid_as_array[0, ...]))
438
+ right = math.ceil(np.amax(grid_as_array[0, ...]))
439
+ top = math.floor(np.amin(grid_as_array[1, ...]))
440
+ bottom = math.ceil(np.amax(grid_as_array[1, ...]))
441
+
442
+ transform = rio.Affine(*np.abs(img_transform))
443
+ # transform xmin and xmax positions to index
444
+ (top, bottom, left, right) = abstract_geometry.min_max_to_index_min_max(
445
+ left, right, top, bottom, transform
446
+ )
447
+
448
+ # filter margin for bicubic = 2
449
+ filter_margin = 2
450
+ top -= filter_margin
451
+ bottom += filter_margin
452
+ left -= filter_margin
453
+ right += filter_margin
454
+
455
+ left, right = list(np.clip([left, right], 0, img_reader.shape[0]))
456
+ top, bottom = list(np.clip([top, bottom], 0, img_reader.shape[1]))
457
+
458
+ img_window = Window.from_slices([left, right], [top, bottom])
459
+
460
+ in_sensor = True
461
+ if right - left == 0 or bottom - top == 0:
462
+ in_sensor = False
463
+
464
+ # round window
465
+ img_window = img_window.round_offsets()
466
+ img_window = img_window.round_lengths()
467
+
468
+ # compute offset
469
+ res_x = float(abs(transform[0]))
470
+ res_y = float(abs(transform[4]))
471
+ tile_bounds = list(bounds(img_window, transform))
472
+
473
+ x_offset = min(tile_bounds[0], tile_bounds[2])
474
+ y_offset = min(tile_bounds[1], tile_bounds[3])
475
+
476
+ if in_sensor:
477
+ # get sensor data
478
+ if "band_id" in bands:
479
+ # image
480
+ img_as_array = img_reader.read(bands["band_id"], window=img_window)
481
+ elif "values" in bands:
482
+ # classification
483
+ img_as_array = img_reader.read([1], window=img_window)
484
+ else:
485
+ raise ValueError(
486
+ "File {} not recognised as an image or classif file".format(
487
+ bands
488
+ )
489
+ )
490
+ # get the nodata mask before blurring
491
+ img_nan_mask = img_as_array == nodata
492
+
493
+ # blur the image to avoid moiré artefacts if downsampling
494
+ if resolution != 1 and interpolator_img == "bicubic":
495
+ fourier = fftshift(fft2(img_as_array))
496
+
497
+ _, rows, cols = img_as_array.shape
498
+ crow, ccol = rows // 2, cols // 2
499
+ radius = min(rows, cols) / (2 * resolution)
500
+
501
+ row_mesh, col_mesh = np.ogrid[:rows, :cols]
502
+ dist = (col_mesh - ccol) ** 2 + (row_mesh - crow) ** 2
503
+ gaussian_mask = np.exp(-dist / (2 * radius**2))
504
+ f_filtered = fourier * gaussian_mask
505
+
506
+ img_as_array = np.real(ifft2(ifftshift(f_filtered)))
507
+
508
+ # set the nodata values back
509
+ if nodata is not None:
510
+ img_as_array[img_nan_mask] = nodata
511
+
512
+ # shift grid regarding the img extraction
513
+ grid_as_array[0, ...] -= x_offset
514
+ grid_as_array[1, ...] -= y_offset
515
+
516
+ # apply input resolution
517
+ grid_as_array[0, ...] /= res_x
518
+ grid_as_array[1, ...] /= res_y
519
+
520
+ block_resamp = cresample.grid(
521
+ img_as_array,
522
+ grid_as_array,
523
+ oversampling,
524
+ interpolator=interpolator_img,
525
+ nodata=0,
526
+ ).astype(np.float32)
527
+
528
+ if interpolator_img == "bicubic" and band_coords == cst.BAND_CLASSIF:
529
+ block_resamp = np.where(
530
+ block_resamp >= 0.5,
531
+ 1,
532
+ np.where(block_resamp < 0.5, 0, block_resamp),
533
+ ).astype(int)
534
+
535
+ # extract exact region
536
+ ext_region = block_region - out_region
537
+ block_resamp = block_resamp[
538
+ ...,
539
+ ext_region[1] : ext_region[3] - 1,
540
+ ext_region[0] : ext_region[2] - 1,
541
+ ]
542
+
543
+ if "values" in bands:
544
+ # Extract binary bands from mono-band classification
545
+ multiband_block_resamp = np.zeros(
546
+ (
547
+ nb_bands,
548
+ block_region[3] - block_region[1],
549
+ block_region[2] - block_region[0],
550
+ )
551
+ )
552
+ for band_id, value in enumerate(bands["values"]):
553
+ multiband_block_resamp[band_id] = block_resamp == value
554
+ block_resamp = multiband_block_resamp
555
+
556
+ else:
557
+ block_resamp = np.zeros(
558
+ (
559
+ nb_bands,
560
+ block_region[3] - block_region[1],
561
+ block_region[2] - block_region[0],
562
+ )
563
+ )
564
+
565
+ resamp[:, ystart : ystart + ysize, xstart : xstart + xsize] = block_resamp
566
+
567
+ # create msk
568
+ if in_sensor:
569
+ # get mask in source geometry
570
+ if mask is not None:
571
+ with rio.open(mask) as msk_reader:
572
+ msk_as_array = msk_reader.read(1, window=img_window)
573
+ msk_as_array = np.array([msk_as_array] * img_as_array.shape[0])
574
+ else:
575
+ msk_as_array = np.zeros(img_as_array.shape)
576
+
577
+ if nodata is not None:
578
+ nodata_index = img_as_array == nodata
579
+ msk_as_array[nodata_index] = nodata_msk
580
+
581
+ # resample mask
582
+ block_msk = cresample.grid(
583
+ msk_as_array,
584
+ grid_as_array,
585
+ oversampling,
586
+ interpolator=interpolator_mask,
587
+ nodata=nodata_msk,
588
+ )
589
+
590
+ if interpolator_mask == "bicubic":
591
+ block_msk = np.where(
592
+ block_msk >= 0.5,
593
+ 1,
594
+ np.where(block_msk < 0.5, 0, block_msk),
595
+ ).astype(int)
596
+
597
+ block_msk = block_msk[
598
+ ...,
599
+ ext_region[1] : ext_region[3] - 1,
600
+ ext_region[0] : ext_region[2] - 1,
601
+ ]
602
+ else:
603
+ block_msk = np.full(
604
+ (
605
+ nb_bands,
606
+ block_region[3] - block_region[1],
607
+ block_region[2] - block_region[0],
608
+ ),
609
+ fill_value=nodata_msk,
610
+ )
611
+
612
+ msk[:, ystart : ystart + ysize, xstart : xstart + xsize] = block_msk
613
+
614
+ return resamp, msk
@@ -0,0 +1,36 @@
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
+ this module contains the constants of resampling.
23
+ """
24
+
25
+
26
+ # USED VARIABLES
27
+
28
+
29
+ RESAMPLING_RUN_TAG = "resampling"
30
+
31
+
32
+ # PARAMS
33
+ METHOD = "method"
34
+ EPI_TILE_SIZE = "epi_tile_size"
35
+
36
+ # INFOS