cars 1.0.0a2__cp310-cp310-win_amd64.whl → 1.0.0a4__cp310-cp310-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 +3 -3
- cars/applications/__init__.py +0 -3
- cars/applications/application.py +14 -6
- cars/applications/application_template.py +42 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +12 -2
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +2 -2
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +95 -46
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +7 -6
- cars/applications/dem_generation/abstract_dem_generation_app.py +9 -5
- cars/applications/dem_generation/dem_generation_algo.py +1 -1
- cars/applications/dem_generation/dem_generation_wrappers.py +44 -59
- cars/applications/dem_generation/dichotomic_generation_app.py +9 -6
- cars/applications/dem_generation/rasterization_app.py +112 -43
- cars/applications/dense_match_filling/__init__.py +1 -1
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +2 -15
- cars/applications/dense_match_filling/fill_disp_algo.py +32 -373
- cars/applications/dense_match_filling/fill_disp_wrappers.py +0 -343
- cars/applications/dense_match_filling/zero_padding_app.py +10 -5
- cars/applications/dense_matching/abstract_dense_matching_app.py +2 -1
- cars/applications/dense_matching/census_mccnn_sgm_app.py +48 -60
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp310-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp310-win_amd64.pyd +0 -0
- cars/applications/dense_matching/dense_matching_algo.py +48 -14
- cars/applications/dense_matching/dense_matching_wrappers.py +11 -3
- cars/applications/dense_matching/disparity_grid_algo.py +95 -79
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +169 -34
- cars/applications/dsm_filling/border_interpolation_app.py +11 -12
- cars/applications/dsm_filling/bulldozer_filling_app.py +16 -15
- cars/applications/dsm_filling/exogenous_filling_app.py +14 -14
- cars/applications/grid_generation/abstract_grid_generation_app.py +1 -1
- cars/applications/grid_generation/epipolar_grid_generation_app.py +4 -2
- cars/applications/grid_generation/grid_correction_app.py +4 -1
- cars/applications/grid_generation/grid_generation_algo.py +7 -2
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +1 -1
- cars/applications/ground_truth_reprojection/direct_localization_app.py +2 -2
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +2 -1
- cars/applications/point_cloud_fusion/abstract_pc_fusion_app.py +0 -155
- cars/applications/point_cloud_fusion/mapping_to_terrain_tiles_app.py +0 -658
- cars/applications/point_cloud_fusion/pc_fusion_algo.py +0 -1339
- cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +0 -869
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +11 -6
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +9 -8
- cars/applications/point_cloud_outlier_removal/small_components_app.py +101 -270
- cars/applications/point_cloud_outlier_removal/statistical_app.py +120 -277
- cars/applications/rasterization/abstract_pc_rasterization_app.py +2 -1
- cars/applications/rasterization/rasterization_algo.py +18 -6
- cars/applications/rasterization/rasterization_wrappers.py +2 -1
- cars/applications/rasterization/simple_gaussian_app.py +88 -116
- cars/applications/resampling/abstract_resampling_app.py +1 -1
- cars/applications/resampling/bicubic_resampling_app.py +3 -1
- cars/applications/resampling/resampling_algo.py +60 -53
- cars/applications/resampling/resampling_wrappers.py +3 -1
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +1 -1
- cars/applications/sparse_matching/sift_app.py +5 -25
- cars/applications/sparse_matching/sparse_matching_algo.py +3 -2
- cars/applications/sparse_matching/sparse_matching_wrappers.py +1 -1
- cars/applications/triangulation/abstract_triangulation_app.py +1 -1
- cars/applications/triangulation/line_of_sight_intersection_app.py +13 -11
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +6 -4
- cars/applications/triangulation/triangulation_wrappers.py +1 -0
- cars/bundleadjustment.py +6 -6
- cars/cars.py +11 -9
- cars/core/cars_logging.py +80 -49
- cars/core/constants.py +0 -1
- cars/core/datasets.py +5 -2
- cars/core/geometry/abstract_geometry.py +364 -22
- cars/core/geometry/shareloc_geometry.py +112 -82
- cars/core/inputs.py +72 -19
- cars/core/outputs.py +1 -1
- cars/core/preprocessing.py +17 -3
- cars/core/projection.py +126 -6
- cars/core/tiling.py +10 -3
- cars/data_structures/cars_dataset.py +12 -10
- cars/data_structures/corresponding_tiles_tools.py +0 -103
- cars/data_structures/format_transformation.py +4 -1
- cars/devibrate.py +6 -3
- cars/extractroi.py +20 -21
- cars/orchestrator/cluster/abstract_cluster.py +15 -5
- cars/orchestrator/cluster/abstract_dask_cluster.py +6 -2
- cars/orchestrator/cluster/dask_jobqueue_utils.py +1 -1
- cars/orchestrator/cluster/log_wrapper.py +149 -22
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +12 -4
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +2 -2
- cars/orchestrator/cluster/pbs_dask_cluster.py +1 -1
- cars/orchestrator/cluster/sequential_cluster.py +5 -4
- cars/orchestrator/cluster/slurm_dask_cluster.py +1 -1
- cars/orchestrator/orchestrator.py +15 -4
- cars/orchestrator/registry/id_generator.py +1 -0
- cars/orchestrator/registry/saver_registry.py +2 -2
- cars/pipelines/conf_resolution/conf_final_resolution.json +5 -3
- cars/pipelines/default/default_pipeline.py +461 -1052
- cars/pipelines/parameters/advanced_parameters.py +91 -64
- cars/pipelines/parameters/advanced_parameters_constants.py +6 -5
- cars/pipelines/parameters/application_parameters.py +71 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -314
- cars/pipelines/parameters/dsm_inputs.py +40 -4
- cars/pipelines/parameters/output_parameters.py +44 -8
- cars/pipelines/parameters/sensor_inputs.py +122 -73
- cars/pipelines/parameters/sensor_inputs_constants.py +0 -2
- cars/pipelines/parameters/sensor_loaders/__init__.py +4 -3
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +106 -0
- cars/pipelines/parameters/sensor_loaders/{basic_sensor_loader.py → basic_image_loader.py} +16 -22
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +121 -0
- cars/pipelines/parameters/sensor_loaders/{pivot_sensor_loader.py → pivot_image_loader.py} +10 -21
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +1 -3
- cars/pipelines/pipeline_template.py +1 -3
- cars/pipelines/unit/unit_pipeline.py +676 -1070
- cars/starter.py +4 -3
- cars-1.0.0a4.dist-info/DELVEWHEEL +2 -0
- {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/METADATA +135 -53
- {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/RECORD +120 -134
- 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/applications/dense_match_filling/cpp/__init__.py +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp310-win_amd64.dll.a +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp310-win_amd64.pyd +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.py +0 -72
- cars/applications/dense_match_filling/cpp/includes/dense_match_filling.hpp +0 -46
- cars/applications/dense_match_filling/cpp/meson.build +0 -9
- cars/applications/dense_match_filling/cpp/src/bindings.cpp +0 -11
- cars/applications/dense_match_filling/cpp/src/dense_match_filling.cpp +0 -142
- cars/applications/dense_match_filling/plane_app.py +0 -556
- cars/applications/hole_detection/__init__.py +0 -30
- cars/applications/hole_detection/abstract_hole_detection_app.py +0 -125
- cars/applications/hole_detection/cloud_to_bbox_app.py +0 -346
- cars/applications/hole_detection/hole_detection_algo.py +0 -144
- cars/applications/hole_detection/hole_detection_wrappers.py +0 -53
- cars/applications/point_cloud_denoising/__init__.py +0 -29
- cars/applications/point_cloud_denoising/abstract_pc_denoising_app.py +0 -273
- cars/applications/point_cloud_fusion/__init__.py +0 -30
- cars/applications/point_cloud_fusion/cloud_fusion_constants.py +0 -39
- cars/applications/sparse_matching/pandora_sparse_matching_app.py +0 -0
- cars/pipelines/parameters/depth_map_inputs_constants.py +0 -25
- cars-1.0.0a2.dist-info/DELVEWHEEL +0 -2
- cars.libs/libgcc_s_seh-1-f2b6825d483bdf14050493af93b5997d.dll +0 -0
- cars.libs/libstdc++-6-6b0059df6bc601df5a0f18a5805eea05.dll +0 -0
- cars.libs/libwinpthread-1-e01b8e85fd67c2b861f64d4ccc7df607.dll +0 -0
- {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/WHEEL +0 -0
- {cars-1.0.0a2.dist-info → cars-1.0.0a4.dist-info}/entry_points.txt +0 -0
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
# See the License for the specific language governing permissions and
|
|
19
19
|
# limitations under the License.
|
|
20
20
|
#
|
|
21
|
+
|
|
22
|
+
# pylint: disable=C0302
|
|
23
|
+
|
|
21
24
|
"""
|
|
22
25
|
this module contains the abstract geometry class to use in the
|
|
23
26
|
geometry plugins
|
|
@@ -30,7 +33,10 @@ from typing import Dict, List, Tuple, Union
|
|
|
30
33
|
import numpy as np
|
|
31
34
|
import rasterio as rio
|
|
32
35
|
import xarray as xr
|
|
33
|
-
from
|
|
36
|
+
from affine import Affine
|
|
37
|
+
from json_checker import And, Checker
|
|
38
|
+
from rasterio.enums import Resampling
|
|
39
|
+
from rasterio.warp import reproject
|
|
34
40
|
from scipy import interpolate
|
|
35
41
|
from scipy.interpolate import LinearNDInterpolator
|
|
36
42
|
from shapely.geometry import Polygon
|
|
@@ -38,19 +44,26 @@ from shareloc import proj_utils
|
|
|
38
44
|
from shareloc.geofunctions.rectification_grid import RectificationGrid
|
|
39
45
|
|
|
40
46
|
from cars.core import constants as cst
|
|
41
|
-
from cars.core import inputs, outputs
|
|
47
|
+
from cars.core import inputs, outputs, projection
|
|
42
48
|
from cars.core.utils import safe_makedirs
|
|
43
49
|
from cars.data_structures import cars_dataset
|
|
50
|
+
from cars.orchestrator.cluster.log_wrapper import cars_profile
|
|
44
51
|
|
|
45
52
|
|
|
46
|
-
class AbstractGeometry(metaclass=ABCMeta):
|
|
53
|
+
class AbstractGeometry(metaclass=ABCMeta): # pylint: disable=R0902
|
|
47
54
|
"""
|
|
48
55
|
AbstractGeometry
|
|
49
56
|
"""
|
|
50
57
|
|
|
51
58
|
available_plugins: Dict = {}
|
|
52
59
|
|
|
53
|
-
def __new__(
|
|
60
|
+
def __new__(
|
|
61
|
+
cls,
|
|
62
|
+
geometry_plugin_conf=None,
|
|
63
|
+
pairs_for_roi=None,
|
|
64
|
+
scaling_coeff=1,
|
|
65
|
+
**kwargs,
|
|
66
|
+
):
|
|
54
67
|
"""
|
|
55
68
|
Return the required plugin
|
|
56
69
|
:raises:
|
|
@@ -59,6 +72,8 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
59
72
|
:param geometry_plugin_conf: plugin name or plugin configuration
|
|
60
73
|
to instantiate
|
|
61
74
|
:type geometry_plugin_conf: str or dict
|
|
75
|
+
:param scaling_coeff: scaling factor for resolution
|
|
76
|
+
:type scaling_coeff: float
|
|
62
77
|
:return: a geometry_plugin object
|
|
63
78
|
"""
|
|
64
79
|
if geometry_plugin_conf is not None:
|
|
@@ -94,28 +109,218 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
94
109
|
)
|
|
95
110
|
return super().__new__(cls)
|
|
96
111
|
|
|
97
|
-
def __init__(
|
|
112
|
+
def __init__( # pylint: disable=too-many-positional-arguments
|
|
98
113
|
self,
|
|
99
114
|
geometry_plugin_conf,
|
|
100
115
|
dem=None,
|
|
101
116
|
geoid=None,
|
|
102
117
|
default_alt=None,
|
|
118
|
+
pairs_for_roi=None,
|
|
119
|
+
scaling_coeff=1,
|
|
120
|
+
output_dem_dir=None,
|
|
103
121
|
**kwargs,
|
|
104
122
|
):
|
|
123
|
+
self.scaling_coeff = scaling_coeff
|
|
105
124
|
|
|
106
|
-
|
|
125
|
+
self.used_config = self.check_conf(geometry_plugin_conf)
|
|
107
126
|
|
|
108
|
-
self.plugin_name =
|
|
109
|
-
self.interpolator =
|
|
110
|
-
self.dem_roi_margin =
|
|
111
|
-
|
|
112
|
-
self.dem = dem
|
|
127
|
+
self.plugin_name = self.used_config["plugin_name"]
|
|
128
|
+
self.interpolator = self.used_config["interpolator"]
|
|
129
|
+
self.dem_roi_margin = self.used_config["dem_roi_margin"]
|
|
130
|
+
self.dem = None
|
|
113
131
|
self.dem_roi = None
|
|
114
132
|
self.dem_roi_epsg = None
|
|
115
133
|
self.geoid = geoid
|
|
116
134
|
self.default_alt = default_alt
|
|
135
|
+
self.elevation = default_alt
|
|
136
|
+
# a margin is needed for cubic interpolation
|
|
137
|
+
self.rectification_grid_margin = 0
|
|
138
|
+
if self.interpolator == "cubic":
|
|
139
|
+
self.rectification_grid_margin = 5
|
|
117
140
|
self.kwargs = kwargs
|
|
118
141
|
|
|
142
|
+
# compute roi only when generating geometry object with dem
|
|
143
|
+
if dem is not None:
|
|
144
|
+
self.dem = dem
|
|
145
|
+
self.default_alt = self.get_dem_median_value()
|
|
146
|
+
self.elevation = self.default_alt
|
|
147
|
+
logging.info(
|
|
148
|
+
"Median value of DEM ({}) will be used as default_alt".format(
|
|
149
|
+
self.default_alt
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
if pairs_for_roi is not None:
|
|
153
|
+
self.dem_roi_epsg = inputs.rasterio_get_epsg(dem)
|
|
154
|
+
self.dem_roi = self.get_roi(
|
|
155
|
+
pairs_for_roi,
|
|
156
|
+
self.dem_roi_epsg,
|
|
157
|
+
z_min=-1000,
|
|
158
|
+
z_max=9000,
|
|
159
|
+
linear_margin=self.dem_roi_margin[0],
|
|
160
|
+
constant_margin=self.dem_roi_margin[1],
|
|
161
|
+
)
|
|
162
|
+
if output_dem_dir is not None:
|
|
163
|
+
self.dem = self.extend_dem_to_roi(dem, output_dem_dir)
|
|
164
|
+
|
|
165
|
+
def get_dem_median_value(self):
|
|
166
|
+
"""
|
|
167
|
+
Compute dem median value
|
|
168
|
+
:param dem: path of DEM
|
|
169
|
+
"""
|
|
170
|
+
with rio.open(self.dem) as dem_file:
|
|
171
|
+
dem_data = dem_file.read(1)
|
|
172
|
+
median_value = np.nanmedian(dem_data)
|
|
173
|
+
median_value = float(median_value)
|
|
174
|
+
return median_value
|
|
175
|
+
|
|
176
|
+
def get_roi( # pylint: disable=too-many-positional-arguments
|
|
177
|
+
self,
|
|
178
|
+
pairs_for_roi,
|
|
179
|
+
epsg,
|
|
180
|
+
z_min=0,
|
|
181
|
+
z_max=0,
|
|
182
|
+
linear_margin=0,
|
|
183
|
+
constant_margin=0.012,
|
|
184
|
+
):
|
|
185
|
+
"""
|
|
186
|
+
Compute region of interest for intersection of DEM
|
|
187
|
+
|
|
188
|
+
:param pairs_for_roi: list of pairs of images and geomodels
|
|
189
|
+
:type pairs_for_roi: List[(str, dict, str, dict)]
|
|
190
|
+
:param dem_epsg: output EPSG code for ROI
|
|
191
|
+
:type dem_epsg: int
|
|
192
|
+
:param linear_margin: margin for ROI (factor of initial ROI size)
|
|
193
|
+
:type linear_margin: float
|
|
194
|
+
:param constant_margin: margin for ROI in degrees
|
|
195
|
+
:type constant_margin: float
|
|
196
|
+
"""
|
|
197
|
+
coords_list = []
|
|
198
|
+
z_min = np.array(z_min)
|
|
199
|
+
z_max = np.array(z_max)
|
|
200
|
+
for image1, geomodel1, image2, geomodel2 in pairs_for_roi:
|
|
201
|
+
# Footprint of left image with altitude z_min
|
|
202
|
+
coords_list.extend(
|
|
203
|
+
self.image_envelope(
|
|
204
|
+
image1["main_file"], geomodel1, elevation=z_min
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
# Footprint of left image with altitude z_max
|
|
208
|
+
coords_list.extend(
|
|
209
|
+
self.image_envelope(
|
|
210
|
+
image1["main_file"], geomodel1, elevation=z_max
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
# Footprint of right image with altitude z_min
|
|
214
|
+
coords_list.extend(
|
|
215
|
+
self.image_envelope(
|
|
216
|
+
image2["main_file"], geomodel2, elevation=z_min
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
# Footprint of right image with altitude z_max
|
|
220
|
+
coords_list.extend(
|
|
221
|
+
self.image_envelope(
|
|
222
|
+
image2["main_file"], geomodel2, elevation=z_max
|
|
223
|
+
)
|
|
224
|
+
)
|
|
225
|
+
lon_list, lat_list = list(zip(*coords_list)) # noqa: B905
|
|
226
|
+
roi = [
|
|
227
|
+
min(lon_list) - constant_margin,
|
|
228
|
+
min(lat_list) - constant_margin,
|
|
229
|
+
max(lon_list) + constant_margin,
|
|
230
|
+
max(lat_list) + constant_margin,
|
|
231
|
+
]
|
|
232
|
+
points = np.array(
|
|
233
|
+
[
|
|
234
|
+
(roi[0], roi[1], 0),
|
|
235
|
+
(roi[2], roi[3], 0),
|
|
236
|
+
(roi[0], roi[1], 0),
|
|
237
|
+
(roi[2], roi[3], 0),
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
new_points = projection.point_cloud_conversion(points, 4326, epsg)
|
|
241
|
+
roi = [
|
|
242
|
+
min(new_points[:, 0]),
|
|
243
|
+
min(new_points[:, 1]),
|
|
244
|
+
max(new_points[:, 0]),
|
|
245
|
+
max(new_points[:, 1]),
|
|
246
|
+
]
|
|
247
|
+
|
|
248
|
+
lon_size = roi[2] - roi[0]
|
|
249
|
+
lat_size = roi[3] - roi[1]
|
|
250
|
+
|
|
251
|
+
roi[0] -= linear_margin * lon_size
|
|
252
|
+
roi[1] -= linear_margin * lat_size
|
|
253
|
+
roi[2] += linear_margin * lon_size
|
|
254
|
+
roi[3] += linear_margin * lat_size
|
|
255
|
+
|
|
256
|
+
return roi
|
|
257
|
+
|
|
258
|
+
def extend_dem_to_roi(self, dem, output_dem_dir):
|
|
259
|
+
"""
|
|
260
|
+
Extend the size of the dem to the required ROI and fill
|
|
261
|
+
:param dem: path to the input DEM
|
|
262
|
+
:param output_dem_dir: path to write the output extended DEM
|
|
263
|
+
"""
|
|
264
|
+
with rio.open(dem) as in_dem:
|
|
265
|
+
src_dem = in_dem.read(1)
|
|
266
|
+
metadata = in_dem.meta
|
|
267
|
+
src_transform = in_dem.transform
|
|
268
|
+
crs = in_dem.crs
|
|
269
|
+
bounds = in_dem.bounds
|
|
270
|
+
|
|
271
|
+
logging.info(
|
|
272
|
+
"DEM bounds : {}, {}, {}, {}".format(
|
|
273
|
+
bounds.left, bounds.top, bounds.right, bounds.bottom
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
logging.info(
|
|
277
|
+
"ROI bounds : {}, {}, {}, {}".format(
|
|
278
|
+
self.dem_roi[0],
|
|
279
|
+
self.dem_roi[1],
|
|
280
|
+
self.dem_roi[2],
|
|
281
|
+
self.dem_roi[3],
|
|
282
|
+
)
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Longitude
|
|
286
|
+
lon_res = src_transform[0]
|
|
287
|
+
lon_shift = (self.dem_roi[0] - bounds.left) / lon_res
|
|
288
|
+
dst_width = int((self.dem_roi[2] - self.dem_roi[0]) / abs(lon_res)) + 1
|
|
289
|
+
# Latitude
|
|
290
|
+
lat_res = src_transform[4]
|
|
291
|
+
lat_shift = (self.dem_roi[3] - bounds.top) / lat_res
|
|
292
|
+
dst_height = int((self.dem_roi[3] - self.dem_roi[1]) / abs(lat_res)) + 1
|
|
293
|
+
|
|
294
|
+
shift = Affine.translation(lon_shift, lat_shift)
|
|
295
|
+
dst_transform = src_transform * shift
|
|
296
|
+
dst_dem = np.zeros((dst_height, dst_width))
|
|
297
|
+
|
|
298
|
+
reproject(
|
|
299
|
+
source=src_dem,
|
|
300
|
+
destination=dst_dem,
|
|
301
|
+
src_transform=src_transform,
|
|
302
|
+
src_crs=crs,
|
|
303
|
+
dst_transform=dst_transform,
|
|
304
|
+
dst_crs=crs,
|
|
305
|
+
resampling=Resampling.bilinear,
|
|
306
|
+
)
|
|
307
|
+
# Fill nodata
|
|
308
|
+
dst_dem = rio.fill.fillnodata(
|
|
309
|
+
dst_dem,
|
|
310
|
+
mask=~(dst_dem == 0),
|
|
311
|
+
)
|
|
312
|
+
metadata["transform"] = dst_transform
|
|
313
|
+
metadata["height"] = dst_height
|
|
314
|
+
metadata["width"] = dst_width
|
|
315
|
+
metadata["driver"] = "GTiff"
|
|
316
|
+
|
|
317
|
+
out_dem_path = os.path.join(output_dem_dir, "initial_elevation.tif")
|
|
318
|
+
|
|
319
|
+
with rio.open(out_dem_path, "w", **metadata) as dst:
|
|
320
|
+
dst.write(dst_dem, 1)
|
|
321
|
+
|
|
322
|
+
return out_dem_path
|
|
323
|
+
|
|
119
324
|
@classmethod
|
|
120
325
|
def register_subclass(cls, short_name: str):
|
|
121
326
|
"""
|
|
@@ -160,12 +365,14 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
160
365
|
"plugin_name", "SharelocGeometry"
|
|
161
366
|
)
|
|
162
367
|
overloaded_conf["interpolator"] = conf.get("interpolator", "cubic")
|
|
163
|
-
overloaded_conf["dem_roi_margin"] = conf.get(
|
|
368
|
+
overloaded_conf["dem_roi_margin"] = conf.get(
|
|
369
|
+
"dem_roi_margin", [0.75, 0.02]
|
|
370
|
+
)
|
|
164
371
|
|
|
165
372
|
geometry_schema = {
|
|
166
373
|
"plugin_name": str,
|
|
167
374
|
"interpolator": And(str, lambda x: x in ["cubic", "linear"]),
|
|
168
|
-
"dem_roi_margin":
|
|
375
|
+
"dem_roi_margin": [float],
|
|
169
376
|
}
|
|
170
377
|
|
|
171
378
|
# Check conf
|
|
@@ -175,7 +382,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
175
382
|
return overloaded_conf
|
|
176
383
|
|
|
177
384
|
@abstractmethod
|
|
178
|
-
def triangulate(
|
|
385
|
+
def triangulate( # pylint: disable=too-many-positional-arguments
|
|
179
386
|
self,
|
|
180
387
|
sensor1,
|
|
181
388
|
sensor2,
|
|
@@ -186,6 +393,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
186
393
|
grid1: str,
|
|
187
394
|
grid2: str,
|
|
188
395
|
roi_key: Union[None, str] = None,
|
|
396
|
+
interpolation_method=None,
|
|
189
397
|
) -> np.ndarray:
|
|
190
398
|
"""
|
|
191
399
|
Performs triangulation from cars disparity or matches dataset
|
|
@@ -215,6 +423,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
215
423
|
:return: True if the products are readable, False otherwise
|
|
216
424
|
"""
|
|
217
425
|
|
|
426
|
+
# pylint: disable=too-many-positional-arguments
|
|
218
427
|
@abstractmethod
|
|
219
428
|
def generate_epipolar_grids(
|
|
220
429
|
self, sensor1, sensor2, geomodel1, geomodel2, epipolar_step: int = 30
|
|
@@ -249,6 +458,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
249
458
|
"""
|
|
250
459
|
return geomodel
|
|
251
460
|
|
|
461
|
+
# pylint: disable=too-many-positional-arguments
|
|
252
462
|
def matches_to_sensor_coords(
|
|
253
463
|
self,
|
|
254
464
|
grid1: Union[str, cars_dataset.CarsDataset, RectificationGrid],
|
|
@@ -257,6 +467,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
257
467
|
matches_type: str,
|
|
258
468
|
matches_msk: np.ndarray = None,
|
|
259
469
|
ul_matches_shift: Tuple[int, int] = None,
|
|
470
|
+
interpolation_method=None,
|
|
260
471
|
) -> Tuple[np.ndarray, np.ndarray]:
|
|
261
472
|
"""
|
|
262
473
|
Convert matches (sparse or dense matches) given in epipolar
|
|
@@ -330,10 +541,10 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
330
541
|
|
|
331
542
|
# convert epipolar matches to sensor coordinates
|
|
332
543
|
sensor_pos_left = self.sensor_position_from_grid(
|
|
333
|
-
grid1, vec_epi_pos_left
|
|
544
|
+
grid1, vec_epi_pos_left, interpolation_method=interpolation_method
|
|
334
545
|
)
|
|
335
546
|
sensor_pos_right = self.sensor_position_from_grid(
|
|
336
|
-
grid2, vec_epi_pos_right
|
|
547
|
+
grid2, vec_epi_pos_right, interpolation_method=interpolation_method
|
|
337
548
|
)
|
|
338
549
|
|
|
339
550
|
if matches_type == cst.DISP_MODE:
|
|
@@ -369,6 +580,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
369
580
|
self,
|
|
370
581
|
grid: Union[dict, RectificationGrid],
|
|
371
582
|
positions: np.ndarray,
|
|
583
|
+
interpolation_method=None,
|
|
372
584
|
) -> np.ndarray:
|
|
373
585
|
"""
|
|
374
586
|
Interpolate the positions given as inputs using the grid
|
|
@@ -441,6 +653,11 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
441
653
|
min_row_idx : max_row_idx + 1, min_col_idx : max_col_idx + 1
|
|
442
654
|
]
|
|
443
655
|
|
|
656
|
+
if interpolation_method is not None:
|
|
657
|
+
method = interpolation_method
|
|
658
|
+
else:
|
|
659
|
+
method = self.interpolator
|
|
660
|
+
|
|
444
661
|
# interpolate sensor positions
|
|
445
662
|
interpolator = interpolate.RegularGridInterpolator(
|
|
446
663
|
(cols_cropped, rows_cropped),
|
|
@@ -451,13 +668,35 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
451
668
|
),
|
|
452
669
|
axis=2,
|
|
453
670
|
),
|
|
454
|
-
method=
|
|
671
|
+
method=method,
|
|
455
672
|
bounds_error=False,
|
|
456
673
|
fill_value=None,
|
|
457
674
|
)
|
|
458
675
|
|
|
459
676
|
sensor_positions = interpolator(positions)
|
|
460
677
|
|
|
678
|
+
min_row = np.min(sensor_row_positions_cropped)
|
|
679
|
+
max_row = np.max(sensor_row_positions_cropped)
|
|
680
|
+
min_col = np.min(sensor_col_positions_cropped)
|
|
681
|
+
max_col = np.max(sensor_col_positions_cropped)
|
|
682
|
+
|
|
683
|
+
valid_rows = np.logical_and(
|
|
684
|
+
sensor_positions[:, 0] > min_row,
|
|
685
|
+
sensor_positions[:, 0] < max_row,
|
|
686
|
+
)
|
|
687
|
+
valid_cols = np.logical_and(
|
|
688
|
+
sensor_positions[:, 1] > min_col,
|
|
689
|
+
sensor_positions[:, 1] < max_col,
|
|
690
|
+
)
|
|
691
|
+
valid = np.logical_and(valid_rows, valid_cols)
|
|
692
|
+
|
|
693
|
+
if np.sum(~valid) > 0:
|
|
694
|
+
logging.warning(
|
|
695
|
+
"{}/{} points are outside of epipolar grid".format(
|
|
696
|
+
np.sum(~valid), valid.size
|
|
697
|
+
)
|
|
698
|
+
)
|
|
699
|
+
|
|
461
700
|
# swap
|
|
462
701
|
sensor_positions[:, [0, 1]] = sensor_positions[:, [1, 0]]
|
|
463
702
|
|
|
@@ -517,6 +756,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
517
756
|
|
|
518
757
|
return epipolar_positions
|
|
519
758
|
|
|
759
|
+
@cars_profile(name="Transform matches", interval=0.5)
|
|
520
760
|
def transform_matches_from_grids(
|
|
521
761
|
self,
|
|
522
762
|
sensor_matches_left,
|
|
@@ -553,7 +793,8 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
553
793
|
|
|
554
794
|
return new_matches_array
|
|
555
795
|
|
|
556
|
-
|
|
796
|
+
@cars_profile(name="Get sensor matches")
|
|
797
|
+
def get_sensor_matches( # pylint: disable=too-many-positional-arguments
|
|
557
798
|
self,
|
|
558
799
|
matches_array,
|
|
559
800
|
grid_left,
|
|
@@ -562,7 +803,7 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
562
803
|
save_matches,
|
|
563
804
|
):
|
|
564
805
|
"""
|
|
565
|
-
|
|
806
|
+
Get sensor matches
|
|
566
807
|
|
|
567
808
|
:param grid_left: path to epipolar grid of image 1
|
|
568
809
|
:param grid_left: path to epipolar grid of image 2
|
|
@@ -595,7 +836,29 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
595
836
|
return sensor_matches_left, sensor_matches_right
|
|
596
837
|
|
|
597
838
|
@abstractmethod
|
|
598
|
-
def direct_loc(
|
|
839
|
+
def direct_loc( # pylint: disable=too-many-positional-arguments
|
|
840
|
+
self,
|
|
841
|
+
sensor,
|
|
842
|
+
geomodel,
|
|
843
|
+
x_coord: np.array,
|
|
844
|
+
y_coord: np.array,
|
|
845
|
+
z_coord: np.array = None,
|
|
846
|
+
) -> np.ndarray:
|
|
847
|
+
"""
|
|
848
|
+
For a given image points list, compute the latitudes,
|
|
849
|
+
longitudes, altitudes
|
|
850
|
+
|
|
851
|
+
Advice: to be sure, use x,y,z list inputs only
|
|
852
|
+
|
|
853
|
+
:param sensor: path to sensor image
|
|
854
|
+
:param geomodel: path and attributes for geomodel
|
|
855
|
+
:param x_coord: X Coordinates list in input image sensor
|
|
856
|
+
:param y_coord: Y Coordinate list in input image sensor
|
|
857
|
+
:param z_coord: Z Altitude list coordinate to take the image
|
|
858
|
+
:return: Latitude, Longitude, Altitude coordinates list as a numpy array
|
|
859
|
+
"""
|
|
860
|
+
|
|
861
|
+
def safe_direct_loc( # pylint: disable=too-many-positional-arguments
|
|
599
862
|
self,
|
|
600
863
|
sensor,
|
|
601
864
|
geomodel,
|
|
@@ -616,9 +879,58 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
616
879
|
:param z_coord: Z Altitude list coordinate to take the image
|
|
617
880
|
:return: Latitude, Longitude, Altitude coordinates list as a numpy array
|
|
618
881
|
"""
|
|
882
|
+
if len(x_coord) > 0:
|
|
883
|
+
ground_points = self.direct_loc(
|
|
884
|
+
sensor,
|
|
885
|
+
geomodel,
|
|
886
|
+
x_coord,
|
|
887
|
+
y_coord,
|
|
888
|
+
z_coord,
|
|
889
|
+
)
|
|
890
|
+
else:
|
|
891
|
+
logging.warning("Direct loc function launched on empty list")
|
|
892
|
+
return []
|
|
893
|
+
if z_coord is None:
|
|
894
|
+
status = np.any(np.isnan(ground_points), axis=0)
|
|
895
|
+
if sum(status) > 0:
|
|
896
|
+
logging.warning(
|
|
897
|
+
"{} errors have been detected on direct "
|
|
898
|
+
"loc and will be re-launched".format(sum(status))
|
|
899
|
+
)
|
|
900
|
+
ground_points_retry = self.direct_loc(
|
|
901
|
+
sensor,
|
|
902
|
+
geomodel,
|
|
903
|
+
x_coord[status],
|
|
904
|
+
y_coord[status],
|
|
905
|
+
np.array([0]),
|
|
906
|
+
)
|
|
907
|
+
ground_points[:, status] = ground_points_retry
|
|
908
|
+
return ground_points
|
|
619
909
|
|
|
620
910
|
@abstractmethod
|
|
621
|
-
def inverse_loc(
|
|
911
|
+
def inverse_loc( # pylint: disable=too-many-positional-arguments
|
|
912
|
+
self,
|
|
913
|
+
sensor,
|
|
914
|
+
geomodel,
|
|
915
|
+
lat_coord: np.array,
|
|
916
|
+
lon_coord: np.array,
|
|
917
|
+
z_coord: np.array = None,
|
|
918
|
+
) -> np.ndarray:
|
|
919
|
+
"""
|
|
920
|
+
For a given image points list, compute the latitudes,
|
|
921
|
+
longitudes, altitudes
|
|
922
|
+
|
|
923
|
+
Advice: to be sure, use x,y,z list inputs only
|
|
924
|
+
|
|
925
|
+
:param sensor: path to sensor image
|
|
926
|
+
:param geomodel: path and attributes for geomodel
|
|
927
|
+
:param lat_coord: latitute Coordinate list
|
|
928
|
+
:param lon_coord: longitude Coordinates list
|
|
929
|
+
:param z_coord: Z Altitude list
|
|
930
|
+
:return: X / Y / Z Coordinates list in input image as a numpy array
|
|
931
|
+
"""
|
|
932
|
+
|
|
933
|
+
def safe_inverse_loc( # pylint: disable=too-many-positional-arguments
|
|
622
934
|
self,
|
|
623
935
|
sensor,
|
|
624
936
|
geomodel,
|
|
@@ -639,8 +951,38 @@ class AbstractGeometry(metaclass=ABCMeta):
|
|
|
639
951
|
:param z_coord: Z Altitude list
|
|
640
952
|
:return: X / Y / Z Coordinates list in input image as a numpy array
|
|
641
953
|
"""
|
|
954
|
+
if len(lat_coord) > 0:
|
|
955
|
+
image_points = self.inverse_loc(
|
|
956
|
+
sensor,
|
|
957
|
+
geomodel,
|
|
958
|
+
lat_coord,
|
|
959
|
+
lon_coord,
|
|
960
|
+
z_coord,
|
|
961
|
+
)
|
|
962
|
+
image_points = np.array(image_points)
|
|
963
|
+
else:
|
|
964
|
+
logging.warning("Inverse loc function launched on empty list")
|
|
965
|
+
return [], [], []
|
|
966
|
+
if z_coord is None:
|
|
967
|
+
image_points = np.array(image_points)
|
|
968
|
+
status = np.any(np.isnan(image_points), axis=0)
|
|
969
|
+
if sum(status) > 0:
|
|
970
|
+
logging.warning(
|
|
971
|
+
"{} errors have been detected on inverse "
|
|
972
|
+
"loc and will be re-launched".format(sum(status))
|
|
973
|
+
)
|
|
974
|
+
image_points_retry = self.inverse_loc(
|
|
975
|
+
sensor,
|
|
976
|
+
geomodel,
|
|
977
|
+
lat_coord[status],
|
|
978
|
+
lon_coord[status],
|
|
979
|
+
np.array([self.default_alt]),
|
|
980
|
+
)
|
|
981
|
+
|
|
982
|
+
image_points[:, status] = image_points_retry
|
|
983
|
+
return image_points[0], image_points[1], image_points[2]
|
|
642
984
|
|
|
643
|
-
def image_envelope(
|
|
985
|
+
def image_envelope( # pylint: disable=too-many-positional-arguments
|
|
644
986
|
self,
|
|
645
987
|
sensor,
|
|
646
988
|
geomodel,
|