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.
- cars/__init__.py +4 -4
- cars/applications/application.py +14 -6
- cars/applications/application_template.py +22 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +15 -10
- 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_wrappers.py +48 -25
- cars/applications/dem_generation/dichotomic_generation_app.py +27 -9
- cars/applications/dem_generation/rasterization_app.py +85 -32
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +4 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp313-win_amd64.dll.a +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp313-win_amd64.pyd +0 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +41 -12
- cars/applications/dense_match_filling/plane_app.py +11 -0
- cars/applications/dense_match_filling/zero_padding_app.py +11 -1
- cars/applications/dense_matching/census_mccnn_sgm_app.py +254 -548
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp313-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp313-win_amd64.pyd +0 -0
- cars/applications/dense_matching/dense_matching_algo.py +59 -11
- cars/applications/dense_matching/dense_matching_wrappers.py +51 -31
- cars/applications/dense_matching/disparity_grid_algo.py +566 -0
- 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 +78 -1
- cars/applications/dsm_filling/border_interpolation_app.py +10 -5
- cars/applications/dsm_filling/bulldozer_filling_app.py +14 -7
- cars/applications/dsm_filling/exogenous_filling_app.py +10 -5
- cars/applications/grid_generation/grid_correction_app.py +0 -53
- cars/applications/grid_generation/transform_grid.py +5 -5
- cars/applications/point_cloud_fusion/pc_fusion_algo.py +17 -11
- cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +3 -4
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +9 -5
- cars/applications/point_cloud_outlier_removal/small_components_app.py +5 -3
- cars/applications/point_cloud_outlier_removal/statistical_app.py +4 -2
- cars/applications/rasterization/abstract_pc_rasterization_app.py +1 -0
- cars/applications/rasterization/rasterization_algo.py +20 -27
- cars/applications/rasterization/rasterization_wrappers.py +6 -5
- cars/applications/rasterization/simple_gaussian_app.py +30 -17
- cars/applications/resampling/resampling_algo.py +44 -49
- cars/applications/sparse_matching/sift_app.py +2 -22
- cars/applications/sparse_matching/sparse_matching_wrappers.py +0 -49
- cars/applications/triangulation/line_of_sight_intersection_app.py +1 -1
- cars/applications/triangulation/triangulation_wrappers.py +2 -1
- cars/bundleadjustment.py +51 -11
- cars/cars.py +15 -5
- cars/core/constants.py +1 -1
- cars/core/geometry/abstract_geometry.py +166 -12
- cars/core/geometry/shareloc_geometry.py +61 -14
- cars/core/inputs.py +15 -0
- cars/core/projection.py +117 -0
- cars/data_structures/cars_dataset.py +7 -5
- cars/orchestrator/cluster/log_wrapper.py +1 -1
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +1 -1
- cars/orchestrator/orchestrator.py +1 -1
- cars/orchestrator/registry/saver_registry.py +0 -78
- cars/pipelines/default/default_pipeline.py +69 -52
- cars/pipelines/parameters/advanced_parameters.py +17 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +4 -0
- cars/pipelines/parameters/depth_map_inputs.py +22 -67
- cars/pipelines/parameters/dsm_inputs.py +16 -29
- cars/pipelines/parameters/output_parameters.py +44 -8
- cars/pipelines/parameters/sensor_inputs.py +117 -24
- cars/pipelines/parameters/sensor_loaders/basic_sensor_loader.py +3 -3
- cars/pipelines/parameters/sensor_loaders/pivot_sensor_loader.py +2 -2
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +2 -2
- cars/pipelines/pipeline.py +8 -8
- cars/pipelines/unit/unit_pipeline.py +276 -274
- cars/starter.py +20 -1
- cars-1.0.0a3.dist-info/DELVEWHEEL +2 -0
- {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/METADATA +3 -2
- {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/RECORD +77 -74
- cars.libs/libgcc_s_seh-1-ca70890bbc5723b6d0ea31e9c9cded2b.dll +0 -0
- cars.libs/libstdc++-6-00ee19f73d5122a1277c137b1c218401.dll +0 -0
- cars.libs/libwinpthread-1-f5042e8e3d21edce20c1bc99445f551b.dll +0 -0
- cars-1.0.0a1.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.0a1.dist-info → cars-1.0.0a3.dist-info}/WHEEL +0 -0
- {cars-1.0.0a1.dist-info → cars-1.0.0a3.dist-info}/entry_points.txt +0 -0
|
@@ -208,6 +208,7 @@ class SimpleGaussian(
|
|
|
208
208
|
self,
|
|
209
209
|
point_clouds,
|
|
210
210
|
epsg,
|
|
211
|
+
output_crs,
|
|
211
212
|
resolution,
|
|
212
213
|
orchestrator=None,
|
|
213
214
|
dsm_file_name=None,
|
|
@@ -256,6 +257,8 @@ class SimpleGaussian(
|
|
|
256
257
|
:type point_clouds: CarsDataset filled with pandas.DataFrame
|
|
257
258
|
:param epsg: epsg of raster data
|
|
258
259
|
:type epsg: str
|
|
260
|
+
:param output_crs: output_crs of raster data
|
|
261
|
+
:type output_crs: str
|
|
259
262
|
:param resolution: resolution of raster data (in target CRS unit)
|
|
260
263
|
:type resolution: float
|
|
261
264
|
:param orchestrator: orchestrator used
|
|
@@ -267,7 +270,7 @@ class SimpleGaussian(
|
|
|
267
270
|
:type color_file_name: str
|
|
268
271
|
:param mask_file_name: path of color
|
|
269
272
|
:type mask_file_name: str
|
|
270
|
-
:param classif_file_name: path of
|
|
273
|
+
:param classif_file_name: path of classification
|
|
271
274
|
:type classif_file_name: str
|
|
272
275
|
:param performance_map_file_name: path of performance map file
|
|
273
276
|
:type performance_map_file_name: str
|
|
@@ -317,6 +320,27 @@ class SimpleGaussian(
|
|
|
317
320
|
# Get if color, mask and stats are saved
|
|
318
321
|
save_intermediate_data = self.used_config["save_intermediate_data"]
|
|
319
322
|
|
|
323
|
+
keep_dir = (
|
|
324
|
+
len(
|
|
325
|
+
list(
|
|
326
|
+
filter(
|
|
327
|
+
lambda x: x is not None,
|
|
328
|
+
[
|
|
329
|
+
weights_file_name,
|
|
330
|
+
color_file_name,
|
|
331
|
+
mask_file_name,
|
|
332
|
+
classif_file_name,
|
|
333
|
+
performance_map_file_name,
|
|
334
|
+
ambiguity_file_name,
|
|
335
|
+
contributing_pair_file_name,
|
|
336
|
+
filling_file_name,
|
|
337
|
+
],
|
|
338
|
+
)
|
|
339
|
+
)
|
|
340
|
+
)
|
|
341
|
+
> 0
|
|
342
|
+
)
|
|
343
|
+
|
|
320
344
|
if not self.color_dtype:
|
|
321
345
|
self.color_dtype = color_dtype
|
|
322
346
|
|
|
@@ -333,7 +357,7 @@ class SimpleGaussian(
|
|
|
333
357
|
if dump_dir is not None:
|
|
334
358
|
out_dump_dir = dump_dir
|
|
335
359
|
safe_makedirs(dump_dir)
|
|
336
|
-
if not save_intermediate_data:
|
|
360
|
+
if not save_intermediate_data and not keep_dir:
|
|
337
361
|
self.orchestrator.add_to_clean(dump_dir)
|
|
338
362
|
else:
|
|
339
363
|
out_dump_dir = self.orchestrator.out_dir
|
|
@@ -512,6 +536,7 @@ class SimpleGaussian(
|
|
|
512
536
|
out_classif_file_name = os.path.join(
|
|
513
537
|
out_dump_dir, "classification.tif"
|
|
514
538
|
)
|
|
539
|
+
|
|
515
540
|
if out_classif_file_name is not None:
|
|
516
541
|
list_computed_layers += ["classif"]
|
|
517
542
|
self.orchestrator.add_to_save_lists(
|
|
@@ -644,7 +669,7 @@ class SimpleGaussian(
|
|
|
644
669
|
)
|
|
645
670
|
elif save_intermediate_data:
|
|
646
671
|
# File is not part of the official product, write it in dump_dir
|
|
647
|
-
out_source_pc = os.path.join(out_dump_dir, "
|
|
672
|
+
out_source_pc = os.path.join(out_dump_dir, "contributing_pair.tif")
|
|
648
673
|
if out_source_pc:
|
|
649
674
|
list_computed_layers += ["source_pc"]
|
|
650
675
|
self.orchestrator.add_to_save_lists(
|
|
@@ -653,7 +678,7 @@ class SimpleGaussian(
|
|
|
653
678
|
terrain_raster,
|
|
654
679
|
dtype=np.uint8,
|
|
655
680
|
nodata=self.msk_no_data,
|
|
656
|
-
cars_ds_name="
|
|
681
|
+
cars_ds_name="contributing_pair",
|
|
657
682
|
optional_data=True,
|
|
658
683
|
)
|
|
659
684
|
|
|
@@ -680,18 +705,6 @@ class SimpleGaussian(
|
|
|
680
705
|
|
|
681
706
|
# TODO Check that intervals indeed exist!
|
|
682
707
|
if save_intermediate_data:
|
|
683
|
-
out_confidence = os.path.join(out_dump_dir, "confidence.tif")
|
|
684
|
-
list_computed_layers += ["confidence"]
|
|
685
|
-
self.orchestrator.add_to_save_lists(
|
|
686
|
-
out_confidence,
|
|
687
|
-
cst.RASTER_CONFIDENCE,
|
|
688
|
-
terrain_raster,
|
|
689
|
-
dtype=np.float32,
|
|
690
|
-
nodata=self.msk_no_data,
|
|
691
|
-
cars_ds_name="confidence",
|
|
692
|
-
optional_data=True,
|
|
693
|
-
)
|
|
694
|
-
|
|
695
708
|
list_computed_layers += [cst.POINT_CLOUD_LAYER_SUP_OR_INF_ROOT]
|
|
696
709
|
out_dsm_inf_file_name = os.path.join(out_dump_dir, "dsm_inf.tif")
|
|
697
710
|
self.orchestrator.add_to_save_lists(
|
|
@@ -829,7 +842,7 @@ class SimpleGaussian(
|
|
|
829
842
|
"driver": "GTiff",
|
|
830
843
|
"dtype": "float32",
|
|
831
844
|
"transform": transform,
|
|
832
|
-
"crs":
|
|
845
|
+
"crs": output_crs.to_wkt(),
|
|
833
846
|
"tiled": True,
|
|
834
847
|
}
|
|
835
848
|
)
|
|
@@ -284,14 +284,10 @@ def resample_image( # noqa: C901
|
|
|
284
284
|
(nb_bands, region[3] - region[1], region[2] - region[0]),
|
|
285
285
|
dtype=np.float32,
|
|
286
286
|
)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
dtype=np.float32,
|
|
292
|
-
)
|
|
293
|
-
else:
|
|
294
|
-
msk = None
|
|
287
|
+
msk = np.empty(
|
|
288
|
+
(nb_bands, region[3] - region[1], region[2] - region[0]),
|
|
289
|
+
dtype=np.float32,
|
|
290
|
+
)
|
|
295
291
|
|
|
296
292
|
ystart = 0
|
|
297
293
|
with rio.open(grid["path"]) as grid_reader, rio.open(img) as img_reader:
|
|
@@ -513,51 +509,50 @@ def oversampling_func(
|
|
|
513
509
|
resamp[:, ystart : ystart + ysize, xstart : xstart + xsize] = block_resamp
|
|
514
510
|
|
|
515
511
|
# create msk
|
|
516
|
-
if
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
msk_as_array = np.array([msk_as_array] * img_as_array.shape[0])
|
|
525
|
-
else:
|
|
526
|
-
msk_as_array = np.zeros(img_as_array.shape)
|
|
512
|
+
if in_sensor:
|
|
513
|
+
# get mask in source geometry
|
|
514
|
+
if mask is not None:
|
|
515
|
+
with rio.open(mask) as msk_reader:
|
|
516
|
+
msk_as_array = msk_reader.read(1, window=img_window)
|
|
517
|
+
msk_as_array = np.array([msk_as_array] * img_as_array.shape[0])
|
|
518
|
+
else:
|
|
519
|
+
msk_as_array = np.zeros(img_as_array.shape)
|
|
527
520
|
|
|
521
|
+
if nodata is not None:
|
|
522
|
+
nodata_index = img_as_array == nodata
|
|
528
523
|
msk_as_array[nodata_index] = nodata_msk
|
|
529
524
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
525
|
+
# resample mask
|
|
526
|
+
block_msk = cresample.grid(
|
|
527
|
+
msk_as_array,
|
|
528
|
+
grid_as_array,
|
|
529
|
+
oversampling,
|
|
530
|
+
interpolator=interpolator_mask,
|
|
531
|
+
nodata=nodata_msk,
|
|
532
|
+
)
|
|
538
533
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
534
|
+
if interpolator_mask == "bicubic":
|
|
535
|
+
block_msk = np.where(
|
|
536
|
+
block_msk >= 0.5,
|
|
537
|
+
1,
|
|
538
|
+
np.where(block_msk < 0.5, 0, block_msk),
|
|
539
|
+
).astype(int)
|
|
540
|
+
|
|
541
|
+
block_msk = block_msk[
|
|
542
|
+
...,
|
|
543
|
+
ext_region[1] : ext_region[3] - 1,
|
|
544
|
+
ext_region[0] : ext_region[2] - 1,
|
|
545
|
+
]
|
|
546
|
+
else:
|
|
547
|
+
block_msk = np.full(
|
|
548
|
+
(
|
|
549
|
+
nb_bands,
|
|
550
|
+
block_region[3] - block_region[1],
|
|
551
|
+
block_region[2] - block_region[0],
|
|
552
|
+
),
|
|
553
|
+
fill_value=nodata_msk,
|
|
554
|
+
)
|
|
560
555
|
|
|
561
|
-
|
|
556
|
+
msk[:, ystart : ystart + ysize, xstart : xstart + xsize] = block_msk
|
|
562
557
|
|
|
563
558
|
return resamp, msk
|
|
@@ -224,7 +224,7 @@ class Sift(SparseMatching, short_name=["sift"]):
|
|
|
224
224
|
"sift_matching_threshold": And(float, lambda x: x > 0),
|
|
225
225
|
"sift_n_octave": And(int, lambda x: x > 0),
|
|
226
226
|
"sift_n_scale_per_octave": And(int, lambda x: x > 0),
|
|
227
|
-
"sift_peak_threshold": Or(float,
|
|
227
|
+
"sift_peak_threshold": Or(float, int),
|
|
228
228
|
"sift_edge_threshold": float,
|
|
229
229
|
"sift_magnification": And(float, lambda x: x > 0),
|
|
230
230
|
"sift_window_size": And(int, lambda x: x > 0),
|
|
@@ -514,26 +514,6 @@ class Sift(SparseMatching, short_name=["sift"]):
|
|
|
514
514
|
epipolar_disparity_map_left.attributes.update(
|
|
515
515
|
epipolar_image_left.attributes
|
|
516
516
|
)
|
|
517
|
-
# check sift_peak_threshold with image type
|
|
518
|
-
# only if sift_peak_threshold is None
|
|
519
|
-
tmp_sift_peak_threshold = self.sift_peak_threshold
|
|
520
|
-
if not self.sift_peak_threshold:
|
|
521
|
-
logging.info("The sift_peak_threshold is set to auto-mode.")
|
|
522
|
-
# sift_peak_threshold is None or not specified
|
|
523
|
-
# check input type
|
|
524
|
-
if np.issubdtype(
|
|
525
|
-
epipolar_disparity_map_left.attributes["image_type"],
|
|
526
|
-
np.uint8,
|
|
527
|
-
):
|
|
528
|
-
tmp_sift_peak_threshold = 1
|
|
529
|
-
else:
|
|
530
|
-
tmp_sift_peak_threshold = 20
|
|
531
|
-
logging.info(
|
|
532
|
-
"The sift_peak_threshold will be set to {}.".format(
|
|
533
|
-
tmp_sift_peak_threshold
|
|
534
|
-
)
|
|
535
|
-
)
|
|
536
|
-
self.sift_peak_threshold = tmp_sift_peak_threshold
|
|
537
517
|
|
|
538
518
|
# Save disparity maps
|
|
539
519
|
if self.save_intermediate_data:
|
|
@@ -628,7 +608,7 @@ class Sift(SparseMatching, short_name=["sift"]):
|
|
|
628
608
|
matching_threshold=self.sift_matching_threshold,
|
|
629
609
|
n_octave=self.sift_n_octave,
|
|
630
610
|
n_scale_per_octave=self.sift_n_scale_per_octave,
|
|
631
|
-
peak_threshold=
|
|
611
|
+
peak_threshold=self.sift_peak_threshold,
|
|
632
612
|
edge_threshold=self.sift_edge_threshold,
|
|
633
613
|
magnification=self.sift_magnification,
|
|
634
614
|
window_size=self.sift_window_size,
|
|
@@ -170,55 +170,6 @@ def compute_disp_min_disp_max(
|
|
|
170
170
|
return dmin, dmax
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
@cars_profile(name="Clustering matches")
|
|
174
|
-
def clustering_matches(
|
|
175
|
-
triangulated_matches,
|
|
176
|
-
connection_val=3.0,
|
|
177
|
-
nb_pts_threshold=80,
|
|
178
|
-
clusters_distance_threshold: float = None,
|
|
179
|
-
filtered_elt_pos: bool = False,
|
|
180
|
-
):
|
|
181
|
-
"""
|
|
182
|
-
Filter triangulated matches
|
|
183
|
-
|
|
184
|
-
:param pd_cloud: triangulated_matches
|
|
185
|
-
:type pd_cloud: pandas Dataframe
|
|
186
|
-
:param connection_val: distance to use
|
|
187
|
-
to consider that two points are connected
|
|
188
|
-
:param nb_pts_threshold: number of points to use
|
|
189
|
-
to identify small clusters to filter
|
|
190
|
-
:param clusters_distance_threshold: distance to use
|
|
191
|
-
to consider if two points clusters are far from each other or not
|
|
192
|
-
(set to None to deactivate this level of filtering)
|
|
193
|
-
:param filtered_elt_pos: if filtered_elt_pos is set to True,
|
|
194
|
-
the removed points positions in their original
|
|
195
|
-
epipolar images are returned, otherwise it is set to None
|
|
196
|
-
|
|
197
|
-
:return: filtered_matches
|
|
198
|
-
:rtype: pandas Dataframe
|
|
199
|
-
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
filtered_pandora_matches, _ = (
|
|
203
|
-
outlier_removal_algo.small_component_filtering(
|
|
204
|
-
triangulated_matches,
|
|
205
|
-
connection_val=connection_val,
|
|
206
|
-
nb_pts_threshold=nb_pts_threshold,
|
|
207
|
-
clusters_distance_threshold=clusters_distance_threshold,
|
|
208
|
-
filtered_elt_pos=filtered_elt_pos,
|
|
209
|
-
)
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
filtered_pandora_matches_dataframe = pandas.DataFrame(
|
|
213
|
-
filtered_pandora_matches
|
|
214
|
-
)
|
|
215
|
-
filtered_pandora_matches_dataframe.attrs["epsg"] = (
|
|
216
|
-
triangulated_matches.attrs["epsg"]
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
return filtered_pandora_matches_dataframe
|
|
220
|
-
|
|
221
|
-
|
|
222
173
|
@cars_profile(name="filter_point_cloud_matches")
|
|
223
174
|
def filter_point_cloud_matches(
|
|
224
175
|
pd_cloud,
|
|
@@ -1044,7 +1044,7 @@ def triangulation_wrapper(
|
|
|
1044
1044
|
ambiguity_map = None
|
|
1045
1045
|
perf_ambiguity_threshold = None
|
|
1046
1046
|
if use_ambiguity:
|
|
1047
|
-
ambiguity_map = disp_ref["
|
|
1047
|
+
ambiguity_map = disp_ref["ambiguity"]
|
|
1048
1048
|
perf_ambiguity_threshold = performance_maps_parameters[
|
|
1049
1049
|
"perf_ambiguity_threshold"
|
|
1050
1050
|
]
|
|
@@ -246,7 +246,8 @@ def compute_performance_map(
|
|
|
246
246
|
)
|
|
247
247
|
|
|
248
248
|
if ambiguity_map is not None:
|
|
249
|
-
|
|
249
|
+
# ambiguity is already ambiguity, not confidence from ambiguity
|
|
250
|
+
ambiguity_map = ambiguity_map.values
|
|
250
251
|
mask_ambi = ambiguity_map > perf_ambiguity_threshold
|
|
251
252
|
w_ambi = ambiguity_map / perf_ambiguity_threshold
|
|
252
253
|
w_ambi[mask_ambi] = 1
|
cars/bundleadjustment.py
CHANGED
|
@@ -15,6 +15,7 @@ import geopandas as gpd
|
|
|
15
15
|
import numpy as np
|
|
16
16
|
import pandas as pd
|
|
17
17
|
import rasterio as rio
|
|
18
|
+
import yaml
|
|
18
19
|
|
|
19
20
|
try:
|
|
20
21
|
from rpcfit import rpc_fit
|
|
@@ -34,6 +35,7 @@ from shareloc.geomodels.geomodel import GeoModel
|
|
|
34
35
|
from shareloc.geomodels.los import LOS
|
|
35
36
|
from shareloc.proj_utils import coordinates_conversion
|
|
36
37
|
|
|
38
|
+
from cars.pipelines.parameters import sensor_inputs
|
|
37
39
|
from cars.pipelines.pipeline import Pipeline
|
|
38
40
|
|
|
39
41
|
|
|
@@ -550,14 +552,26 @@ def new_rpcs_from_matches(
|
|
|
550
552
|
return None
|
|
551
553
|
|
|
552
554
|
|
|
553
|
-
def cars_bundle_adjustment(conf, no_run_sparse):
|
|
555
|
+
def cars_bundle_adjustment(conf, no_run_sparse, output_format="yaml"):
|
|
554
556
|
"""
|
|
555
557
|
cars-bundleadjustement main:
|
|
556
558
|
- Launch CARS to compute homologous points (run sparse matching)
|
|
557
559
|
- Compute new RPCs
|
|
558
560
|
"""
|
|
559
|
-
|
|
560
|
-
|
|
561
|
+
_, ext = os.path.splitext(conf)
|
|
562
|
+
ext = ext.lower()
|
|
563
|
+
|
|
564
|
+
if ext == ".json":
|
|
565
|
+
with open(conf, encoding="utf-8") as reader:
|
|
566
|
+
conf_as_dict = json.load(reader)
|
|
567
|
+
elif ext in [".yaml", ".yml"]:
|
|
568
|
+
with open(conf, encoding="utf-8") as reader:
|
|
569
|
+
conf_as_dict = yaml.safe_load(reader)
|
|
570
|
+
else:
|
|
571
|
+
raise ValueError(
|
|
572
|
+
f"Unsupported configuration file format: {ext}. "
|
|
573
|
+
"Please use .json, .yaml, or .yml"
|
|
574
|
+
)
|
|
561
575
|
|
|
562
576
|
conf_dirname = os.path.dirname(conf)
|
|
563
577
|
out_dir = os.path.abspath(
|
|
@@ -576,6 +590,7 @@ def cars_bundle_adjustment(conf, no_run_sparse):
|
|
|
576
590
|
]
|
|
577
591
|
sparse_matching_config["output"]["directory"] = sparse_matching
|
|
578
592
|
sparse_matching_config["output"]["product_level"] = []
|
|
593
|
+
sparse_matching_config["advanced"] = {}
|
|
579
594
|
sparse_matching_config["advanced"]["epipolar_resolutions"] = [1]
|
|
580
595
|
if "sparse_matching.sift" not in sparse_matching_config["applications"]:
|
|
581
596
|
sparse_matching_config["applications"]["sparse_matching.sift"] = {}
|
|
@@ -595,6 +610,9 @@ def cars_bundle_adjustment(conf, no_run_sparse):
|
|
|
595
610
|
sparse_matching_pipeline.run()
|
|
596
611
|
|
|
597
612
|
# create new refined rpcs
|
|
613
|
+
conf_as_dict["inputs"] = sensor_inputs.sensors_check_inputs(
|
|
614
|
+
conf_as_dict["inputs"], config_dir=conf_dirname
|
|
615
|
+
)
|
|
598
616
|
separate = bundle_adjustment_config.pop("separate")
|
|
599
617
|
refined_rpcs = new_rpcs_from_matches(
|
|
600
618
|
conf_as_dict["inputs"]["sensors"],
|
|
@@ -623,9 +641,15 @@ def cars_bundle_adjustment(conf, no_run_sparse):
|
|
|
623
641
|
raw_config["inputs"]["pairing"] = pairing
|
|
624
642
|
raw_config["output"]["directory"] = raw
|
|
625
643
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
644
|
+
# output config file
|
|
645
|
+
raw_cfg_file = raw_config["output"]["directory"] + (
|
|
646
|
+
".yaml" if output_format == "yaml" else ".json"
|
|
647
|
+
)
|
|
648
|
+
with open(raw_cfg_file, "w", encoding="utf8") as writer:
|
|
649
|
+
if output_format == "yaml":
|
|
650
|
+
yaml.safe_dump(raw_config, writer, sort_keys=False)
|
|
651
|
+
else:
|
|
652
|
+
json.dump(raw_config, writer, indent=2)
|
|
629
653
|
|
|
630
654
|
if refined_rpcs is not None:
|
|
631
655
|
# create configuration file + launch cars dense matching
|
|
@@ -645,9 +669,14 @@ def cars_bundle_adjustment(conf, no_run_sparse):
|
|
|
645
669
|
refined_config["inputs"]["pairing"] = pairing
|
|
646
670
|
refined_config["output"]["directory"] = refined
|
|
647
671
|
|
|
648
|
-
refined_cfg_file = refined_config["output"]["directory"] +
|
|
649
|
-
|
|
650
|
-
|
|
672
|
+
refined_cfg_file = refined_config["output"]["directory"] + (
|
|
673
|
+
".yaml" if output_format == "yaml" else ".json"
|
|
674
|
+
)
|
|
675
|
+
with open(refined_cfg_file, "w", encoding="utf8") as writer:
|
|
676
|
+
if output_format == "yaml":
|
|
677
|
+
yaml.safe_dump(refined_config, writer, sort_keys=False)
|
|
678
|
+
else:
|
|
679
|
+
json.dump(refined_config, writer, indent=2)
|
|
651
680
|
|
|
652
681
|
|
|
653
682
|
def cli():
|
|
@@ -679,8 +708,8 @@ key and its associated value:
|
|
|
679
708
|
```
|
|
680
709
|
|
|
681
710
|
- Parameters "pairing" and "separate" are mandatory.
|
|
682
|
-
- Parameters "nb_decimals" (default value: 0)
|
|
683
|
-
(default value: 100) are optional.
|
|
711
|
+
- Parameters "nb_decimals" (default value: 0), "min_matches" \
|
|
712
|
+
(default value: 100) and "output_format" (default value: yaml) are optional.
|
|
684
713
|
|
|
685
714
|
### Generation of homologous points calculated by pair
|
|
686
715
|
|
|
@@ -704,7 +733,18 @@ number of matches per zone required to calculate these statistics."""
|
|
|
704
733
|
)
|
|
705
734
|
parser.add_argument("conf", type=str, help="Configuration File")
|
|
706
735
|
parser.add_argument("--no-run-sparse", action="store_true")
|
|
736
|
+
parser.add_argument(
|
|
737
|
+
"--output-format",
|
|
738
|
+
type=str,
|
|
739
|
+
default="json",
|
|
740
|
+
choices=["json", "yaml", "JSON", "YAML"],
|
|
741
|
+
help="Output format for generated configuration files "
|
|
742
|
+
"(json or yaml, case-insensitive). Default: json",
|
|
743
|
+
)
|
|
744
|
+
|
|
707
745
|
args = parser.parse_args()
|
|
746
|
+
# normalize format to lowercase
|
|
747
|
+
args.output_format = args.output_format.lower()
|
|
708
748
|
cars_bundle_adjustment(**vars(args))
|
|
709
749
|
|
|
710
750
|
|
cars/cars.py
CHANGED
|
@@ -33,6 +33,8 @@ import os
|
|
|
33
33
|
import sys
|
|
34
34
|
import warnings
|
|
35
35
|
|
|
36
|
+
import yaml
|
|
37
|
+
|
|
36
38
|
# CARS imports
|
|
37
39
|
from cars import __version__
|
|
38
40
|
from cars.core import cars_logging
|
|
@@ -87,9 +89,17 @@ def main_cli(args, dry_run=False): # noqa: C901
|
|
|
87
89
|
from cars.pipelines.pipeline import Pipeline
|
|
88
90
|
|
|
89
91
|
try:
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
# Check file extension and load configuration
|
|
93
|
+
config_path = args.conf
|
|
94
|
+
ext = os.path.splitext(config_path)[1].lower()
|
|
95
|
+
if ext == ".json":
|
|
96
|
+
with open(config_path, "r", encoding="utf8") as fstream:
|
|
97
|
+
config = json.load(fstream)
|
|
98
|
+
elif ext in [".yaml", ".yml"]:
|
|
99
|
+
with open(config_path, "r", encoding="utf8") as fstream:
|
|
100
|
+
config = yaml.safe_load(fstream)
|
|
101
|
+
else:
|
|
102
|
+
raise ValueError("Configuration file must be .json or .yaml/.yml")
|
|
93
103
|
|
|
94
104
|
# Cars 0.9.0 API change, check if the configfile seems to use the old
|
|
95
105
|
# API by looking for the deprecated out_dir key
|
|
@@ -109,7 +119,7 @@ def main_cli(args, dry_run=False): # noqa: C901
|
|
|
109
119
|
config["output"]["directory"] = config["output"]["out_dir"]
|
|
110
120
|
del config["output"]["out_dir"]
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
config_dir = os.path.abspath(os.path.dirname(config_path))
|
|
113
123
|
pipeline_name = config.get("advanced", {}).get("pipeline", "default")
|
|
114
124
|
|
|
115
125
|
# Logging configuration with args Loglevel
|
|
@@ -126,7 +136,7 @@ def main_cli(args, dry_run=False): # noqa: C901
|
|
|
126
136
|
|
|
127
137
|
# Generate pipeline and check conf
|
|
128
138
|
cars_logging.add_progress_message("Check configuration...")
|
|
129
|
-
used_pipeline = Pipeline(pipeline_name, config,
|
|
139
|
+
used_pipeline = Pipeline(pipeline_name, config, config_dir)
|
|
130
140
|
cars_logging.add_progress_message("CARS pipeline is started.")
|
|
131
141
|
if not dry_run:
|
|
132
142
|
# run pipeline
|
cars/core/constants.py
CHANGED
|
@@ -184,7 +184,7 @@ DSM_INF_MEAN = "dsm_inf_mean"
|
|
|
184
184
|
DSM_INF_STD = "dsm_inf_std"
|
|
185
185
|
DSM_SUP_MEAN = "dsm_sup_mean"
|
|
186
186
|
DSM_SUP_STD = "dsm_sup_std"
|
|
187
|
-
|
|
187
|
+
DSM_AMBIGUITY = "ambiguity"
|
|
188
188
|
DSM_CONFIDENCE = "confidence"
|
|
189
189
|
DSM_PERFORMANCE_MAP = "performance_map"
|
|
190
190
|
DSM_SOURCE_PC = "source_pc"
|