cars 1.0.0a1__cp313-cp313-win_amd64.whl → 1.0.0a3__cp313-cp313-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 (81) hide show
  1. cars/__init__.py +4 -4
  2. cars/applications/application.py +14 -6
  3. cars/applications/application_template.py +22 -0
  4. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +15 -10
  5. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +7 -6
  6. cars/applications/dem_generation/abstract_dem_generation_app.py +9 -5
  7. cars/applications/dem_generation/dem_generation_wrappers.py +48 -25
  8. cars/applications/dem_generation/dichotomic_generation_app.py +27 -9
  9. cars/applications/dem_generation/rasterization_app.py +85 -32
  10. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +4 -0
  11. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp313-win_amd64.dll.a +0 -0
  12. cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp313-win_amd64.pyd +0 -0
  13. cars/applications/dense_match_filling/fill_disp_algo.py +41 -12
  14. cars/applications/dense_match_filling/plane_app.py +11 -0
  15. cars/applications/dense_match_filling/zero_padding_app.py +11 -1
  16. cars/applications/dense_matching/census_mccnn_sgm_app.py +254 -548
  17. cars/applications/dense_matching/cpp/dense_matching_cpp.cp313-win_amd64.dll.a +0 -0
  18. cars/applications/dense_matching/cpp/dense_matching_cpp.cp313-win_amd64.pyd +0 -0
  19. cars/applications/dense_matching/dense_matching_algo.py +59 -11
  20. cars/applications/dense_matching/dense_matching_wrappers.py +51 -31
  21. cars/applications/dense_matching/disparity_grid_algo.py +566 -0
  22. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  23. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  24. cars/applications/dense_matching/loaders/pandora_loader.py +78 -1
  25. cars/applications/dsm_filling/border_interpolation_app.py +10 -5
  26. cars/applications/dsm_filling/bulldozer_filling_app.py +14 -7
  27. cars/applications/dsm_filling/exogenous_filling_app.py +10 -5
  28. cars/applications/grid_generation/grid_correction_app.py +0 -53
  29. cars/applications/grid_generation/transform_grid.py +5 -5
  30. cars/applications/point_cloud_fusion/pc_fusion_algo.py +17 -11
  31. cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +3 -4
  32. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +9 -5
  33. cars/applications/point_cloud_outlier_removal/small_components_app.py +5 -3
  34. cars/applications/point_cloud_outlier_removal/statistical_app.py +4 -2
  35. cars/applications/rasterization/abstract_pc_rasterization_app.py +1 -0
  36. cars/applications/rasterization/rasterization_algo.py +20 -27
  37. cars/applications/rasterization/rasterization_wrappers.py +6 -5
  38. cars/applications/rasterization/simple_gaussian_app.py +30 -17
  39. cars/applications/resampling/resampling_algo.py +44 -49
  40. cars/applications/sparse_matching/sift_app.py +2 -22
  41. cars/applications/sparse_matching/sparse_matching_wrappers.py +0 -49
  42. cars/applications/triangulation/line_of_sight_intersection_app.py +1 -1
  43. cars/applications/triangulation/triangulation_wrappers.py +2 -1
  44. cars/bundleadjustment.py +51 -11
  45. cars/cars.py +15 -5
  46. cars/core/constants.py +1 -1
  47. cars/core/geometry/abstract_geometry.py +166 -12
  48. cars/core/geometry/shareloc_geometry.py +61 -14
  49. cars/core/inputs.py +15 -0
  50. cars/core/projection.py +117 -0
  51. cars/data_structures/cars_dataset.py +7 -5
  52. cars/orchestrator/cluster/log_wrapper.py +1 -1
  53. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +1 -1
  54. cars/orchestrator/orchestrator.py +1 -1
  55. cars/orchestrator/registry/saver_registry.py +0 -78
  56. cars/pipelines/default/default_pipeline.py +69 -52
  57. cars/pipelines/parameters/advanced_parameters.py +17 -0
  58. cars/pipelines/parameters/advanced_parameters_constants.py +4 -0
  59. cars/pipelines/parameters/depth_map_inputs.py +22 -67
  60. cars/pipelines/parameters/dsm_inputs.py +16 -29
  61. cars/pipelines/parameters/output_parameters.py +44 -8
  62. cars/pipelines/parameters/sensor_inputs.py +117 -24
  63. cars/pipelines/parameters/sensor_loaders/basic_sensor_loader.py +3 -3
  64. cars/pipelines/parameters/sensor_loaders/pivot_sensor_loader.py +2 -2
  65. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
  66. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +2 -2
  67. cars/pipelines/pipeline.py +8 -8
  68. cars/pipelines/unit/unit_pipeline.py +276 -274
  69. cars/starter.py +20 -1
  70. cars-1.0.0a3.dist-info/DELVEWHEEL +2 -0
  71. {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/METADATA +3 -2
  72. {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/RECORD +77 -74
  73. cars.libs/libgcc_s_seh-1-ca70890bbc5723b6d0ea31e9c9cded2b.dll +0 -0
  74. cars.libs/libstdc++-6-00ee19f73d5122a1277c137b1c218401.dll +0 -0
  75. cars.libs/libwinpthread-1-f5042e8e3d21edce20c1bc99445f551b.dll +0 -0
  76. cars-1.0.0a1.dist-info/DELVEWHEEL +0 -2
  77. cars.libs/libgcc_s_seh-1-f2b6825d483bdf14050493af93b5997d.dll +0 -0
  78. cars.libs/libstdc++-6-6b0059df6bc601df5a0f18a5805eea05.dll +0 -0
  79. cars.libs/libwinpthread-1-e01b8e85fd67c2b861f64d4ccc7df607.dll +0 -0
  80. {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/WHEEL +0 -0
  81. {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/entry_points.txt +0 -0
@@ -26,25 +26,21 @@ import collections
26
26
 
27
27
  # Standard imports
28
28
  import copy
29
- import itertools
30
29
  import logging
31
30
  import math
32
31
  import os
33
32
  from typing import Dict, Tuple
34
33
 
35
34
  # Third party imports
36
- import affine
37
35
  import numpy as np
38
- import pandas
39
36
  import pandora
40
- import rasterio
41
37
  import xarray as xr
42
- from affine import Affine
43
38
  from json_checker import And, Checker, Or
44
39
  from pandora.check_configuration import check_pipeline_section
45
40
  from pandora.img_tools import add_global_disparity
46
41
  from pandora.state_machine import PandoraMachine
47
- from scipy.ndimage import generic_filter
42
+ from rasterio.profiles import DefaultGTiffProfile
43
+ from scipy.ndimage import maximum_filter, minimum_filter
48
44
 
49
45
  import cars.applications.dense_matching.dense_matching_constants as dm_cst
50
46
  import cars.orchestrator.orchestrator as ocht
@@ -56,8 +52,9 @@ from cars.applications.dense_matching import (
56
52
  from cars.applications.dense_matching.abstract_dense_matching_app import (
57
53
  DenseMatching,
58
54
  )
59
- from cars.applications.dense_matching.dense_matching_algo import (
60
- LinearInterpNearestExtrap,
55
+ from cars.applications.dense_matching.disparity_grid_algo import (
56
+ generate_disp_range_const_tile_wrapper,
57
+ generate_disp_range_from_dem_wrapper,
61
58
  )
62
59
  from cars.applications.dense_matching.loaders.pandora_loader import (
63
60
  PandoraLoader,
@@ -66,8 +63,7 @@ from cars.applications.dense_matching.loaders.pandora_loader import (
66
63
  # CARS imports
67
64
  from cars.core import constants as cst
68
65
  from cars.core import constants_disparity as cst_disp
69
- from cars.core import inputs, projection
70
- from cars.core.projection import point_cloud_conversion
66
+ from cars.core import inputs, tiling
71
67
  from cars.core.utils import safe_makedirs
72
68
  from cars.data_structures import cars_dataset, format_transformation
73
69
  from cars.orchestrator.cluster.log_wrapper import cars_profile
@@ -82,6 +78,7 @@ class CensusMccnnSgm(
82
78
  "census_sgm_mountain_and_vegetation",
83
79
  "census_sgm_homogeneous",
84
80
  "mccnn_sgm",
81
+ "auto",
85
82
  ],
86
83
  ): # pylint: disable=R0903,disable=R0902
87
84
  """
@@ -126,6 +123,9 @@ class CensusMccnnSgm(
126
123
  self.disp_range_propagation_filter_size = self.used_config[
127
124
  "disp_range_propagation_filter_size"
128
125
  ]
126
+ self.epi_disp_grid_tile_size = self.used_config[
127
+ "epi_disp_grid_tile_size"
128
+ ]
129
129
  self.use_cross_validation = self.used_config["use_cross_validation"]
130
130
  self.denoise_disparity_map = self.used_config["denoise_disparity_map"]
131
131
  self.required_bands = self.used_config["required_bands"]
@@ -133,7 +133,11 @@ class CensusMccnnSgm(
133
133
 
134
134
  # Saving files
135
135
  self.save_intermediate_data = self.used_config["save_intermediate_data"]
136
+
136
137
  self.confidence_filtering = self.used_config["confidence_filtering"]
138
+ self.threshold_disp_range_to_borders = self.used_config[
139
+ "threshold_disp_range_to_borders"
140
+ ]
137
141
 
138
142
  # init orchestrator
139
143
  self.orchestrator = None
@@ -175,7 +179,7 @@ class CensusMccnnSgm(
175
179
 
176
180
  # Overload conf
177
181
  overloaded_conf["method"] = conf.get(
178
- "method", "census_sgm_default"
182
+ "method", "auto"
179
183
  ) # change it if census_sgm is not default
180
184
  # method called in abstract_dense_matching_app.py
181
185
  overloaded_conf["min_epi_tile_size"] = conf.get(
@@ -232,13 +236,19 @@ class CensusMccnnSgm(
232
236
  "use_global_disp_range", False
233
237
  )
234
238
  overloaded_conf["local_disp_grid_step"] = conf.get(
235
- "local_disp_grid_step", 30
239
+ "local_disp_grid_step", 10
236
240
  )
237
241
  overloaded_conf["disp_range_propagation_filter_size"] = conf.get(
238
- "disp_range_propagation_filter_size", 300
242
+ "disp_range_propagation_filter_size", 50
243
+ )
244
+ overloaded_conf["epi_disp_grid_tile_size"] = conf.get(
245
+ "epi_disp_grid_tile_size", 800
239
246
  )
240
247
  overloaded_conf["required_bands"] = conf.get("required_bands", ["b0"])
241
248
  overloaded_conf["used_band"] = conf.get("used_band", "b0")
249
+ overloaded_conf["threshold_disp_range_to_borders"] = conf.get(
250
+ "threshold_disp_range_to_borders", False
251
+ )
242
252
 
243
253
  # Saving files
244
254
  overloaded_conf["save_intermediate_data"] = conf.get(
@@ -360,11 +370,13 @@ class CensusMccnnSgm(
360
370
  "disp_range_propagation_filter_size": And(
361
371
  Or(int, float), lambda x: x >= 0
362
372
  ),
373
+ "epi_disp_grid_tile_size": int,
363
374
  "required_bands": [str],
364
375
  "used_band": str,
365
376
  "loader_conf": Or(dict, collections.OrderedDict, str, None),
366
377
  "loader": str,
367
378
  "confidence_filtering": dict,
379
+ "threshold_disp_range_to_borders": bool,
368
380
  }
369
381
 
370
382
  # Check conf
@@ -416,33 +428,41 @@ class CensusMccnnSgm(
416
428
  overloaded_conf["confidence_filtering"]["activated"] = overloaded_conf[
417
429
  "confidence_filtering"
418
430
  ].get("activated", True)
419
- overloaded_conf["confidence_filtering"]["upper_bound"] = (
420
- overloaded_conf["confidence_filtering"].get("upper_bound", 5)
431
+ overloaded_conf["confidence_filtering"]["bounds_ratio_threshold"] = (
432
+ overloaded_conf["confidence_filtering"].get(
433
+ "bounds_ratio_threshold", 0.2
434
+ )
421
435
  )
422
- overloaded_conf["confidence_filtering"]["lower_bound"] = (
423
- overloaded_conf["confidence_filtering"].get("lower_bound", -30)
436
+ overloaded_conf["confidence_filtering"]["risk_ratio_threshold"] = (
437
+ overloaded_conf["confidence_filtering"].get(
438
+ "risk_ratio_threshold", 0.8
439
+ )
440
+ )
441
+ overloaded_conf["confidence_filtering"]["bounds_range_threshold"] = (
442
+ overloaded_conf["confidence_filtering"].get(
443
+ "bounds_range_threshold", 4
444
+ )
445
+ )
446
+ overloaded_conf["confidence_filtering"]["risk_range_threshold"] = (
447
+ overloaded_conf["confidence_filtering"].get(
448
+ "risk_range_threshold", 12
449
+ )
424
450
  )
425
- overloaded_conf["confidence_filtering"]["risk_max"] = overloaded_conf[
426
- "confidence_filtering"
427
- ].get("risk_max", 60)
428
451
  overloaded_conf["confidence_filtering"]["nan_threshold"] = (
429
- overloaded_conf["confidence_filtering"].get("nan_threshold", 0.1)
452
+ overloaded_conf["confidence_filtering"].get("nan_threshold", 0.2)
430
453
  )
431
454
  overloaded_conf["confidence_filtering"]["win_nanratio"] = (
432
455
  overloaded_conf["confidence_filtering"].get("win_nanratio", 20)
433
456
  )
434
- overloaded_conf["confidence_filtering"]["win_mean_risk_max"] = (
435
- overloaded_conf["confidence_filtering"].get("win_mean_risk_max", 7)
436
- )
437
457
 
438
458
  confidence_filtering_schema = {
439
459
  "activated": bool,
440
- "upper_bound": int,
441
- "lower_bound": int,
442
- "risk_max": int,
460
+ "bounds_ratio_threshold": float,
461
+ "risk_ratio_threshold": float,
462
+ "bounds_range_threshold": int,
463
+ "risk_range_threshold": int,
443
464
  "nan_threshold": float,
444
465
  "win_nanratio": int,
445
- "win_mean_risk_max": int,
446
466
  }
447
467
 
448
468
  checker_confidence_filtering_schema = Checker(
@@ -464,12 +484,16 @@ class CensusMccnnSgm(
464
484
 
465
485
  """
466
486
 
467
- disp_min_grid_arr = disp_range_grid[0, 0]["disp_min_grid"].values
468
- disp_max_grid_arr = disp_range_grid[0, 0]["disp_max_grid"].values
469
- step_row = disp_range_grid.attributes["step_row"]
470
- step_col = disp_range_grid.attributes["step_col"]
471
- row_range = disp_range_grid.attributes["row_range"]
472
- col_range = disp_range_grid.attributes["col_range"]
487
+ disp_min_grid_arr, _ = inputs.rasterio_read_as_array(
488
+ disp_range_grid["grid_min_path"]
489
+ )
490
+ disp_max_grid_arr, _ = inputs.rasterio_read_as_array(
491
+ disp_range_grid["grid_max_path"]
492
+ )
493
+ step_row = disp_range_grid["step_row"]
494
+ step_col = disp_range_grid["step_col"]
495
+ row_range = disp_range_grid["row_range"]
496
+ col_range = disp_range_grid["col_range"]
473
497
 
474
498
  # get disp_to_alt_ratio
475
499
  disp_to_alt_ratio = grid_left["disp_to_alt_ratio"]
@@ -574,6 +598,13 @@ class CensusMccnnSgm(
574
598
 
575
599
  return margins_wrapper
576
600
 
601
+ def get_method(self):
602
+ """
603
+ return the method that will be used in dense_matching
604
+ """
605
+
606
+ return self.used_method
607
+
577
608
  @cars_profile(name="Optimal size estimation")
578
609
  def get_optimal_tile_size(self, disp_range_grid, max_ram_per_worker):
579
610
  """
@@ -585,19 +616,24 @@ class CensusMccnnSgm(
585
616
 
586
617
  """
587
618
 
588
- disp_min_grids = disp_range_grid[0, 0][dm_cst.DISP_MIN_GRID].values
589
- disp_max_grids = disp_range_grid[0, 0][dm_cst.DISP_MAX_GRID].values
619
+ disp_min_grids, _ = inputs.rasterio_read_as_array(
620
+ disp_range_grid["grid_min_path"]
621
+ )
622
+ disp_max_grids, _ = inputs.rasterio_read_as_array(
623
+ disp_range_grid["grid_max_path"]
624
+ )
590
625
 
591
626
  # use max tile size as overlap for min and max:
592
627
  # max Point to point diff is less than diff of tile
593
628
 
594
629
  # use filter of size max_epi_tile_size
595
630
  overlap = 3 * int(self.max_epi_tile_size / self.local_disp_grid_step)
596
- disp_min_grids = generic_filter(
597
- disp_min_grids, np.nanmin, [overlap, overlap], mode="nearest"
631
+
632
+ disp_min_grids = minimum_filter(
633
+ disp_min_grids, size=[overlap, overlap], mode="nearest"
598
634
  )
599
- disp_max_grids = generic_filter(
600
- disp_max_grids, np.nanmax, [overlap, overlap], mode="nearest"
635
+ disp_max_grids = maximum_filter(
636
+ disp_max_grids, size=[overlap, overlap], mode="nearest"
601
637
  )
602
638
 
603
639
  # Worst cases scenario:
@@ -692,7 +728,7 @@ class CensusMccnnSgm(
692
728
  dem_min=None,
693
729
  dem_max=None,
694
730
  pair_folder=None,
695
- loc_inverse_orchestrator=None,
731
+ orchestrator=None,
696
732
  ):
697
733
  """
698
734
  Generate disparity grids min and max, with given step
@@ -724,18 +760,24 @@ class CensusMccnnSgm(
724
760
  :type dem_max: str
725
761
  :param pair_folder: folder used for current pair
726
762
  :type pair_folder: str
727
- :param loc_inverse_orchestrator: orchestrator to perform inverse locs
728
- :type loc_inverse_orchestrator: Orchestrator
763
+ :param orchestrator: orchestrator
764
+ :type orchestrator: Orchestrator
729
765
 
730
766
 
731
767
  :return disparity grid range, containing grid min and max
732
768
  :rtype: CarsDataset
733
769
  """
734
770
 
735
- # Create sequential orchestrator for savings
736
- grid_orchestrator = ocht.Orchestrator(
737
- orchestrator_conf={"mode": "sequential"}
738
- )
771
+ # Default orchestrator
772
+ if orchestrator is None:
773
+ # Create default sequential orchestrator for current application
774
+ # be aware, no out_json will be shared between orchestrators
775
+ # No files saved
776
+ self.orchestrator = ocht.Orchestrator(
777
+ orchestrator_conf={"mode": "sequential"}
778
+ )
779
+ else:
780
+ self.orchestrator = orchestrator
739
781
 
740
782
  epi_size_row = grid_right["epipolar_size_y"]
741
783
  epi_size_col = grid_right["epipolar_size_x"]
@@ -751,46 +793,31 @@ class CensusMccnnSgm(
751
793
  0, epi_size_col, nb_cols, retstep=True
752
794
  )
753
795
 
754
- grid_min = np.empty((len(row_range), len(col_range)))
755
- grid_max = np.empty((len(row_range), len(col_range)))
756
-
757
796
  # Create CarsDataset
758
797
  grid_disp_range = cars_dataset.CarsDataset(
759
798
  "arrays", name="grid_disp_range_unknown_pair"
760
799
  )
761
- # Only one tile
762
- grid_disp_range.tiling_grid = np.array(
763
- [[[0, epi_size_row, 0, epi_size_col]]]
764
- )
800
+ global_infos_cars_ds = cars_dataset.CarsDataset("dict")
765
801
 
766
- grid_attributes = {
767
- "step_row": step_row,
768
- "step_col": step_col,
769
- "row_range": row_range,
770
- "col_range": col_range,
771
- }
772
- grid_disp_range.attributes = grid_attributes.copy()
802
+ # Generate profile
803
+ raster_profile = DefaultGTiffProfile(count=1)
773
804
 
774
805
  # saving infos
775
806
  # disp grids
807
+
776
808
  if self.save_intermediate_data:
777
- safe_makedirs(pair_folder)
778
809
  grid_min_path = os.path.join(pair_folder, "disp_min_grid.tif")
779
- grid_orchestrator.add_to_save_lists(
780
- grid_min_path,
781
- dm_cst.DISP_MIN_GRID,
782
- grid_disp_range,
783
- dtype=np.float32,
784
- cars_ds_name="disp_min_grid",
785
- )
786
810
  grid_max_path = os.path.join(pair_folder, "disp_max_grid.tif")
787
- grid_orchestrator.add_to_save_lists(
788
- grid_max_path,
789
- dm_cst.DISP_MAX_GRID,
790
- grid_disp_range,
791
- dtype=np.float32,
792
- cars_ds_name="disp_max_grid",
793
- )
811
+ safe_makedirs(pair_folder)
812
+ else:
813
+ if pair_folder is None:
814
+ tmp_folder = os.path.join(self.orchestrator.out_dir, "tmp")
815
+ else:
816
+ tmp_folder = os.path.join(pair_folder, "tmp")
817
+ safe_makedirs(tmp_folder)
818
+ self.orchestrator.add_to_clean(tmp_folder)
819
+ grid_min_path = os.path.join(tmp_folder, "disp_min_grid.tif")
820
+ grid_max_path = os.path.join(tmp_folder, "disp_max_grid.tif")
794
821
 
795
822
  if None not in (dmin, dmax):
796
823
  # use global disparity range
@@ -800,446 +827,169 @@ class CensusMccnnSgm(
800
827
  ):
801
828
  raise RuntimeError("Mix between local and global mode")
802
829
 
803
- grid_min[:, :] = dmin
804
- grid_max[:, :] = dmax
830
+ # Only one tile
831
+ grid_disp_range.tiling_grid = np.array([[[0, nb_rows, 0, nb_cols]]])
805
832
 
806
833
  elif None not in (dem_min, dem_max, dem_median) or None not in (
807
834
  altitude_delta_min,
808
835
  altitude_delta_max,
809
836
  ):
810
- # use local disparity
811
-
812
- # Get associated alti mean / min / max values
813
- dem_median_shape = inputs.rasterio_get_size(dem_median)
814
- dem_median_width, dem_median_height = dem_median_shape
815
-
816
- min_row = 0
817
- min_col = 0
818
- max_row = dem_median_height
819
- max_col = dem_median_width
820
-
821
- # get epsg
822
- terrain_epsg = inputs.rasterio_get_epsg(dem_median)
823
-
824
- # Get epipolar position of all dem mean
825
- transform = inputs.rasterio_get_transform(dem_median)
826
-
827
- if None not in (dem_min, dem_max, dem_median):
828
- dem_min_shape = inputs.rasterio_get_size(dem_min)
829
- dem_epsg = inputs.rasterio_get_epsg(dem_min)
830
-
831
- if dem_median_shape != dem_min_shape:
832
- # dem min max are the same shape
833
- # dem median is not , hence we crop it
834
-
835
- # get terrain bounds dem min
836
- dem_min_bounds = inputs.rasterio_get_bounds(dem_min)
837
-
838
- # find roi in dem_mean
839
- roi_points = np.array(
840
- [
841
- [dem_min_bounds[0], dem_min_bounds[1]],
842
- [dem_min_bounds[0], dem_min_bounds[3]],
843
- [dem_min_bounds[2], dem_min_bounds[1]],
844
- [dem_min_bounds[2], dem_min_bounds[3]],
845
- ]
846
- )
847
-
848
- # Transform points to terrain_epsg (dem min is in 4326)
849
- roi_points_terrain = point_cloud_conversion(
850
- roi_points,
851
- dem_epsg,
852
- terrain_epsg,
853
- )
854
837
 
855
- # Get pixel roi in dem mean
856
- pixel_roi_dem_mean = inputs.rasterio_get_pixel_points(
857
- dem_median, roi_points_terrain
858
- )
859
- roi_lower_row = np.floor(np.min(pixel_roi_dem_mean[:, 0]))
860
- roi_upper_row = np.ceil(np.max(pixel_roi_dem_mean[:, 0]))
861
- roi_lower_col = np.floor(np.min(pixel_roi_dem_mean[:, 1]))
862
- roi_upper_col = np.ceil(np.max(pixel_roi_dem_mean[:, 1]))
863
-
864
- min_row = int(max(0, roi_lower_row))
865
- max_row = int(
866
- min(
867
- dem_median_height, # number of rows
868
- roi_upper_row,
869
- )
870
- )
871
- min_col = int(max(0, roi_lower_col))
872
- max_col = int(
873
- min(
874
- dem_median_width, # number of columns
875
- roi_upper_col,
876
- )
877
- )
838
+ # Generate multiple tiles
839
+ grid_tile_size = self.epi_disp_grid_tile_size
840
+ grid_disp_range.tiling_grid = tiling.generate_tiling_grid(
841
+ 0,
842
+ 0,
843
+ nb_rows,
844
+ nb_cols,
845
+ grid_tile_size,
846
+ grid_tile_size,
847
+ )
878
848
 
879
- elif (
880
- None not in (altitude_delta_min, altitude_delta_max)
881
- and geom_plugin_with_dem_and_geoid.plugin_name
882
- == "SharelocGeometry"
883
- ):
884
- roi_points_terrain = np.array(
885
- [
886
- [
887
- geom_plugin_with_dem_and_geoid.roi_shareloc[1],
888
- geom_plugin_with_dem_and_geoid.roi_shareloc[0],
889
- ],
890
- [
891
- geom_plugin_with_dem_and_geoid.roi_shareloc[1],
892
- geom_plugin_with_dem_and_geoid.roi_shareloc[2],
893
- ],
894
- [
895
- geom_plugin_with_dem_and_geoid.roi_shareloc[3],
896
- geom_plugin_with_dem_and_geoid.roi_shareloc[0],
897
- ],
898
- [
899
- geom_plugin_with_dem_and_geoid.roi_shareloc[3],
900
- geom_plugin_with_dem_and_geoid.roi_shareloc[2],
901
- ],
902
- ]
903
- )
849
+ # add tiling of global_infos_cars_ds
850
+ global_infos_cars_ds.tiling_grid = grid_disp_range.tiling_grid
851
+ self.orchestrator.add_to_replace_lists(
852
+ global_infos_cars_ds,
853
+ cars_ds_name="global infos",
854
+ )
904
855
 
905
- pixel_roi_dem_mean = inputs.rasterio_get_pixel_points(
906
- dem_median, roi_points_terrain
907
- )
856
+ self.orchestrator.add_to_save_lists(
857
+ grid_min_path,
858
+ dm_cst.DISP_MIN_GRID,
859
+ grid_disp_range,
860
+ dtype=np.float32,
861
+ nodata=0,
862
+ cars_ds_name="disp_min_grid",
863
+ )
908
864
 
909
- roi_lower_row = np.floor(np.min(pixel_roi_dem_mean[:, 0]))
910
- roi_upper_row = np.ceil(np.max(pixel_roi_dem_mean[:, 0]))
911
- roi_lower_col = np.floor(np.min(pixel_roi_dem_mean[:, 1]))
912
- roi_upper_col = np.ceil(np.max(pixel_roi_dem_mean[:, 1]))
865
+ self.orchestrator.add_to_save_lists(
866
+ grid_max_path,
867
+ dm_cst.DISP_MAX_GRID,
868
+ grid_disp_range,
869
+ dtype=np.float32,
870
+ nodata=0,
871
+ cars_ds_name="disp_max_grid",
872
+ )
873
+ [saving_info] = ( # pylint: disable=unbalanced-tuple-unpacking
874
+ self.orchestrator.get_saving_infos([grid_disp_range])
875
+ )
876
+ [saving_info_global_infos] = self.orchestrator.get_saving_infos(
877
+ [global_infos_cars_ds]
878
+ )
913
879
 
914
- min_row = int(max(0, roi_lower_row))
915
- max_row = int(min(dem_median_height, roi_upper_row))
916
- min_col = int(max(0, roi_lower_col))
917
- max_col = int(min(dem_median_width, roi_upper_col))
880
+ # Generate grids on dict format
881
+ grid_disp_range_dict = {
882
+ "grid_min_path": grid_min_path,
883
+ "grid_max_path": grid_max_path,
884
+ "global_min": None,
885
+ "global_max": None,
886
+ "step_row": step_row,
887
+ "step_col": step_col,
888
+ "row_range": row_range,
889
+ "col_range": col_range,
890
+ }
918
891
 
919
- # compute terrain positions to use (all dem min and max)
920
- row_indexes = range(min_row, max_row)
921
- col_indexes = range(min_col, max_col)
922
- transformer = rasterio.transform.AffineTransformer(transform)
892
+ if None not in (dmin, dmax):
893
+ # use global disparity range
894
+ if None not in (dem_min, dem_max) or None not in (
895
+ altitude_delta_min,
896
+ altitude_delta_max,
897
+ ):
898
+ raise RuntimeError("Mix between local and global mode")
923
899
 
924
- indexes = np.array(
925
- list(itertools.product(row_indexes, col_indexes))
900
+ saving_info_global_infos_full = ocht.update_saving_infos(
901
+ saving_info_global_infos, row=0, col=0
926
902
  )
927
-
928
- row = indexes[:, 0]
929
- col = indexes[:, 1]
930
- terrain_positions = []
931
- x_mean, y_mean = transformer.xy(row, col)
932
- terrain_positions = np.transpose(np.array([x_mean, y_mean]))
933
-
934
- # dem mean in terrain_epsg
935
- x_mean = terrain_positions[:, 0]
936
- y_mean = terrain_positions[:, 1]
937
-
938
- dem_median_list = inputs.rasterio_get_values(
939
- dem_median, x_mean, y_mean, point_cloud_conversion
903
+ saving_info_full = ocht.update_saving_infos(
904
+ saving_info, row=0, col=0
940
905
  )
941
906
 
942
- nan_mask = ~np.isnan(dem_median_list)
943
-
944
- # transform to lon lat
945
- terrain_position_lon_lat = projection.point_cloud_conversion(
946
- terrain_positions, terrain_epsg, 4326
907
+ (
908
+ grid_disp_range[0, 0],
909
+ global_infos_cars_ds[0, 0],
910
+ ) = self.orchestrator.cluster.create_task(
911
+ generate_disp_range_const_tile_wrapper, nout=2
912
+ )(
913
+ row_range,
914
+ col_range,
915
+ dmin,
916
+ dmax,
917
+ raster_profile,
918
+ saving_info_full,
919
+ saving_info_global_infos_full,
947
920
  )
948
- lon_mean = terrain_position_lon_lat[:, 0]
949
- lat_mean = terrain_position_lon_lat[:, 1]
950
921
 
951
- if None not in (dem_min, dem_max, dem_median):
952
- # dem min and max are in 4326
953
- dem_min_list = inputs.rasterio_get_values(
954
- dem_min, lon_mean, lat_mean, point_cloud_conversion
955
- )
956
- dem_max_list = inputs.rasterio_get_values(
957
- dem_max, lon_mean, lat_mean, point_cloud_conversion
958
- )
959
- nan_mask = (
960
- nan_mask & ~np.isnan(dem_min_list) & ~np.isnan(dem_max_list)
961
- )
962
- else:
963
- dem_min_list = dem_median_list - altitude_delta_min
964
- dem_max_list = dem_median_list + altitude_delta_max
965
-
966
- # filter nan value from input points
967
- lon_mean = lon_mean[nan_mask]
968
- lat_mean = lat_mean[nan_mask]
969
- dem_median_list = dem_median_list[nan_mask]
970
- dem_min_list = dem_min_list[nan_mask]
971
- dem_max_list = dem_max_list[nan_mask]
972
-
973
- # if shareloc is used, perform inverse locs sequentially
974
- if geom_plugin_with_dem_and_geoid.plugin_name == "SharelocGeometry":
975
-
976
- # sensors physical positions
977
- (
978
- ind_cols_sensor,
979
- ind_rows_sensor,
980
- _,
981
- ) = geom_plugin_with_dem_and_geoid.inverse_loc(
982
- sensor_image_right["image"]["main_file"],
983
- sensor_image_right["geomodel"],
984
- lat_mean,
985
- lon_mean,
986
- z_coord=dem_median_list,
987
- )
988
-
989
- # else (if libgeo is used) perform inverse locs in parallel
990
- else:
991
-
992
- num_points = len(dem_median_list)
993
-
994
- if loc_inverse_orchestrator is None:
995
- loc_inverse_orchestrator = grid_orchestrator
996
-
997
- num_workers = loc_inverse_orchestrator.get_conf().get(
998
- "nb_workers", 1
999
- )
1000
-
1001
- loc_inverse_dataset = cars_dataset.CarsDataset(
1002
- "points", name="loc_inverse"
1003
- )
1004
- step = int(np.ceil(num_points / num_workers))
1005
- # Create a grid with num_workers elements
1006
- loc_inverse_dataset.create_grid(1, num_workers, 1, 1, 0, 0)
922
+ elif None not in (dem_min, dem_max, dem_median) or None not in (
923
+ altitude_delta_min,
924
+ altitude_delta_max,
925
+ ):
1007
926
 
1008
- # Get saving info in order to save tiles when they are computed
1009
- [saving_info] = loc_inverse_orchestrator.get_saving_infos(
1010
- [loc_inverse_dataset]
927
+ # use filter to propagate min and max
928
+ filter_overlap = (
929
+ 2
930
+ * int(
931
+ self.disp_range_propagation_filter_size
932
+ / self.local_disp_grid_step
1011
933
  )
934
+ + 1
935
+ )
1012
936
 
1013
- for task_id in range(0, num_workers):
1014
- first_elem = task_id * step
1015
- last_elem = min((task_id + 1) * step, num_points)
937
+ for col in range(grid_disp_range.shape[1]):
938
+ for row in range(grid_disp_range.shape[0]):
939
+ # update saving infos for potential replacement
1016
940
  full_saving_info = ocht.update_saving_infos(
1017
- saving_info, row=task_id, col=0
941
+ saving_info, row=row, col=col
942
+ )
943
+ saving_info_global_infos_full = ocht.update_saving_infos(
944
+ saving_info_global_infos, row=row, col=col
1018
945
  )
1019
- loc_inverse_dataset[
1020
- task_id, 0
1021
- ] = loc_inverse_orchestrator.cluster.create_task(
1022
- loc_inverse_wrapper
946
+ array_window = grid_disp_range.get_window_as_dict(row, col)
947
+ (
948
+ grid_disp_range[row, col],
949
+ global_infos_cars_ds[row, col],
950
+ ) = self.orchestrator.cluster.create_task(
951
+ generate_disp_range_from_dem_wrapper, nout=2
1023
952
  )(
953
+ array_window,
954
+ row_range,
955
+ col_range,
956
+ sensor_image_right,
957
+ grid_right,
1024
958
  geom_plugin_with_dem_and_geoid,
1025
- sensor_image_right["image"]["main_file"],
1026
- sensor_image_right["geomodel"],
1027
- lat_mean[first_elem:last_elem],
1028
- lon_mean[first_elem:last_elem],
1029
- dem_median_list[first_elem:last_elem],
959
+ dem_median,
960
+ dem_min,
961
+ dem_max,
962
+ altitude_delta_min,
963
+ altitude_delta_max,
964
+ raster_profile,
1030
965
  full_saving_info,
966
+ saving_info_global_infos_full,
967
+ filter_overlap,
968
+ disp_to_alt_ratio,
969
+ disp_min_threshold=self.disp_min_threshold,
970
+ disp_max_threshold=self.disp_max_threshold,
1031
971
  )
1032
972
 
1033
- loc_inverse_orchestrator.add_to_replace_lists(
1034
- loc_inverse_dataset
1035
- )
1036
-
1037
- loc_inverse_orchestrator.compute_futures(
1038
- only_remaining_delayed=[
1039
- tile[0] for tile in loc_inverse_dataset.tiles
1040
- ]
1041
- )
1042
-
1043
- ind_cols_sensor = []
1044
- ind_rows_sensor = []
1045
-
1046
- for tile in loc_inverse_dataset.tiles:
1047
- ind_cols_sensor += list(tile[0]["col"])
1048
- ind_rows_sensor += list(tile[0]["row"])
1049
-
1050
- # Generate epipolar disp grids
1051
- # Get epipolar positions
1052
- (epipolar_positions_row, epipolar_positions_col) = np.meshgrid(
1053
- col_range, row_range
1054
- )
1055
- epipolar_positions = np.stack(
1056
- [epipolar_positions_row, epipolar_positions_col], axis=2
1057
- )
1058
-
1059
- # Get sensor position
1060
- sensors_positions = (
1061
- geom_plugin_with_dem_and_geoid.sensor_position_from_grid(
1062
- grid_right,
1063
- np.reshape(
1064
- epipolar_positions,
1065
- (
1066
- epipolar_positions.shape[0]
1067
- * epipolar_positions.shape[1],
1068
- 2,
1069
- ),
1070
- ),
1071
- )
1072
- )
1073
-
1074
- # compute reverse matrix
1075
- transform_sensor = rasterio.Affine(
1076
- *np.abs(
1077
- inputs.rasterio_get_transform(
1078
- sensor_image_right["image"]["main_file"]
1079
- )
1080
- )
1081
- )
1082
-
1083
- trans_inv = ~transform_sensor
1084
- # Transform to positive values
1085
- trans_inv = np.array(trans_inv)
1086
- trans_inv = np.reshape(trans_inv, (3, 3))
1087
- if trans_inv[0, 0] < 0:
1088
- trans_inv[0, :] *= -1
1089
- if trans_inv[1, 1] < 0:
1090
- trans_inv[1, :] *= -1
1091
- trans_inv = affine.Affine(*list(trans_inv.flatten()))
1092
-
1093
- # Transform physical position to index
1094
- index_positions = np.empty(sensors_positions.shape)
1095
- for row_point in range(index_positions.shape[0]):
1096
- row_geo, col_geo = sensors_positions[row_point, :]
1097
- col, row = trans_inv * (row_geo, col_geo)
1098
- index_positions[row_point, :] = (row, col)
1099
-
1100
- ind_rows_sensor_grid = index_positions[:, 0] - 0.5
1101
- ind_cols_sensor_grid = index_positions[:, 1] - 0.5
1102
-
1103
- # Interpolate disparity
1104
- disp_min_points = (
1105
- -(dem_max_list - dem_median_list) / disp_to_alt_ratio
1106
- )
1107
- disp_max_points = (
1108
- -(dem_min_list - dem_median_list) / disp_to_alt_ratio
1109
- )
1110
-
1111
- interp_min_linear = LinearInterpNearestExtrap(
1112
- list(zip(ind_rows_sensor, ind_cols_sensor)), # noqa: B905
1113
- disp_min_points,
1114
- )
1115
- interp_max_linear = LinearInterpNearestExtrap(
1116
- list(zip(ind_rows_sensor, ind_cols_sensor)), # noqa: B905
1117
- disp_max_points,
1118
- )
1119
-
1120
- grid_min = np.reshape(
1121
- interp_min_linear(ind_rows_sensor_grid, ind_cols_sensor_grid),
1122
- (
1123
- epipolar_positions.shape[0],
1124
- epipolar_positions.shape[1],
1125
- ),
1126
- )
1127
-
1128
- grid_max = np.reshape(
1129
- interp_max_linear(ind_rows_sensor_grid, ind_cols_sensor_grid),
1130
- (
1131
- epipolar_positions.shape[0],
1132
- epipolar_positions.shape[1],
1133
- ),
1134
- )
1135
-
1136
- else:
1137
- raise RuntimeError(
1138
- "Not a global or local mode for disparity range estimation"
1139
- )
1140
-
1141
- # Add margin
1142
- diff = grid_max - grid_min
1143
- logging.info("Max grid max - grid min : {} disp ".format(np.max(diff)))
1144
-
1145
- if self.disp_min_threshold is not None:
1146
- if np.any(grid_min < self.disp_min_threshold):
1147
- logging.warning(
1148
- "Override disp_min with disp_min_threshold {}".format(
1149
- self.disp_min_threshold
1150
- )
1151
- )
1152
- grid_min[grid_min < self.disp_min_threshold] = (
1153
- self.disp_min_threshold
1154
- )
1155
- if self.disp_max_threshold is not None:
1156
- if np.any(grid_max > self.disp_max_threshold):
1157
- logging.warning(
1158
- "Override disp_max with disp_max_threshold {}".format(
1159
- self.disp_max_threshold
973
+ # Compute grid
974
+ self.orchestrator.breakpoint()
975
+
976
+ # Fill global infos
977
+ mins, maxs = [], []
978
+ for row in range(global_infos_cars_ds.shape[0]):
979
+ for col in range(global_infos_cars_ds.shape[1]):
980
+ try:
981
+ dict_data = global_infos_cars_ds[row, col].data
982
+ mins.append(dict_data["global_min"])
983
+ maxs.append(dict_data["global_max"])
984
+ except Exception:
985
+ logging.info(
986
+ "Tile {} {} not computed in epi disp range"
987
+ " generation".format(row, col)
1160
988
  )
1161
- )
1162
- grid_max[grid_max > self.disp_max_threshold] = (
1163
- self.disp_max_threshold
1164
- )
1165
-
1166
- # use filter to propagate min and max
1167
- overlap = (
1168
- 2
1169
- * int(
1170
- self.disp_range_propagation_filter_size
1171
- / self.local_disp_grid_step
1172
- )
1173
- + 1
1174
- )
1175
-
1176
- grid_min = generic_filter(
1177
- grid_min, np.min, [overlap, overlap], mode="nearest"
1178
- )
1179
- grid_max = generic_filter(
1180
- grid_max, np.max, [overlap, overlap], mode="nearest"
1181
- )
1182
-
1183
- # Generate dataset
1184
- # min and max are reversed
1185
- disp_range_tile = xr.Dataset(
1186
- data_vars={
1187
- dm_cst.DISP_MIN_GRID: (["row", "col"], grid_min),
1188
- dm_cst.DISP_MAX_GRID: (["row", "col"], grid_max),
1189
- },
1190
- coords={
1191
- "row": np.arange(0, grid_min.shape[0]),
1192
- "col": np.arange(0, grid_min.shape[1]),
1193
- },
1194
- )
1195
-
1196
- # Save
1197
- [saving_info] = ( # pylint: disable=unbalanced-tuple-unpacking
1198
- grid_orchestrator.get_saving_infos([grid_disp_range])
1199
- )
1200
- saving_info = ocht.update_saving_infos(saving_info, row=0, col=0)
1201
- # Generate profile
1202
- # Generate profile
1203
- geotransform = (
1204
- epi_size_row,
1205
- step_row,
1206
- 0.0,
1207
- epi_size_col,
1208
- 0.0,
1209
- step_col,
1210
- )
1211
-
1212
- transform = Affine.from_gdal(*geotransform)
1213
- raster_profile = collections.OrderedDict(
1214
- {
1215
- "height": nb_rows,
1216
- "width": nb_cols,
1217
- "driver": "GTiff",
1218
- "dtype": "float32",
1219
- "transform": transform,
1220
- "tiled": True,
1221
- }
1222
- )
1223
- cars_dataset.fill_dataset(
1224
- disp_range_tile,
1225
- saving_info=saving_info,
1226
- window=None,
1227
- profile=raster_profile,
1228
- attributes=None,
1229
- overlaps=None,
1230
- )
1231
- grid_disp_range[0, 0] = disp_range_tile
989
+ grid_disp_range_dict["global_min"] = np.floor(np.nanmin(mins))
990
+ grid_disp_range_dict["global_max"] = np.ceil(np.nanmax(maxs))
1232
991
 
1233
- if self.save_intermediate_data:
1234
- grid_orchestrator.breakpoint()
1235
-
1236
- if np.any(diff < 0):
1237
- logging.error("grid min > grid max in {}".format(pair_folder))
1238
- raise RuntimeError("grid min > grid max in {}".format(pair_folder))
1239
-
1240
- # cleanup
1241
- grid_orchestrator.cleanup()
1242
- return grid_disp_range
992
+ return grid_disp_range_dict
1243
993
 
1244
994
  def run(
1245
995
  self,
@@ -1435,16 +1185,8 @@ class CensusMccnnSgm(
1435
1185
  application_constants.APPLICATION_TAG: {
1436
1186
  dm_cst.DENSE_MATCHING_RUN_TAG: {
1437
1187
  pair_key: {
1438
- "global_disp_min": np.nanmin(
1439
- disp_range_grid[0, 0][
1440
- dm_cst.DISP_MIN_GRID
1441
- ].values
1442
- ),
1443
- "global_disp_max": np.nanmax(
1444
- disp_range_grid[0, 0][
1445
- dm_cst.DISP_MAX_GRID
1446
- ].values
1447
- ),
1188
+ "global_disp_min": disp_range_grid["global_min"],
1189
+ "global_disp_max": disp_range_grid["global_max"],
1448
1190
  },
1449
1191
  },
1450
1192
  }
@@ -1521,6 +1263,9 @@ class CensusMccnnSgm(
1521
1263
  ),
1522
1264
  texture_bands=texture_bands,
1523
1265
  conf_filtering=self.confidence_filtering,
1266
+ threshold_disp_range_to_borders=(
1267
+ self.threshold_disp_range_to_borders
1268
+ ),
1524
1269
  )
1525
1270
 
1526
1271
  else:
@@ -1545,6 +1290,7 @@ def compute_disparity_wrapper(
1545
1290
  classification_fusion_margin=-1,
1546
1291
  texture_bands=None,
1547
1292
  conf_filtering=None,
1293
+ threshold_disp_range_to_borders=False,
1548
1294
  ) -> Dict[str, Tuple[xr.Dataset, xr.Dataset]]:
1549
1295
  """
1550
1296
  Compute disparity maps from image objects.
@@ -1604,15 +1350,17 @@ def compute_disparity_wrapper(
1604
1350
  (
1605
1351
  disp_min_grid,
1606
1352
  disp_max_grid,
1607
- ) = dm_algo.compute_disparity_grid(disp_range_grid, left_image_object)
1608
-
1609
- global_disp_min = np.floor(
1610
- np.nanmin(disp_range_grid[0, 0]["disp_min_grid"].data)
1611
- )
1612
- global_disp_max = np.ceil(
1613
- np.nanmax(disp_range_grid[0, 0]["disp_max_grid"].data)
1353
+ ) = dm_algo.compute_disparity_grid(
1354
+ disp_range_grid,
1355
+ left_image_object,
1356
+ right_image_object,
1357
+ used_band,
1358
+ threshold_disp_range_to_borders,
1614
1359
  )
1615
1360
 
1361
+ global_disp_min = disp_range_grid["global_min"]
1362
+ global_disp_max = disp_range_grid["global_max"]
1363
+
1616
1364
  # add global disparity in case of ambiguity normalization
1617
1365
  left_image_object = add_global_disparity(
1618
1366
  left_image_object, global_disp_min, global_disp_max
@@ -1664,7 +1412,9 @@ def compute_disparity_wrapper(
1664
1412
 
1665
1413
  # Filtering by using the confidence
1666
1414
  requested_confidence = [
1415
+ "confidence_from_risk_min.cars_2",
1667
1416
  "confidence_from_risk_max.cars_2",
1417
+ "confidence_from_interval_bounds_inf.cars_3",
1668
1418
  "confidence_from_interval_bounds_sup.cars_3",
1669
1419
  ]
1670
1420
 
@@ -1690,47 +1440,3 @@ def compute_disparity_wrapper(
1690
1440
  )
1691
1441
 
1692
1442
  return disp_dataset
1693
-
1694
-
1695
- def loc_inverse_wrapper(
1696
- geom_plugin,
1697
- image,
1698
- geomodel,
1699
- latitudes,
1700
- longitudes,
1701
- altitudes,
1702
- saving_info=None,
1703
- ) -> pandas.DataFrame:
1704
- """
1705
- Perform inverse localizations on input coordinates
1706
- This function will be run as a delayed task.
1707
-
1708
- :param geom_plugin: geometry plugin used to perform localizations
1709
- :type geom_plugin: SharelocGeometry
1710
- :param image: input image path
1711
- :type image: str
1712
- :param geomodel: input geometric model
1713
- :type geomodel: str
1714
- :param latitudes: input latitude coordinates
1715
- :type latitudes: np.array
1716
- :param longitudes: input longitudes coordinates
1717
- :type longitudes: np.array
1718
- :param altitudes: input latitude coordinates
1719
- :type altitudes: np.array
1720
- :param saving_info: saving info for cars orchestrator
1721
- :type saving_info: dict
1722
-
1723
- """
1724
- col, row, _ = geom_plugin.inverse_loc(
1725
- image,
1726
- geomodel,
1727
- latitudes,
1728
- longitudes,
1729
- z_coord=altitudes,
1730
- )
1731
- output = pandas.DataFrame({"col": col, "row": row}, copy=False)
1732
- cars_dataset.fill_dataframe(
1733
- output, saving_info=saving_info, attributes=None
1734
- )
1735
-
1736
- return output