cars 1.0.0a3__cp39-cp39-win_amd64.whl → 1.0.0a4__cp39-cp39-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 +5 -5
- cars/applications/__init__.py +0 -3
- cars/applications/application_template.py +20 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +12 -2
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +2 -2
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +80 -36
- cars/applications/dem_generation/dem_generation_algo.py +1 -1
- cars/applications/dem_generation/dem_generation_wrappers.py +23 -57
- cars/applications/dem_generation/dichotomic_generation_app.py +3 -3
- cars/applications/dem_generation/rasterization_app.py +100 -41
- cars/applications/dense_match_filling/__init__.py +1 -1
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +2 -15
- cars/applications/dense_match_filling/fill_disp_algo.py +32 -373
- cars/applications/dense_match_filling/fill_disp_wrappers.py +0 -343
- cars/applications/dense_match_filling/zero_padding_app.py +10 -5
- cars/applications/dense_matching/abstract_dense_matching_app.py +2 -1
- cars/applications/dense_matching/census_mccnn_sgm_app.py +38 -39
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp39-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp39-win_amd64.pyd +0 -0
- cars/applications/dense_matching/dense_matching_algo.py +48 -14
- cars/applications/dense_matching/dense_matching_wrappers.py +11 -3
- cars/applications/dense_matching/disparity_grid_algo.py +84 -62
- cars/applications/dense_matching/loaders/pandora_loader.py +91 -33
- cars/applications/dsm_filling/border_interpolation_app.py +1 -7
- cars/applications/dsm_filling/bulldozer_filling_app.py +2 -8
- cars/applications/dsm_filling/exogenous_filling_app.py +4 -9
- cars/applications/grid_generation/abstract_grid_generation_app.py +1 -1
- cars/applications/grid_generation/epipolar_grid_generation_app.py +4 -2
- cars/applications/grid_generation/grid_correction_app.py +4 -1
- cars/applications/grid_generation/grid_generation_algo.py +7 -2
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +1 -1
- cars/applications/ground_truth_reprojection/direct_localization_app.py +2 -2
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +2 -1
- cars/applications/point_cloud_fusion/abstract_pc_fusion_app.py +0 -155
- cars/applications/point_cloud_fusion/mapping_to_terrain_tiles_app.py +0 -658
- cars/applications/point_cloud_fusion/pc_fusion_algo.py +0 -1339
- cars/applications/point_cloud_fusion/pc_fusion_wrappers.py +0 -869
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +2 -1
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +9 -8
- cars/applications/point_cloud_outlier_removal/small_components_app.py +96 -267
- cars/applications/point_cloud_outlier_removal/statistical_app.py +116 -275
- cars/applications/rasterization/abstract_pc_rasterization_app.py +1 -1
- cars/applications/rasterization/rasterization_algo.py +18 -6
- cars/applications/rasterization/rasterization_wrappers.py +2 -1
- cars/applications/rasterization/simple_gaussian_app.py +60 -113
- cars/applications/resampling/abstract_resampling_app.py +1 -1
- cars/applications/resampling/bicubic_resampling_app.py +3 -1
- cars/applications/resampling/resampling_algo.py +16 -4
- cars/applications/resampling/resampling_wrappers.py +3 -1
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +1 -1
- cars/applications/sparse_matching/sift_app.py +3 -3
- cars/applications/sparse_matching/sparse_matching_algo.py +3 -2
- cars/applications/sparse_matching/sparse_matching_wrappers.py +1 -1
- cars/applications/triangulation/abstract_triangulation_app.py +1 -1
- cars/applications/triangulation/line_of_sight_intersection_app.py +13 -11
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +6 -4
- cars/applications/triangulation/triangulation_wrappers.py +1 -0
- cars/bundleadjustment.py +6 -6
- cars/cars.py +11 -9
- cars/core/cars_logging.py +80 -49
- cars/core/constants.py +0 -1
- cars/core/datasets.py +5 -2
- cars/core/geometry/abstract_geometry.py +256 -25
- cars/core/geometry/shareloc_geometry.py +110 -82
- cars/core/inputs.py +57 -19
- cars/core/outputs.py +1 -1
- cars/core/preprocessing.py +17 -3
- cars/core/projection.py +9 -6
- cars/core/tiling.py +10 -3
- cars/data_structures/cars_dataset.py +5 -5
- cars/data_structures/corresponding_tiles_tools.py +0 -103
- cars/data_structures/format_transformation.py +4 -1
- cars/devibrate.py +6 -3
- cars/extractroi.py +20 -21
- cars/orchestrator/cluster/abstract_cluster.py +15 -5
- cars/orchestrator/cluster/abstract_dask_cluster.py +6 -2
- cars/orchestrator/cluster/dask_jobqueue_utils.py +1 -1
- cars/orchestrator/cluster/log_wrapper.py +148 -21
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +11 -3
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +2 -2
- cars/orchestrator/cluster/pbs_dask_cluster.py +1 -1
- cars/orchestrator/cluster/sequential_cluster.py +5 -4
- cars/orchestrator/cluster/slurm_dask_cluster.py +1 -1
- cars/orchestrator/orchestrator.py +14 -3
- cars/orchestrator/registry/id_generator.py +1 -0
- cars/orchestrator/registry/saver_registry.py +2 -2
- cars/pipelines/conf_resolution/conf_final_resolution.json +5 -3
- cars/pipelines/default/default_pipeline.py +462 -1073
- cars/pipelines/parameters/advanced_parameters.py +74 -64
- cars/pipelines/parameters/advanced_parameters_constants.py +2 -5
- cars/pipelines/parameters/application_parameters.py +71 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -314
- cars/pipelines/parameters/dsm_inputs.py +40 -4
- cars/pipelines/parameters/output_parameters.py +2 -2
- cars/pipelines/parameters/sensor_inputs.py +30 -75
- cars/pipelines/parameters/sensor_inputs_constants.py +0 -2
- cars/pipelines/parameters/sensor_loaders/__init__.py +4 -3
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +106 -0
- cars/pipelines/parameters/sensor_loaders/{basic_sensor_loader.py → basic_image_loader.py} +16 -22
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +121 -0
- cars/pipelines/parameters/sensor_loaders/{pivot_sensor_loader.py → pivot_image_loader.py} +10 -21
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +4 -6
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +1 -3
- cars/pipelines/pipeline_template.py +1 -3
- cars/pipelines/unit/unit_pipeline.py +527 -1016
- cars/starter.py +4 -3
- cars-1.0.0a4.dist-info/DELVEWHEEL +2 -0
- {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/METADATA +135 -53
- {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/RECORD +116 -132
- cars.libs/.load-order-cars-1.0.0a4 +3 -0
- cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
- cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
- cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
- cars/applications/dense_match_filling/cpp/__init__.py +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp39-win_amd64.dll.a +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.cp39-win_amd64.pyd +0 -0
- cars/applications/dense_match_filling/cpp/dense_match_filling_cpp.py +0 -72
- cars/applications/dense_match_filling/cpp/includes/dense_match_filling.hpp +0 -46
- cars/applications/dense_match_filling/cpp/meson.build +0 -9
- cars/applications/dense_match_filling/cpp/src/bindings.cpp +0 -11
- cars/applications/dense_match_filling/cpp/src/dense_match_filling.cpp +0 -142
- cars/applications/dense_match_filling/plane_app.py +0 -556
- cars/applications/hole_detection/__init__.py +0 -30
- cars/applications/hole_detection/abstract_hole_detection_app.py +0 -125
- cars/applications/hole_detection/cloud_to_bbox_app.py +0 -346
- cars/applications/hole_detection/hole_detection_algo.py +0 -144
- cars/applications/hole_detection/hole_detection_wrappers.py +0 -53
- cars/applications/point_cloud_denoising/__init__.py +0 -29
- cars/applications/point_cloud_denoising/abstract_pc_denoising_app.py +0 -273
- cars/applications/point_cloud_fusion/__init__.py +0 -30
- cars/applications/point_cloud_fusion/cloud_fusion_constants.py +0 -39
- cars/applications/sparse_matching/pandora_sparse_matching_app.py +0 -0
- cars/pipelines/parameters/depth_map_inputs_constants.py +0 -25
- cars-1.0.0a3.dist-info/DELVEWHEEL +0 -2
- cars.libs/.load-order-cars-1.0.0a3 +0 -3
- 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.0a3.dist-info → cars-1.0.0a4.dist-info}/WHEEL +0 -0
- {cars-1.0.0a3.dist-info → cars-1.0.0a4.dist-info}/entry_points.txt +0 -0
|
@@ -27,8 +27,6 @@ Contains functions for array reconstructions and crop for multiple tiles
|
|
|
27
27
|
import numpy as np
|
|
28
28
|
import xarray as xr
|
|
29
29
|
|
|
30
|
-
import cars.core.constants as cst
|
|
31
|
-
|
|
32
30
|
|
|
33
31
|
def reconstruct_data(tiles, window, overlap): # noqa: C901
|
|
34
32
|
"""
|
|
@@ -186,104 +184,3 @@ def reconstruct_data(tiles, window, overlap): # noqa: C901
|
|
|
186
184
|
dims=dims,
|
|
187
185
|
).astype(data_type)
|
|
188
186
|
return new_dataset, row_min - ol_row_min, col_min - ol_col_min
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def find_tile_dataset(corresponding_tiles, window):
|
|
192
|
-
"""
|
|
193
|
-
Find the dataset corresponding to window, in the list of tiles.
|
|
194
|
-
|
|
195
|
-
:param corresponding_tiles: list of tiles
|
|
196
|
-
:type corresponding_tiles: list(tuple)
|
|
197
|
-
:param window: window of base tile [row min, row max, col min col max]
|
|
198
|
-
:type window: list
|
|
199
|
-
|
|
200
|
-
:return: dataset corresponding to window
|
|
201
|
-
:rtype: xr.Dataset
|
|
202
|
-
|
|
203
|
-
"""
|
|
204
|
-
|
|
205
|
-
dataset = None
|
|
206
|
-
for tile_window, _, tile_dataset in corresponding_tiles:
|
|
207
|
-
if tuple(tile_window) == tuple(window):
|
|
208
|
-
dataset = tile_dataset
|
|
209
|
-
|
|
210
|
-
return dataset
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def crop_dataset(full_dataset, in_dataset, window, overlap, row_min, col_min):
|
|
214
|
-
"""
|
|
215
|
-
Crop full dataset to fit with a given tile dataset
|
|
216
|
-
|
|
217
|
-
:param full_dataset: Combined dataset
|
|
218
|
-
:type full_dataset: xr.Dataset
|
|
219
|
-
:param in_dataset: dataset to use as template dataset
|
|
220
|
-
:type in_dataset: xr.Dataset
|
|
221
|
-
:param window: window of base tile [row min, row max, col min col max]
|
|
222
|
-
:type window: list
|
|
223
|
-
:param overlap: overlap of base tile [row min, row max, col min col max]
|
|
224
|
-
:type overlap: list
|
|
225
|
-
:param row_min: position of row min in full image
|
|
226
|
-
:type row_min: int
|
|
227
|
-
:param col_min: position of col min in full image
|
|
228
|
-
:type col_min: int
|
|
229
|
-
|
|
230
|
-
:return: cropped dataset
|
|
231
|
-
:rtype: xr.Dataset
|
|
232
|
-
|
|
233
|
-
"""
|
|
234
|
-
cropped = xr.Dataset()
|
|
235
|
-
|
|
236
|
-
coords = {}
|
|
237
|
-
if cst.ROW in in_dataset:
|
|
238
|
-
coords[cst.ROW] = in_dataset.coords[cst.ROW]
|
|
239
|
-
if cst.COL in in_dataset:
|
|
240
|
-
coords[cst.COL] = in_dataset.coords[cst.COL]
|
|
241
|
-
|
|
242
|
-
list_tags = list(full_dataset.keys())
|
|
243
|
-
|
|
244
|
-
for tag in list_tags:
|
|
245
|
-
full_data = full_dataset[tag].values
|
|
246
|
-
|
|
247
|
-
offset_row = int(window[0] - overlap[0] - row_min)
|
|
248
|
-
offset_col = int(window[2] - overlap[2] - col_min)
|
|
249
|
-
|
|
250
|
-
if len(full_data.shape) == 2:
|
|
251
|
-
nb_row = int(in_dataset[tag].values.shape[0])
|
|
252
|
-
nb_col = int(in_dataset[tag].values.shape[1])
|
|
253
|
-
|
|
254
|
-
values = np.ascontiguousarray(
|
|
255
|
-
full_data[
|
|
256
|
-
offset_row : offset_row + nb_row,
|
|
257
|
-
offset_col : offset_col + nb_col,
|
|
258
|
-
]
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
else:
|
|
262
|
-
nb_row = int(in_dataset[tag].values.shape[1])
|
|
263
|
-
nb_col = int(in_dataset[tag].values.shape[2])
|
|
264
|
-
|
|
265
|
-
values = np.ascontiguousarray(
|
|
266
|
-
full_data[
|
|
267
|
-
:,
|
|
268
|
-
offset_row : offset_row + nb_row,
|
|
269
|
-
offset_col : offset_col + nb_col,
|
|
270
|
-
]
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
xarray_coords = {}
|
|
274
|
-
for coord_tag in full_dataset[tag].coords:
|
|
275
|
-
if coord_tag in coords:
|
|
276
|
-
xarray_coords[coord_tag] = coords[coord_tag]
|
|
277
|
-
else:
|
|
278
|
-
xarray_coords[coord_tag] = full_dataset[tag].coords[coord_tag]
|
|
279
|
-
|
|
280
|
-
dims = full_dataset[tag].dims
|
|
281
|
-
|
|
282
|
-
data_array = xr.DataArray(values, coords=xarray_coords, dims=dims)
|
|
283
|
-
if tag in in_dataset:
|
|
284
|
-
data_array.attrs = in_dataset[tag].attrs
|
|
285
|
-
cropped[tag] = data_array
|
|
286
|
-
|
|
287
|
-
cropped.attrs = in_dataset.attrs
|
|
288
|
-
|
|
289
|
-
return cropped
|
|
@@ -30,9 +30,12 @@ import math
|
|
|
30
30
|
import numpy as np
|
|
31
31
|
import xarray as xr
|
|
32
32
|
|
|
33
|
+
from cars.orchestrator.cluster.log_wrapper import cars_profile
|
|
34
|
+
|
|
33
35
|
# CARS imports
|
|
34
36
|
|
|
35
37
|
|
|
38
|
+
@cars_profile(name="Grid margins 2 overlaps", interval=0.5)
|
|
36
39
|
def grid_margins_2_overlaps(grid, margins_fun):
|
|
37
40
|
"""
|
|
38
41
|
Convert margins to overlap grid format used in CarsDatasets
|
|
@@ -48,7 +51,7 @@ def grid_margins_2_overlaps(grid, margins_fun):
|
|
|
48
51
|
|
|
49
52
|
"""
|
|
50
53
|
|
|
51
|
-
def fill_overlap(
|
|
54
|
+
def fill_overlap( # pylint: disable=too-many-positional-arguments
|
|
52
55
|
cars_ds_overlaps,
|
|
53
56
|
margins,
|
|
54
57
|
row_up,
|
cars/devibrate.py
CHANGED
|
@@ -95,7 +95,7 @@ def acquisition_direction(
|
|
|
95
95
|
return time_direction_vector, vec1, vec2
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def get_time_ground_direction(
|
|
98
|
+
def get_time_ground_direction( # pylint: disable=too-many-positional-arguments
|
|
99
99
|
sensor,
|
|
100
100
|
geomodel,
|
|
101
101
|
geometry_plugin,
|
|
@@ -180,6 +180,7 @@ def project_coordinates_on_line(
|
|
|
180
180
|
return dist_to_origin * np.cos(proj_angle)
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
# pylint: disable=too-many-positional-arguments
|
|
183
184
|
def lowres_initial_dem_splines_fit(
|
|
184
185
|
lowres_dsm_from_matches: xr.Dataset,
|
|
185
186
|
lowres_initial_dem: xr.Dataset,
|
|
@@ -379,7 +380,7 @@ def read_lowres_dsm(srtm_path, startx, starty, endx, endy):
|
|
|
379
380
|
return dsm_as_ds, newstartx, newstarty, sizex, sizey, resolution
|
|
380
381
|
|
|
381
382
|
|
|
382
|
-
def compute_splines(
|
|
383
|
+
def compute_splines( # pylint: disable=too-many-positional-arguments
|
|
383
384
|
sensor1,
|
|
384
385
|
geomodel1,
|
|
385
386
|
sensor2,
|
|
@@ -507,7 +508,7 @@ def compute_splines(
|
|
|
507
508
|
}
|
|
508
509
|
|
|
509
510
|
|
|
510
|
-
def cars_devibrate(
|
|
511
|
+
def cars_devibrate( # pylint: disable=too-many-positional-arguments
|
|
511
512
|
used_conf,
|
|
512
513
|
srtm_path,
|
|
513
514
|
geoid_path,
|
|
@@ -594,6 +595,8 @@ def cars_devibrate(
|
|
|
594
595
|
)
|
|
595
596
|
|
|
596
597
|
x_values_2d, y_values_2d = np.meshgrid(x_values_1d, y_values_1d)
|
|
598
|
+
|
|
599
|
+
positions = None
|
|
597
600
|
if src.crs != "EPSG:4326":
|
|
598
601
|
transformer = pyproj.Transformer.from_crs(
|
|
599
602
|
src.crs, "EPSG:4326", always_xy=True
|
cars/extractroi.py
CHANGED
|
@@ -29,6 +29,7 @@ import numpy as np
|
|
|
29
29
|
import rasterio as rio
|
|
30
30
|
from affine import Affine
|
|
31
31
|
from shapely.geometry import box
|
|
32
|
+
from shareloc.geomodels.rpc_writers import write_rio_rpc_as_rpb
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
def is_bbx_in_image(bbx, image_dataset):
|
|
@@ -75,7 +76,7 @@ def get_slices_from_bbx(image_dataset, bbx, rpc_options):
|
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
def process_image_file(
|
|
78
|
-
bbx, input_image_path, output_image_path,
|
|
79
|
+
bbx, input_image_path, output_image_path, rpb_file_path, rpc_options
|
|
79
80
|
):
|
|
80
81
|
"""
|
|
81
82
|
Processes an image file by extracting a region based on the given geometry.
|
|
@@ -84,7 +85,7 @@ def process_image_file(
|
|
|
84
85
|
region_geometry (dict): GeoJSON-like dictionary defining the region.
|
|
85
86
|
input_image_path (str): Path to the input image file.
|
|
86
87
|
output_image_path (str): Path to save the output image.
|
|
87
|
-
|
|
88
|
+
rpb_file_path (str): Path to save the .RPB file.
|
|
88
89
|
rpc_options (dict): Options for GDALCreateRPCTransformer.
|
|
89
90
|
"""
|
|
90
91
|
|
|
@@ -110,7 +111,8 @@ def process_image_file(
|
|
|
110
111
|
# copy rpc
|
|
111
112
|
dst.rpcs = image_dataset.rpcs
|
|
112
113
|
|
|
113
|
-
|
|
114
|
+
if rpb_file_path is not None:
|
|
115
|
+
create_rpb_file(image_dataset, rpb_file_path)
|
|
114
116
|
|
|
115
117
|
|
|
116
118
|
def get_human_readable_bbox(image_dataset, rpc_options):
|
|
@@ -167,34 +169,23 @@ def validate_bounding_box(bbx, image_dataset, rpc_options):
|
|
|
167
169
|
image_dataset, rpc_options
|
|
168
170
|
)
|
|
169
171
|
raise ValueError(
|
|
170
|
-
f"Coordinates must between "
|
|
172
|
+
f"Coordinates must be between "
|
|
171
173
|
f"({min_x}, {min_y}) and ({max_x}, {max_y})"
|
|
172
174
|
)
|
|
173
175
|
|
|
174
176
|
|
|
175
|
-
def
|
|
177
|
+
def create_rpb_file(image_dataset, rpb_filename):
|
|
176
178
|
"""
|
|
177
|
-
Create and save a .
|
|
179
|
+
Create and save a .RPB file from a rasterio dataset
|
|
178
180
|
|
|
179
181
|
Parameters:
|
|
180
182
|
image_dataset (rio.DatasetReader): Opened image dataset.
|
|
181
|
-
|
|
183
|
+
rpb_filename (str): Path to save the .RPB file.
|
|
182
184
|
"""
|
|
183
185
|
if not image_dataset.rpcs:
|
|
184
186
|
raise ValueError("Image dataset has no RPCs")
|
|
185
187
|
rpcs_as_dict = image_dataset.rpcs.to_dict()
|
|
186
|
-
|
|
187
|
-
for key in rpcs_as_dict:
|
|
188
|
-
if isinstance(rpcs_as_dict[key], list):
|
|
189
|
-
for idx, coef in enumerate(rpcs_as_dict[key]):
|
|
190
|
-
writer.write(key + "_%02d" % idx + ": " + str(coef))
|
|
191
|
-
writer.write("\n")
|
|
192
|
-
else:
|
|
193
|
-
writer.write(key + ": " + str(rpcs_as_dict[key]))
|
|
194
|
-
writer.write("\n")
|
|
195
|
-
|
|
196
|
-
writer.write("type: ossimRpcModel\n")
|
|
197
|
-
writer.write("polynomial_format: B\n")
|
|
188
|
+
write_rio_rpc_as_rpb(rpcs_as_dict, rpb_filename)
|
|
198
189
|
|
|
199
190
|
|
|
200
191
|
def main():
|
|
@@ -240,6 +231,12 @@ def main():
|
|
|
240
231
|
help="Digital Elevation Model used for projection",
|
|
241
232
|
)
|
|
242
233
|
|
|
234
|
+
parser.add_argument(
|
|
235
|
+
"--generate_rpb",
|
|
236
|
+
action="store_true",
|
|
237
|
+
help="Generate RPB file",
|
|
238
|
+
)
|
|
239
|
+
|
|
243
240
|
args = parser.parse_args()
|
|
244
241
|
if not os.path.exists(args.out):
|
|
245
242
|
os.makedirs(args.out)
|
|
@@ -254,10 +251,12 @@ def main():
|
|
|
254
251
|
# check first input in list to determine pipeline
|
|
255
252
|
for idx, image_path in enumerate(args.il):
|
|
256
253
|
output_image_path = os.path.join(args.out, "ext_%03d.tif" % idx)
|
|
257
|
-
|
|
254
|
+
rpb_file_path = None
|
|
255
|
+
if args.generate_rpb:
|
|
256
|
+
rpb_file_path = os.path.splitext(output_image_path)[0] + ".RPB"
|
|
258
257
|
|
|
259
258
|
process_image_file(
|
|
260
|
-
args.bbx, image_path, output_image_path,
|
|
259
|
+
args.bbx, image_path, output_image_path, rpb_file_path, rpc_options
|
|
261
260
|
)
|
|
262
261
|
|
|
263
262
|
|
|
@@ -48,8 +48,13 @@ class AbstractCluster(metaclass=ABCMeta):
|
|
|
48
48
|
# cluster mode output directory
|
|
49
49
|
out_dir: str
|
|
50
50
|
|
|
51
|
-
def __new__( # pylint: disable=
|
|
52
|
-
cls,
|
|
51
|
+
def __new__( # pylint: disable=too-many-positional-arguments
|
|
52
|
+
cls,
|
|
53
|
+
conf_cluster,
|
|
54
|
+
out_dir,
|
|
55
|
+
log_dir,
|
|
56
|
+
launch_worker=True,
|
|
57
|
+
data_to_propagate=None,
|
|
53
58
|
):
|
|
54
59
|
"""
|
|
55
60
|
Return the required cluster
|
|
@@ -98,8 +103,13 @@ class AbstractCluster(metaclass=ABCMeta):
|
|
|
98
103
|
|
|
99
104
|
return decorator
|
|
100
105
|
|
|
101
|
-
def __init__(
|
|
102
|
-
self,
|
|
106
|
+
def __init__( # pylint: disable=too-many-positional-arguments
|
|
107
|
+
self,
|
|
108
|
+
conf_cluster,
|
|
109
|
+
out_dir,
|
|
110
|
+
log_dir,
|
|
111
|
+
launch_worker=True,
|
|
112
|
+
data_to_propagate=None,
|
|
103
113
|
): # pylint: disable=W0613
|
|
104
114
|
"""
|
|
105
115
|
Init function of AbstractCluster
|
|
@@ -114,7 +124,7 @@ class AbstractCluster(metaclass=ABCMeta):
|
|
|
114
124
|
# data to propagate
|
|
115
125
|
self.data_to_propagate = data_to_propagate
|
|
116
126
|
|
|
117
|
-
self.worker_log_dir = os.path.join(
|
|
127
|
+
self.worker_log_dir = os.path.join(log_dir, "workers_log")
|
|
118
128
|
if not os.path.exists(self.worker_log_dir):
|
|
119
129
|
os.makedirs(self.worker_log_dir)
|
|
120
130
|
|
|
@@ -56,7 +56,7 @@ class AbstractDaskCluster(
|
|
|
56
56
|
AbstractDaskCluster
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
|
-
def __init__(self, conf_cluster, out_dir, launch_worker=True):
|
|
59
|
+
def __init__(self, conf_cluster, out_dir, log_dir, launch_worker=True):
|
|
60
60
|
"""
|
|
61
61
|
Init function of AbstractDaskCluster
|
|
62
62
|
|
|
@@ -64,8 +64,12 @@ class AbstractDaskCluster(
|
|
|
64
64
|
|
|
65
65
|
"""
|
|
66
66
|
|
|
67
|
+
print("cluster log_dir", log_dir)
|
|
68
|
+
|
|
67
69
|
# call parent init
|
|
68
|
-
super().__init__(
|
|
70
|
+
super().__init__(
|
|
71
|
+
conf_cluster, out_dir, log_dir, launch_worker=launch_worker
|
|
72
|
+
)
|
|
69
73
|
# retrieve parameters
|
|
70
74
|
self.nb_workers = self.checked_conf_cluster["nb_workers"]
|
|
71
75
|
self.task_timeout = self.checked_conf_cluster["task_timeout"]
|
|
@@ -26,6 +26,7 @@ Contains functions for wrapper logs
|
|
|
26
26
|
import copy
|
|
27
27
|
import cProfile
|
|
28
28
|
import datetime
|
|
29
|
+
import functools
|
|
29
30
|
import gc
|
|
30
31
|
import io
|
|
31
32
|
import logging
|
|
@@ -44,6 +45,8 @@ import numpy as np
|
|
|
44
45
|
import pandas as pd
|
|
45
46
|
import psutil
|
|
46
47
|
from json_checker import Checker
|
|
48
|
+
from matplotlib.backends.backend_pdf import PdfPages
|
|
49
|
+
from PIL import Image
|
|
47
50
|
|
|
48
51
|
from cars.core import cars_logging
|
|
49
52
|
from cars.core.utils import safe_makedirs
|
|
@@ -496,11 +499,37 @@ def log_delta_memory(func, memory_start, memory_end):
|
|
|
496
499
|
log_message(func, message)
|
|
497
500
|
|
|
498
501
|
|
|
502
|
+
def exception_safe(func):
|
|
503
|
+
"""
|
|
504
|
+
Decorator for consistent exception handling in profiling functions
|
|
505
|
+
|
|
506
|
+
:param func: function to wrap
|
|
507
|
+
:return: wrapped function
|
|
508
|
+
"""
|
|
509
|
+
|
|
510
|
+
@functools.wraps(func)
|
|
511
|
+
def wrapper(*args, **kwargs):
|
|
512
|
+
"""
|
|
513
|
+
Catch error
|
|
514
|
+
"""
|
|
515
|
+
try:
|
|
516
|
+
return func(*args, **kwargs)
|
|
517
|
+
except Exception as exc:
|
|
518
|
+
error_msg = (
|
|
519
|
+
f"Error in {func.__name__}: {type(exc).__name__}: {str(exc)}"
|
|
520
|
+
)
|
|
521
|
+
logging.error(error_msg)
|
|
522
|
+
cars_logging.add_profiling_message(f"ERROR - {error_msg}")
|
|
523
|
+
return None
|
|
524
|
+
|
|
525
|
+
return wrapper
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
@exception_safe
|
|
499
529
|
def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
500
530
|
"""
|
|
501
531
|
Generate Profiling summary
|
|
502
532
|
"""
|
|
503
|
-
|
|
504
533
|
nb_workers = 1
|
|
505
534
|
if "orchestrator" not in used_conf:
|
|
506
535
|
first_key = next(iter(used_conf))
|
|
@@ -510,16 +539,15 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
510
539
|
if "nb_workers" in used_conf["orchestrator"]:
|
|
511
540
|
nb_workers = used_conf["orchestrator"]["nb_workers"]
|
|
512
541
|
|
|
513
|
-
workers_log_dir = os.path.join(out_dir, "
|
|
542
|
+
workers_log_dir = os.path.join(out_dir, "workers_log")
|
|
543
|
+
os.makedirs(workers_log_dir, exist_ok=True)
|
|
514
544
|
|
|
515
545
|
log_file_main = os.path.join(
|
|
516
546
|
workers_log_dir,
|
|
517
547
|
"profiling.log",
|
|
518
548
|
)
|
|
519
549
|
|
|
520
|
-
out_profiling_main = os.path.join(
|
|
521
|
-
out_dir, "logs", "profiling", "profiling.log"
|
|
522
|
-
)
|
|
550
|
+
out_profiling_main = os.path.join(out_dir, "profiling", "profiling.log")
|
|
523
551
|
|
|
524
552
|
log_files = [log_file_main, out_profiling_main]
|
|
525
553
|
|
|
@@ -640,7 +668,7 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
640
668
|
cars_logging.add_profiling_message(message)
|
|
641
669
|
|
|
642
670
|
# Generate png
|
|
643
|
-
_, axs = plt.subplots(
|
|
671
|
+
_, axs = plt.subplots(3, 2, figsize=(20, 20), layout="tight")
|
|
644
672
|
# Fill
|
|
645
673
|
|
|
646
674
|
generate_boxplot(
|
|
@@ -689,6 +717,14 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
689
717
|
"calls",
|
|
690
718
|
)
|
|
691
719
|
|
|
720
|
+
# file_name
|
|
721
|
+
profiling_plot = os.path.join(
|
|
722
|
+
out_dir,
|
|
723
|
+
"profiling",
|
|
724
|
+
"profiling_plots_histograms.png",
|
|
725
|
+
)
|
|
726
|
+
plt.savefig(profiling_plot)
|
|
727
|
+
|
|
692
728
|
# Pie chart
|
|
693
729
|
|
|
694
730
|
(name_task_workers, summary_workers) = filter_lists(
|
|
@@ -704,7 +740,7 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
704
740
|
)
|
|
705
741
|
|
|
706
742
|
(_, [pipeline_time]) = filter_lists(
|
|
707
|
-
summary_names, summary_total_time, lambda name: "
|
|
743
|
+
summary_names, summary_total_time, lambda name: "unit_pipeline" in name
|
|
708
744
|
)
|
|
709
745
|
|
|
710
746
|
(_, [multiprocessing_time]) = filter_lists(
|
|
@@ -717,8 +753,10 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
717
753
|
|
|
718
754
|
total_time_workers = nb_workers * multiprocessing_time
|
|
719
755
|
|
|
756
|
+
_, axs2 = plt.subplots(2, 1, figsize=(40, 40), layout="tight")
|
|
757
|
+
|
|
720
758
|
generate_pie_chart(
|
|
721
|
-
|
|
759
|
+
axs2.flat[0],
|
|
722
760
|
name_task_workers,
|
|
723
761
|
100 * np.array(summary_workers) / total_time_workers,
|
|
724
762
|
"Total time in parallel tasks ({} workers) : {}".format(
|
|
@@ -728,7 +766,7 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
728
766
|
)
|
|
729
767
|
|
|
730
768
|
generate_pie_chart(
|
|
731
|
-
|
|
769
|
+
axs2.flat[1],
|
|
732
770
|
name_task_main,
|
|
733
771
|
100 * np.array(summary_main) / sequential_time,
|
|
734
772
|
"Total time in sequential tasks : {}".format(
|
|
@@ -736,19 +774,103 @@ def generate_summary(out_dir, used_conf, clean_worker_logs=False):
|
|
|
736
774
|
),
|
|
737
775
|
)
|
|
738
776
|
|
|
739
|
-
|
|
740
|
-
profiling_plot = os.path.join(
|
|
777
|
+
profiling_plot2 = os.path.join(
|
|
741
778
|
out_dir,
|
|
742
|
-
"logs",
|
|
743
779
|
"profiling",
|
|
744
|
-
"
|
|
780
|
+
"profiling_plots_pie_chart.png",
|
|
745
781
|
)
|
|
746
|
-
plt.savefig(
|
|
782
|
+
plt.savefig(profiling_plot2)
|
|
747
783
|
|
|
748
784
|
if clean_worker_logs and os.path.exists(workers_log_dir):
|
|
749
785
|
shutil.rmtree(workers_log_dir)
|
|
750
786
|
|
|
751
787
|
|
|
788
|
+
def generate_pdf_profiling(log_dir):
|
|
789
|
+
"""
|
|
790
|
+
Generate PDF profiling summary for all res
|
|
791
|
+
"""
|
|
792
|
+
|
|
793
|
+
pages_data = {}
|
|
794
|
+
resolutions = []
|
|
795
|
+
|
|
796
|
+
for item in os.listdir(log_dir):
|
|
797
|
+
item_path = os.path.join(log_dir, item)
|
|
798
|
+
if os.path.isdir(item_path) and item.startswith("res"):
|
|
799
|
+
# Get resolution
|
|
800
|
+
res = int(item[4:])
|
|
801
|
+
resolutions.append(res)
|
|
802
|
+
|
|
803
|
+
# Add paths
|
|
804
|
+
pages_data[res] = {
|
|
805
|
+
"function_profiling_histo": os.path.join(
|
|
806
|
+
item_path, "profiling", "profiling_plots_histo.png"
|
|
807
|
+
),
|
|
808
|
+
"function_profiling_pie_chart": os.path.join(
|
|
809
|
+
item_path, "profiling", "profiling_plots_pie_chart.png"
|
|
810
|
+
),
|
|
811
|
+
"global_profiling": os.path.join(
|
|
812
|
+
item_path, "profiling", "memory_profiling.png"
|
|
813
|
+
),
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
# ordered resolutions
|
|
817
|
+
resolutions.sort(reverse=True)
|
|
818
|
+
|
|
819
|
+
# Build pdf
|
|
820
|
+
pdf_path = os.path.join(log_dir, "profiling_summary.pdf")
|
|
821
|
+
|
|
822
|
+
with PdfPages(pdf_path) as pdf:
|
|
823
|
+
for res in resolutions:
|
|
824
|
+
# function_profiling
|
|
825
|
+
if os.path.exists(pages_data[res]["function_profiling_histo"]):
|
|
826
|
+
img = Image.open(pages_data[res]["function_profiling_histo"])
|
|
827
|
+
fig, axis = plt.subplots(1, 1, figsize=(11.69, 8.27), dpi=300)
|
|
828
|
+
axis.imshow(img, interpolation="none")
|
|
829
|
+
axis.set_title(
|
|
830
|
+
f"Function Profiling Histograms - "
|
|
831
|
+
f"Epipolar Resolution {res}",
|
|
832
|
+
fontsize=16,
|
|
833
|
+
fontweight="bold",
|
|
834
|
+
)
|
|
835
|
+
axis.axis("off")
|
|
836
|
+
plt.subplots_adjust(left=0, right=1, top=0.95, bottom=0)
|
|
837
|
+
pdf.savefig(fig, bbox_inches="tight", dpi=300)
|
|
838
|
+
plt.close(fig)
|
|
839
|
+
|
|
840
|
+
if os.path.exists(pages_data[res]["function_profiling_pie_chart"]):
|
|
841
|
+
img = Image.open(
|
|
842
|
+
pages_data[res]["function_profiling_pie_chart"]
|
|
843
|
+
)
|
|
844
|
+
fig, axis = plt.subplots(1, 1, figsize=(11.69, 8.27), dpi=300)
|
|
845
|
+
axis.imshow(img, interpolation="none")
|
|
846
|
+
axis.set_title(
|
|
847
|
+
f"Function Profiling Pie Chart - Epipolar Resolution {res}",
|
|
848
|
+
fontsize=16,
|
|
849
|
+
fontweight="bold",
|
|
850
|
+
)
|
|
851
|
+
axis.axis("off")
|
|
852
|
+
plt.subplots_adjust(left=0, right=1, top=0.95, bottom=0)
|
|
853
|
+
pdf.savefig(fig, bbox_inches="tight", dpi=300)
|
|
854
|
+
plt.close(fig)
|
|
855
|
+
|
|
856
|
+
# global_profiling
|
|
857
|
+
if os.path.exists(pages_data[res]["global_profiling"]):
|
|
858
|
+
img = Image.open(pages_data[res]["global_profiling"])
|
|
859
|
+
fig, axis = plt.subplots(1, 1, figsize=(11.69, 8.27), dpi=300)
|
|
860
|
+
axis.imshow(img, interpolation="none")
|
|
861
|
+
axis.set_title(
|
|
862
|
+
f"Global Profiling - Epipolar Resolution {res}",
|
|
863
|
+
fontsize=16,
|
|
864
|
+
fontweight="bold",
|
|
865
|
+
)
|
|
866
|
+
axis.axis("off")
|
|
867
|
+
plt.subplots_adjust(left=0, right=1, top=0.95, bottom=0)
|
|
868
|
+
pdf.savefig(fig, bbox_inches="tight", dpi=300)
|
|
869
|
+
plt.close(fig)
|
|
870
|
+
|
|
871
|
+
logging.info("PDF profiling summary generated: {}".format(pdf_path))
|
|
872
|
+
|
|
873
|
+
|
|
752
874
|
def filter_lists(names, data, cond):
|
|
753
875
|
"""
|
|
754
876
|
Filter lists with condition on name
|
|
@@ -776,7 +898,7 @@ def generate_boxplot(axis, names, data_full, title, data_type):
|
|
|
776
898
|
axis.set_title(title)
|
|
777
899
|
|
|
778
900
|
|
|
779
|
-
def generate_histo(
|
|
901
|
+
def generate_histo( # pylint: disable=too-many-positional-arguments
|
|
780
902
|
axis, names, data, title, data_type, data_min_err=None, data_max_err=None
|
|
781
903
|
):
|
|
782
904
|
"""
|
|
@@ -815,8 +937,14 @@ def generate_pie_chart(axis, names, data, title):
|
|
|
815
937
|
data.append(others)
|
|
816
938
|
names.append("other")
|
|
817
939
|
|
|
818
|
-
axis.pie(
|
|
819
|
-
|
|
940
|
+
axis.pie(
|
|
941
|
+
data,
|
|
942
|
+
labels=names,
|
|
943
|
+
autopct="%1.1f%%",
|
|
944
|
+
labeldistance=1.1,
|
|
945
|
+
textprops={"fontsize": 30},
|
|
946
|
+
)
|
|
947
|
+
axis.set_title(title, fontsize=40)
|
|
820
948
|
|
|
821
949
|
|
|
822
950
|
def cars_profile(name=None, interval=0.1):
|
|
@@ -926,15 +1054,14 @@ class CarsMemProf(Thread):
|
|
|
926
1054
|
# Get memory
|
|
927
1055
|
current_mem = self.process.memory_info().rss
|
|
928
1056
|
|
|
929
|
-
|
|
930
|
-
max_mem = current_mem
|
|
1057
|
+
max_mem = max(max_mem, current_mem)
|
|
931
1058
|
|
|
932
1059
|
# Get cpu max
|
|
933
1060
|
current_cpu = self.process.cpu_percent(
|
|
934
1061
|
interval=self.cpu_interval
|
|
935
1062
|
)
|
|
936
|
-
|
|
937
|
-
|
|
1063
|
+
|
|
1064
|
+
max_cpu = max(max_cpu, current_cpu)
|
|
938
1065
|
|
|
939
1066
|
if stop:
|
|
940
1067
|
break
|
|
@@ -83,8 +83,13 @@ class MultiprocessingCluster(abstract_cluster.AbstractCluster):
|
|
|
83
83
|
|
|
84
84
|
# pylint: disable=too-many-instance-attributes
|
|
85
85
|
@cars_profile(name="Multiprocessing orchestrator initialization")
|
|
86
|
-
def __init__(
|
|
87
|
-
self,
|
|
86
|
+
def __init__( # pylint: disable=too-many-positional-arguments
|
|
87
|
+
self,
|
|
88
|
+
conf_cluster,
|
|
89
|
+
out_dir,
|
|
90
|
+
log_dir,
|
|
91
|
+
launch_worker=True,
|
|
92
|
+
data_to_propagate=None,
|
|
88
93
|
):
|
|
89
94
|
"""
|
|
90
95
|
Init function of MultiprocessingCluster
|
|
@@ -102,10 +107,12 @@ class MultiprocessingCluster(abstract_cluster.AbstractCluster):
|
|
|
102
107
|
logging.warning(message)
|
|
103
108
|
|
|
104
109
|
self.out_dir = out_dir
|
|
110
|
+
self.log_dir = log_dir
|
|
105
111
|
# call parent init
|
|
106
112
|
super().__init__(
|
|
107
113
|
conf_cluster,
|
|
108
114
|
out_dir,
|
|
115
|
+
log_dir,
|
|
109
116
|
launch_worker=launch_worker,
|
|
110
117
|
data_to_propagate=data_to_propagate,
|
|
111
118
|
)
|
|
@@ -202,7 +209,7 @@ class MultiprocessingCluster(abstract_cluster.AbstractCluster):
|
|
|
202
209
|
|
|
203
210
|
self.profiler = MultiprocessingProfiler(
|
|
204
211
|
self.pool,
|
|
205
|
-
self.
|
|
212
|
+
self.log_dir,
|
|
206
213
|
self.checked_conf_cluster["max_ram_per_worker"],
|
|
207
214
|
mp_dataframe=mp_dataframe,
|
|
208
215
|
timer=timer,
|
|
@@ -459,6 +466,7 @@ class MultiprocessingCluster(abstract_cluster.AbstractCluster):
|
|
|
459
466
|
|
|
460
467
|
return object_future
|
|
461
468
|
|
|
469
|
+
# pylint: disable=too-many-positional-arguments
|
|
462
470
|
@staticmethod # noqa: C901
|
|
463
471
|
def refresh_task_cache( # noqa: C901
|
|
464
472
|
pool,
|