cars 1.0.0a1__cp310-cp310-win_amd64.whl → 1.0.0a2__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.

Files changed (49) hide show
  1. cars/__init__.py +4 -4
  2. cars/applications/dem_generation/dem_generation_wrappers.py +5 -1
  3. cars/applications/dem_generation/dichotomic_generation_app.py +21 -6
  4. cars/applications/dem_generation/rasterization_app.py +70 -27
  5. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +4 -0
  6. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp310-win_amd64.dll.a +0 -0
  7. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp310-win_amd64.pyd +0 -0
  8. cars/applications/dense_match_filling/fill_disp_algo.py +41 -12
  9. cars/applications/dense_match_filling/plane_app.py +11 -0
  10. cars/applications/dense_match_filling/zero_padding_app.py +11 -1
  11. cars/applications/dense_matching/census_mccnn_sgm_app.py +262 -545
  12. cars/applications/dense_matching/cpp/dense_matching_cpp.cp310-win_amd64.dll.a +0 -0
  13. cars/applications/dense_matching/cpp/dense_matching_cpp.cp310-win_amd64.pyd +0 -0
  14. cars/applications/dense_matching/dense_matching_algo.py +59 -11
  15. cars/applications/dense_matching/dense_matching_wrappers.py +51 -31
  16. cars/applications/dense_matching/disparity_grid_algo.py +572 -0
  17. cars/applications/grid_generation/grid_correction_app.py +0 -53
  18. cars/applications/grid_generation/transform_grid.py +5 -5
  19. cars/applications/point_cloud_fusion/pc_fusion_algo.py +17 -11
  20. cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +3 -4
  21. cars/applications/rasterization/rasterization_algo.py +20 -27
  22. cars/applications/rasterization/rasterization_wrappers.py +6 -5
  23. cars/applications/rasterization/simple_gaussian_app.py +2 -14
  24. cars/applications/sparse_matching/sparse_matching_wrappers.py +0 -49
  25. cars/applications/triangulation/line_of_sight_intersection_app.py +1 -1
  26. cars/applications/triangulation/triangulation_wrappers.py +2 -1
  27. cars/bundleadjustment.py +51 -11
  28. cars/cars.py +15 -5
  29. cars/core/constants.py +1 -1
  30. cars/core/geometry/abstract_geometry.py +54 -11
  31. cars/core/geometry/shareloc_geometry.py +59 -14
  32. cars/orchestrator/registry/saver_registry.py +0 -78
  33. cars/pipelines/default/default_pipeline.py +23 -26
  34. cars/pipelines/parameters/depth_map_inputs.py +22 -67
  35. cars/pipelines/parameters/dsm_inputs.py +16 -29
  36. cars/pipelines/parameters/sensor_inputs.py +20 -21
  37. cars/pipelines/parameters/sensor_loaders/basic_sensor_loader.py +3 -3
  38. cars/pipelines/parameters/sensor_loaders/pivot_sensor_loader.py +2 -2
  39. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
  40. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +2 -2
  41. cars/pipelines/pipeline.py +8 -8
  42. cars/pipelines/unit/unit_pipeline.py +103 -196
  43. cars/starter.py +20 -1
  44. cars-1.0.0a2.dist-info/DELVEWHEEL +2 -0
  45. {cars-1.0.0a1.dist-info → cars-1.0.0a2.dist-info}/METADATA +3 -2
  46. {cars-1.0.0a1.dist-info → cars-1.0.0a2.dist-info}/RECORD +48 -47
  47. cars-1.0.0a1.dist-info/DELVEWHEEL +0 -2
  48. {cars-1.0.0a1.dist-info → cars-1.0.0a2.dist-info}/WHEEL +0 -0
  49. {cars-1.0.0a1.dist-info → cars-1.0.0a2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,572 @@
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 wrapper used in disparity grid computation.
23
+ """
24
+
25
+ # Standard imports
26
+ import itertools
27
+ import logging
28
+
29
+ # Third party imports
30
+ import affine
31
+ import numpy as np
32
+ import rasterio
33
+ import xarray as xr
34
+ from scipy.ndimage import maximum_filter, minimum_filter
35
+ from shareloc.proj_utils import transform_physical_point_to_index
36
+
37
+ # CARS imports
38
+ import cars.applications.dense_matching.dense_matching_constants as dm_cst
39
+ import cars.orchestrator.orchestrator as ocht
40
+ from cars.applications.dense_matching.dense_matching_algo import (
41
+ LinearInterpNearestExtrap,
42
+ )
43
+ from cars.core import inputs, projection
44
+ from cars.core.projection import point_cloud_conversion
45
+ from cars.data_structures import cars_dataset, cars_dict
46
+
47
+
48
+ def generate_disp_grids_dataset(
49
+ grid_min,
50
+ grid_max,
51
+ saving_info,
52
+ raster_profile,
53
+ window=None,
54
+ row_coords=None,
55
+ col_coords=None,
56
+ ):
57
+ """
58
+ Generate disparity grids xarray dataset
59
+
60
+ :param grid_min: disp grid min
61
+ :type grid_min: np.ndarray
62
+ :param grid_max: disp grid max
63
+ :type grid_max: np.ndarray
64
+ :param saving_info: saving infos
65
+ :type saving_info: dict
66
+ :param raster_profile: raster_profile
67
+ :type raster_profile: dict
68
+ :param row_coords: row cooordinates
69
+ :type row_coords: np.ndarray, optional
70
+ :param col_coords: col coordinates
71
+ :type col_coords: np.ndarray, optional
72
+
73
+ :return: disp range dataset
74
+ :rtype: xarray.Dataset
75
+ """
76
+
77
+ if row_coords is None:
78
+ row_coords = np.arange(0, grid_min.shape[0])
79
+
80
+ if col_coords is None:
81
+ col_coords = np.arange(0, grid_min.shape[1])
82
+
83
+ disp_range_tile = xr.Dataset(
84
+ data_vars={
85
+ dm_cst.DISP_MIN_GRID: (["row", "col"], grid_min),
86
+ dm_cst.DISP_MAX_GRID: (["row", "col"], grid_max),
87
+ },
88
+ coords={
89
+ "row": row_coords,
90
+ "col": col_coords,
91
+ },
92
+ )
93
+
94
+ cars_dataset.fill_dataset(
95
+ disp_range_tile,
96
+ saving_info=saving_info,
97
+ window=window,
98
+ profile=raster_profile,
99
+ attributes=None,
100
+ overlaps=None,
101
+ )
102
+
103
+ return disp_range_tile
104
+
105
+
106
+ def generate_disp_range_const_tile_wrapper(
107
+ row_range,
108
+ col_range,
109
+ dmin,
110
+ dmax,
111
+ raster_profile,
112
+ saving_info,
113
+ saving_info_global_infos,
114
+ ):
115
+ """
116
+ Generate disparity range dataset from constant dmin and dmax
117
+
118
+ :param row_range: Row range
119
+ :type row_range: list
120
+ :param col_range: Column range.
121
+ :type col_range: list
122
+ :param dmin: disparity minimum.
123
+ :type dmin: float
124
+ :param dmax: disparity maximum.
125
+ :type dmax: float
126
+ :param raster_profile: The raster profile.
127
+ :type raster_profile: dict
128
+ :param saving_info: The disp range grid saving information.
129
+ :type saving_info: dict
130
+ :param saving_info_global_infos: Global info saving infos.
131
+ :type saving_info_global_infos: dict
132
+
133
+ :return: Disparity range grid
134
+ :rtype: dict
135
+ """
136
+ grid_min = np.empty((len(row_range), len(col_range)))
137
+ grid_max = np.empty((len(row_range), len(col_range)))
138
+ grid_min[:, :] = dmin
139
+ grid_max[:, :] = dmax
140
+
141
+ mono_tile_saving_info = ocht.update_saving_infos(saving_info, row=0, col=0)
142
+ disp_range = generate_disp_grids_dataset(
143
+ grid_min, grid_max, mono_tile_saving_info, raster_profile, window=None
144
+ )
145
+
146
+ # Generate infos on global min and max
147
+ global_infos = cars_dict.CarsDict(
148
+ {"global_min": np.nanmin(dmin), "global_max": np.nanmin(dmax)}
149
+ )
150
+ cars_dataset.fill_dict(global_infos, saving_info=saving_info_global_infos)
151
+
152
+ return disp_range, global_infos
153
+
154
+
155
+ def generate_disp_range_from_dem_wrapper(
156
+ epipolar_grid_array_window,
157
+ full_epi_row_range,
158
+ full_epi_col_range,
159
+ sensor_image_right,
160
+ grid_right,
161
+ geom_plugin_with_dem_and_geoid,
162
+ dem_median,
163
+ dem_min,
164
+ dem_max,
165
+ altitude_delta_min,
166
+ altitude_delta_max,
167
+ raster_profile,
168
+ saving_info,
169
+ saving_info_global_infos,
170
+ filter_overlap,
171
+ disp_to_alt_ratio,
172
+ disp_min_threshold=None,
173
+ disp_max_threshold=None,
174
+ ):
175
+ """
176
+ Generate disparity range dataset from dems
177
+
178
+ :param epipolar_grid_array_window: The window of the epipolar grid array.
179
+ :type epipolar_grid_array_window: dict
180
+ :param full_epi_row_range: The full range of rows in the epipolar grid.
181
+ :type full_epi_row_range: list
182
+ :param full_epi_col_range: The full range of columns in the epipolar grid.
183
+ :type full_epi_col_range: list
184
+ :param sensor_image_right: The right sensor image.
185
+ :type sensor_image_right: dict
186
+ :param grid_right: The right epipolar grid.
187
+ :type grid_right: dict
188
+ :param geom_plugin_with_dem_and_geoid: The geometry plugin with DEM.
189
+ :type geom_plugin_with_dem_and_geoid: object
190
+ :param dem_median: Path of dem median.
191
+ :type dem_median: str
192
+ :param dem_min: Path of dem min.
193
+ :type dem_min: str
194
+ :param dem_max: Path of dem max.
195
+ :type dem_max: srt
196
+ :param altitude_delta_min: The minimum altitude delta.
197
+ :type altitude_delta_min: float
198
+ :param altitude_delta_max: The maximum altitude delta.
199
+ :type altitude_delta_max: float
200
+ :param raster_profile: The raster profile.
201
+ :type raster_profile: dict
202
+ :param saving_info: The disp range grid saving information.
203
+ :type saving_info: dict
204
+ :param saving_info_global_infos: Global info saving infos.
205
+ :type saving_info_global_infos: dict
206
+ :param filter_overlap: The overlap to use for filtering.
207
+ :type filter_overlap: int
208
+ :param disp_to_alt_ratio: disparity to altitude ratio
209
+ :type disp_to_alt_ratio: float
210
+ :param disp_min_threshold: The minimum disparity threshold.
211
+ :type disp_min_threshold: float, optional
212
+ :param disp_max_threshold: The maximum disparity threshold.
213
+ :type disp_max_threshold: float, optional
214
+
215
+ :return: Disparity range grid
216
+ :rtype: dict
217
+ """
218
+
219
+ # Geometry plugin
220
+ geo_plugin = geom_plugin_with_dem_and_geoid
221
+
222
+ # get epsg
223
+ terrain_epsg = inputs.rasterio_get_epsg(dem_median)
224
+
225
+ # Get epipolar position of all dem mean
226
+ transform_dem_median = inputs.rasterio_get_transform(dem_median)
227
+
228
+ # use local disparity
229
+
230
+ # Get associated alti mean / min / max values
231
+ dem_median_shape = inputs.rasterio_get_size(dem_median)
232
+ dem_median_width, dem_median_height = dem_median_shape
233
+
234
+ # get corresponding window from epipolar_array_window
235
+ epi_grid_margin = filter_overlap + 1
236
+ epi_grid_row_min = epipolar_grid_array_window["row_min"]
237
+ epi_grid_row_max = epipolar_grid_array_window["row_max"]
238
+ epi_grid_col_min = epipolar_grid_array_window["col_min"]
239
+ epi_grid_col_max = epipolar_grid_array_window["col_max"]
240
+
241
+ def clip(value, min_value, max_value):
242
+ """
243
+ Clip a value inside bounds
244
+ """
245
+ return int(max(min_value, min(value, max_value)))
246
+
247
+ # Epi grid tile coordinate to use, with and without margins
248
+ epi_grid_row_min_with_margin = clip(
249
+ epi_grid_row_min - epi_grid_margin, 0, len(full_epi_row_range)
250
+ )
251
+ epi_grid_row_max_with_margin = clip(
252
+ epi_grid_row_max + epi_grid_margin, 0, len(full_epi_row_range)
253
+ )
254
+ epi_grid_col_min_with_margin = clip(
255
+ epi_grid_col_min - epi_grid_margin, 0, len(full_epi_col_range)
256
+ )
257
+ epi_grid_col_max_with_margin = clip(
258
+ epi_grid_col_max + epi_grid_margin, 0, len(full_epi_col_range)
259
+ )
260
+
261
+ # range to use for epipolar interpolation
262
+ row_range_with_margin = full_epi_row_range[
263
+ epi_grid_row_min_with_margin:epi_grid_row_max_with_margin
264
+ ]
265
+ row_range_no_margin = full_epi_row_range[epi_grid_row_min:epi_grid_row_max]
266
+ col_range_with_margin = full_epi_col_range[
267
+ epi_grid_col_min_with_margin:epi_grid_col_max_with_margin
268
+ ]
269
+ col_range_no_margin = full_epi_col_range[epi_grid_col_min:epi_grid_col_max]
270
+
271
+ # Loc on dem median
272
+ epi_bbox = [
273
+ (np.min(col_range_with_margin), np.min(row_range_with_margin)),
274
+ (np.min(col_range_with_margin), np.max(row_range_with_margin)),
275
+ (np.max(col_range_with_margin), np.min(row_range_with_margin)),
276
+ (np.max(col_range_with_margin), np.max(row_range_with_margin)),
277
+ ]
278
+ sensor_bbox = geo_plugin.sensor_position_from_grid(grid_right, epi_bbox)
279
+ transform_sensor = inputs.rasterio_get_transform(
280
+ sensor_image_right["image"]["main_file"]
281
+ )
282
+ row_sensor_bbox, col_sensor_bbox = transform_physical_point_to_index(
283
+ ~transform_sensor, sensor_bbox[:, 1], sensor_bbox[:, 0]
284
+ )
285
+
286
+ terrain_bbox = geo_plugin.direct_loc(
287
+ sensor_image_right["image"]["main_file"],
288
+ sensor_image_right["geomodel"],
289
+ col_sensor_bbox,
290
+ row_sensor_bbox,
291
+ )
292
+
293
+ # reshape terrain bbox
294
+ terrain_bbox = terrain_bbox[0:2].T
295
+ terrain_bbox[:, [1, 0]] = terrain_bbox[:, [0, 1]]
296
+
297
+ # get pixel location on dem median
298
+ pixel_roi_dem_mean = inputs.rasterio_get_pixel_points(
299
+ dem_median, terrain_bbox
300
+ )
301
+
302
+ # Add margins (for interpolation) and clip
303
+ dem_margin = 10 # arbitrary
304
+ roi_lower_row = np.floor(np.min(pixel_roi_dem_mean[:, 0])) - dem_margin
305
+ roi_upper_row = np.ceil(np.max(pixel_roi_dem_mean[:, 0])) + dem_margin
306
+ roi_lower_col = np.floor(np.min(pixel_roi_dem_mean[:, 1])) - dem_margin
307
+ roi_upper_col = np.ceil(np.max(pixel_roi_dem_mean[:, 1])) + dem_margin
308
+
309
+ min_row = clip(roi_lower_row, 0, dem_median_height)
310
+ max_row = clip(roi_upper_row, 0, dem_median_height)
311
+ min_col = clip(roi_lower_col, 0, dem_median_width)
312
+ max_col = clip(roi_upper_col, 0, dem_median_width)
313
+
314
+ # compute terrain positions to use (all dem min and max)
315
+ row_indexes = range(min_row, max_row)
316
+ col_indexes = range(min_col, max_col)
317
+ transformer = rasterio.transform.AffineTransformer(transform_dem_median)
318
+
319
+ indexes = np.array(list(itertools.product(row_indexes, col_indexes)))
320
+
321
+ row = indexes[:, 0]
322
+ col = indexes[:, 1]
323
+ x_mean, y_mean = transformer.xy(row, col)
324
+ terrain_positions = np.transpose(np.array([x_mean, y_mean]))
325
+
326
+ # dem mean in terrain_epsg
327
+ x_mean = terrain_positions[:, 0]
328
+ y_mean = terrain_positions[:, 1]
329
+
330
+ dem_median_list = inputs.rasterio_get_values(
331
+ dem_median, x_mean, y_mean, point_cloud_conversion
332
+ )
333
+
334
+ nan_mask = ~np.isnan(dem_median_list)
335
+
336
+ # transform to lon lat
337
+ terrain_position_lon_lat = projection.point_cloud_conversion(
338
+ terrain_positions, terrain_epsg, 4326
339
+ )
340
+ lon_mean = terrain_position_lon_lat[:, 0]
341
+ lat_mean = terrain_position_lon_lat[:, 1]
342
+
343
+ if None not in (dem_min, dem_max, dem_median):
344
+ # dem min and max are in 4326
345
+ dem_min_list = inputs.rasterio_get_values(
346
+ dem_min, lon_mean, lat_mean, point_cloud_conversion
347
+ )
348
+ dem_max_list = inputs.rasterio_get_values(
349
+ dem_max, lon_mean, lat_mean, point_cloud_conversion
350
+ )
351
+ nan_mask = nan_mask & ~np.isnan(dem_min_list) & ~np.isnan(dem_max_list)
352
+ else:
353
+ dem_min_list = dem_median_list - altitude_delta_min
354
+ dem_max_list = dem_median_list + altitude_delta_max
355
+
356
+ # filter nan value from input points
357
+ lon_mean = lon_mean[nan_mask]
358
+ lat_mean = lat_mean[nan_mask]
359
+ dem_median_list = dem_median_list[nan_mask]
360
+ dem_min_list = dem_min_list[nan_mask]
361
+ dem_max_list = dem_max_list[nan_mask]
362
+
363
+ # sensors physical positions
364
+ (
365
+ ind_cols_sensor,
366
+ ind_rows_sensor,
367
+ _,
368
+ ) = geom_plugin_with_dem_and_geoid.inverse_loc(
369
+ sensor_image_right["image"]["main_file"],
370
+ sensor_image_right["geomodel"],
371
+ lat_mean,
372
+ lon_mean,
373
+ z_coord=dem_median_list,
374
+ )
375
+
376
+ # Generate epipolar disp grids
377
+ # Get epipolar positions
378
+ (epipolar_positions_row, epipolar_positions_col) = np.meshgrid(
379
+ col_range_with_margin,
380
+ row_range_with_margin,
381
+ )
382
+ epipolar_positions = np.stack(
383
+ [epipolar_positions_row, epipolar_positions_col], axis=2
384
+ )
385
+
386
+ # Get sensor position
387
+ sensors_positions = (
388
+ geom_plugin_with_dem_and_geoid.sensor_position_from_grid(
389
+ grid_right,
390
+ np.reshape(
391
+ epipolar_positions,
392
+ (
393
+ epipolar_positions.shape[0] * epipolar_positions.shape[1],
394
+ 2,
395
+ ),
396
+ ),
397
+ )
398
+ )
399
+
400
+ # compute reverse matrix
401
+ transform_sensor = rasterio.Affine(
402
+ *np.abs(
403
+ inputs.rasterio_get_transform(
404
+ sensor_image_right["image"]["main_file"]
405
+ )
406
+ )
407
+ )
408
+
409
+ trans_inv = ~transform_sensor
410
+ # Transform to positive values
411
+ trans_inv = np.array(trans_inv)
412
+ trans_inv = np.reshape(trans_inv, (3, 3))
413
+ if trans_inv[0, 0] < 0:
414
+ trans_inv[0, :] *= -1
415
+ if trans_inv[1, 1] < 0:
416
+ trans_inv[1, :] *= -1
417
+ trans_inv = affine.Affine(*list(trans_inv.flatten()))
418
+
419
+ # Transform physical position to index
420
+ index_positions = np.empty(sensors_positions.shape)
421
+ for row_point in range(index_positions.shape[0]):
422
+ row_geo, col_geo = sensors_positions[row_point, :]
423
+ col, row = trans_inv * (row_geo, col_geo)
424
+ index_positions[row_point, :] = (row, col)
425
+
426
+ ind_rows_sensor_grid = index_positions[:, 0] - 0.5
427
+ ind_cols_sensor_grid = index_positions[:, 1] - 0.5
428
+
429
+ if len(ind_rows_sensor) < 5:
430
+ # QH6214 needs at least 4 points for interpolation
431
+
432
+ grid_min = np.empty(
433
+ (len(row_range_no_margin), len(col_range_no_margin))
434
+ )
435
+ grid_max = np.empty(
436
+ (len(row_range_no_margin), len(col_range_no_margin))
437
+ )
438
+ grid_min[:, :] = 0
439
+ grid_max[:, :] = 0
440
+
441
+ disp_range = generate_disp_grids_dataset(
442
+ grid_min,
443
+ grid_max,
444
+ saving_info,
445
+ raster_profile,
446
+ window=epipolar_grid_array_window,
447
+ row_coords=row_range_no_margin,
448
+ col_coords=col_range_no_margin,
449
+ )
450
+
451
+ # Generate infos on global min and max
452
+ global_infos = cars_dict.CarsDict(
453
+ {
454
+ "global_min": 0,
455
+ "global_max": 0,
456
+ }
457
+ )
458
+ cars_dataset.fill_dict(
459
+ global_infos, saving_info=saving_info_global_infos
460
+ )
461
+
462
+ return disp_range, global_infos
463
+
464
+ # Interpolate disparity
465
+ disp_min_points = -(dem_max_list - dem_median_list) / disp_to_alt_ratio
466
+ disp_max_points = -(dem_min_list - dem_median_list) / disp_to_alt_ratio
467
+
468
+ interp_min_linear = LinearInterpNearestExtrap(
469
+ list(zip(ind_rows_sensor, ind_cols_sensor)), # noqa: B905
470
+ disp_min_points,
471
+ )
472
+ interp_max_linear = LinearInterpNearestExtrap(
473
+ list(zip(ind_rows_sensor, ind_cols_sensor)), # noqa: B905
474
+ disp_max_points,
475
+ )
476
+
477
+ grid_min = np.reshape(
478
+ interp_min_linear(ind_rows_sensor_grid, ind_cols_sensor_grid),
479
+ (
480
+ epipolar_positions.shape[0],
481
+ epipolar_positions.shape[1],
482
+ ),
483
+ )
484
+
485
+ grid_max = np.reshape(
486
+ interp_max_linear(ind_rows_sensor_grid, ind_cols_sensor_grid),
487
+ (
488
+ epipolar_positions.shape[0],
489
+ epipolar_positions.shape[1],
490
+ ),
491
+ )
492
+
493
+ # Add margin
494
+ diff = grid_max - grid_min
495
+ logging.info("Max grid max - grid min : {} disp ".format(np.max(diff)))
496
+
497
+ if disp_min_threshold is not None:
498
+ if np.any(grid_min < disp_min_threshold):
499
+ logging.warning(
500
+ "Override disp_min with disp_min_threshold {}".format(
501
+ disp_min_threshold
502
+ )
503
+ )
504
+ grid_min[grid_min < disp_min_threshold] = disp_min_threshold
505
+ if disp_max_threshold is not None:
506
+ if np.any(grid_max > disp_max_threshold):
507
+ logging.warning(
508
+ "Override disp_max with disp_max_threshold {}".format(
509
+ disp_max_threshold
510
+ )
511
+ )
512
+ grid_max[grid_max > disp_max_threshold] = disp_max_threshold
513
+
514
+ # generate footprint
515
+ footprint_mask = create_circular_mask(filter_overlap, filter_overlap)
516
+ grid_min = minimum_filter(
517
+ grid_min, footprint=footprint_mask, mode="nearest"
518
+ )
519
+ grid_max = maximum_filter(
520
+ grid_max, footprint=footprint_mask, mode="nearest"
521
+ )
522
+
523
+ # Create xarray dataset
524
+ disp_range = generate_disp_grids_dataset(
525
+ grid_min,
526
+ grid_max,
527
+ saving_info,
528
+ raster_profile,
529
+ window=epipolar_grid_array_window,
530
+ row_coords=row_range_with_margin,
531
+ col_coords=col_range_with_margin,
532
+ )
533
+
534
+ # crop epipolar grid from margin added for propagation filter
535
+ disp_range = disp_range.sel(
536
+ row=list(row_range_no_margin), col=list(col_range_no_margin)
537
+ )
538
+
539
+ # Generate infos on global min and max
540
+ global_infos = cars_dict.CarsDict(
541
+ {
542
+ "global_min": np.floor(np.nanmin(grid_min)),
543
+ "global_max": np.ceil(np.nanmax(grid_max)),
544
+ }
545
+ )
546
+ cars_dataset.fill_dict(global_infos, saving_info=saving_info_global_infos)
547
+
548
+ return disp_range, global_infos
549
+
550
+
551
+ def create_circular_mask(height, width):
552
+ """
553
+ Create a circular mask for footprint around pixel
554
+
555
+ :param height: height of footprint
556
+ :type height: int
557
+ :param width: width of footprint
558
+ :type width: int
559
+
560
+ :return: mask representing circular footprint
561
+ :rtype: np.ndarray
562
+ """
563
+ center = (int(width / 2), int(height / 2))
564
+ radius = min(center[0], center[1], width - center[0], height - center[1])
565
+
566
+ y_grid, x_grid = np.ogrid[:height, :width]
567
+ dist_from_center = np.sqrt(
568
+ (x_grid - center[0]) ** 2 + (y_grid - center[1]) ** 2
569
+ )
570
+
571
+ mask = dist_from_center <= radius
572
+ return mask.astype(bool)
@@ -31,7 +31,6 @@ import os
31
31
 
32
32
  # Third party imports
33
33
  import numpy as np
34
- import pandas
35
34
  import rasterio as rio
36
35
  from scipy.interpolate import LinearNDInterpolator
37
36
  from scipy.spatial import Delaunay # pylint: disable=E0611
@@ -45,7 +44,6 @@ from cars.applications.grid_generation import (
45
44
  from cars.core.utils import safe_makedirs
46
45
 
47
46
  # CARS imports
48
- from cars.data_structures import cars_dataset
49
47
  from cars.orchestrator.cluster.log_wrapper import cars_profile
50
48
 
51
49
 
@@ -171,7 +169,6 @@ def correct_grid(grid, grid_correction, pair_folder, save_grid=None):
171
169
  def estimate_right_grid_correction(
172
170
  matches,
173
171
  grid_right,
174
- initial_cars_ds=None,
175
172
  save_matches=False,
176
173
  minimum_nb_matches=100,
177
174
  pair_folder="",
@@ -480,13 +477,6 @@ def estimate_right_grid_correction(
480
477
  )
481
478
  np.save(matches_array_path, corrected_matches)
482
479
 
483
- # Create CarsDataset containing corrected matches, with same tiling as input
484
- corrected_matches_cars_ds = None
485
- if initial_cars_ds is not None:
486
- corrected_matches_cars_ds = create_matches_cars_ds(
487
- corrected_matches, initial_cars_ds
488
- )
489
-
490
480
  # Update orchestrator out_json
491
481
  corrected_matches_infos = {
492
482
  application_constants.APPLICATION_TAG: {
@@ -498,49 +488,6 @@ def estimate_right_grid_correction(
498
488
  return (
499
489
  grid_correction,
500
490
  corrected_matches,
501
- corrected_matches_cars_ds,
502
491
  in_stats,
503
492
  out_stats,
504
493
  )
505
-
506
-
507
- def create_matches_cars_ds(corrected_matches, initial_cars_ds):
508
- """
509
- Create CarsDataset representing matches, from numpy matches.
510
- Matches are split into tiles, stored in pandas DataFrames
511
-
512
- Right CarsDataset is filled with Nones
513
-
514
- :param corrected_matches: matches
515
- :type corrected_matches: numpy array
516
- :param initial_cars_ds: cars dataset to use tiling from
517
- :type initial_cars_ds: CarsDataset
518
-
519
- :return new_matches_cars_ds
520
- :rtype: CarsDataset
521
- """
522
-
523
- # initialize CarsDataset
524
- new_matches_cars_ds = cars_dataset.CarsDataset("points")
525
- new_matches_cars_ds.create_empty_copy(initial_cars_ds)
526
- new_matches_cars_ds.attributes = initial_cars_ds.attributes
527
-
528
- for row in range(new_matches_cars_ds.shape[0]):
529
- for col in range(new_matches_cars_ds.shape[1]):
530
- [
531
- row_min,
532
- row_max,
533
- col_min,
534
- col_max,
535
- ] = new_matches_cars_ds.tiling_grid[row, col, :]
536
-
537
- # Get corresponding matches
538
- tile_matches = corrected_matches[corrected_matches[:, 1] > row_min]
539
- tile_matches = tile_matches[tile_matches[:, 1] < row_max]
540
- tile_matches = tile_matches[tile_matches[:, 0] > col_min]
541
- tile_matches = tile_matches[tile_matches[:, 0] < col_max]
542
-
543
- # Create pandas DataFrame
544
- new_matches_cars_ds[row, col] = pandas.DataFrame(tile_matches)
545
-
546
- return new_matches_cars_ds
@@ -41,9 +41,9 @@ def transform_grid_func(grid, resolution, right=False):
41
41
  for key, value in grid.items():
42
42
  if right:
43
43
  if key not in ("grid_origin", "grid_spacing"):
44
- divide(key, value, grid, resolution)
44
+ scale(key, value, grid, resolution)
45
45
  else:
46
- divide(key, value, grid, resolution)
46
+ scale(key, value, grid, resolution)
47
47
 
48
48
  # we need to charge the data to override it
49
49
  with rasterio.open(grid["path"]) as src:
@@ -59,9 +59,9 @@ def transform_grid_func(grid, resolution, right=False):
59
59
  return grid
60
60
 
61
61
 
62
- def divide(key, value, grid, resolution):
62
+ def scale(key, value, grid, resolution):
63
63
  """
64
- Divide attributs by the resolution
64
+ Scale attributes by the resolution
65
65
  """
66
66
 
67
67
  if key == "grid_origin":
@@ -71,7 +71,7 @@ def divide(key, value, grid, resolution):
71
71
  for i, _ in enumerate(value):
72
72
  grid[key][i] = np.floor(value[i] / resolution)
73
73
  elif key == "disp_to_alt_ratio":
74
- grid[key] = value / resolution
74
+ grid[key] = value * resolution
75
75
  elif key == "epipolar_size_x":
76
76
  grid[key] = np.floor(value / resolution)
77
77
  elif key == "epipolar_size_y":