cloudanalyzer 0.2.0__tar.gz → 0.4.0__tar.gz
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.
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/PKG-INFO +5 -1
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/__init__.py +1 -1
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/ground_evaluate.py +30 -8
- cloudanalyzer-0.4.0/ca/core/map_evaluate.py +302 -0
- cloudanalyzer-0.4.0/ca/core/slam_run.py +329 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/ground_evaluate/height_band.py +5 -5
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/ground_evaluate/voxel_confusion.py +5 -4
- cloudanalyzer-0.4.0/ca/experiments/map_evaluate/common.py +99 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/map_evaluate/evaluate.py +19 -11
- cloudanalyzer-0.4.0/ca/experiments/map_evaluate/nn_thresholds.py +16 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/process_docs.py +10 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/__init__.py +46 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/common.py +244 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/evaluate.py +242 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/identity_passthrough.py +90 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/kiss_icp_driver.py +126 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/kiss_slam_driver.py +175 -0
- cloudanalyzer-0.4.0/ca/experiments/slam_run/small_gicp_driver.py +179 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/geometry.py +279 -73
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/split.py +19 -7
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer.egg-info/PKG-INFO +5 -1
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer.egg-info/SOURCES.txt +14 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer.egg-info/requires.txt +5 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer_cli/main.py +247 -5
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/pyproject.toml +5 -0
- cloudanalyzer-0.4.0/tests/test_geometry_splat_ellipsoid.py +275 -0
- cloudanalyzer-0.4.0/tests/test_map_evaluate_core.py +81 -0
- cloudanalyzer-0.4.0/tests/test_phase17_vectorize.py +210 -0
- cloudanalyzer-0.4.0/tests/test_phase18_vectorize.py +150 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_process_docs.py +3 -0
- cloudanalyzer-0.4.0/tests/test_slam_run.py +638 -0
- cloudanalyzer-0.2.0/ca/experiments/map_evaluate/common.py +0 -201
- cloudanalyzer-0.2.0/ca/experiments/map_evaluate/nn_thresholds.py +0 -135
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/LICENSE +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/README.md +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/align.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/baseline_history.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/batch.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/benchmark.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/bundle.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/compare.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/convert.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/check_baseline_evolution.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/check_scaffolding.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/check_triage.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/checks.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/web_progressive_loading.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/web_sampling.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/core/web_trajectory_sampling.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/crop.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/density_map.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/detection.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/diff.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/downsample.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_baseline_evolution/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_baseline_evolution/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_baseline_evolution/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_baseline_evolution/pareto_promote.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_baseline_evolution/stability_window.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_baseline_evolution/threshold_guard.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_scaffolding/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_scaffolding/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_scaffolding/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_scaffolding/literal_profiles.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_scaffolding/object_sections.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_scaffolding/pipeline_overlays.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_triage/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_triage/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_triage/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_triage/pareto_frontier.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_triage/severity_weighted.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/check_triage/signature_cluster.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/ground_evaluate/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/ground_evaluate/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/ground_evaluate/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/ground_evaluate/nearest_neighbor.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/map_evaluate/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/map_evaluate/voxel_entropy.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_progressive_loading/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_progressive_loading/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_progressive_loading/distance_shells.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_progressive_loading/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_progressive_loading/grid_tiles.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_progressive_loading/spatial_shuffle.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_sampling/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_sampling/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_sampling/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_sampling/functional_voxel.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_sampling/object_random.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_sampling/pipeline_hybrid.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_trajectory_sampling/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_trajectory_sampling/common.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_trajectory_sampling/distance_accumulator.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_trajectory_sampling/evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_trajectory_sampling/turn_aware.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/experiments/web_trajectory_sampling/uniform_stride.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/filter.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/ground_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/history.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/info.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/io.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/kitti.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/log.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/loop_closure_report.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/merge.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/metrics.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/mme.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/normals.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/object_eval.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/pareto.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/pipeline.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/plot.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/point_summary.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/posegraph.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/pr_comment.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/registration.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/report.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/run_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/sample.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/scan_match_debug.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/slam_debug.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/stats.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/tracking.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/trajectory.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/view.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/visualization.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/ca/web.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer.egg-info/dependency_links.txt +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer.egg-info/entry_points.txt +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer.egg-info/top_level.txt +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/cloudanalyzer_cli/__init__.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/setup.cfg +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/setup.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_align.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_baseline_history.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_batch.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_benchmark.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_bundle.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_check_baseline_evolution_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_check_scaffolding_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_check_suite.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_check_triage_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_cli.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_compare.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_convert.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_crop.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_density_map.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_detection_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_detection_tracking_report.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_diff.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_downsample.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_filter.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_geometry.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_ground_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_ground_evaluate_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_history.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_info.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_io.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_kitti.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_logging.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_loop_closure_report.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_map_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_merge.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_metrics.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_mme.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_normals.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_object_eval_iou.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_output_json.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_pareto.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_phase16_large_scale.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_pipeline.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_plot.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_posegraph.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_pr_comment.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_public_benchmark_pack.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_public_object_eval_examples.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_registration.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_report.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_run_batch.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_run_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_sample.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_scan_match_debug.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_slam_debug.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_split.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_stats.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_threshold.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_tracking_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_traj_batch.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_trajectory.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_visualization.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_progressive_loading_core.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_progressive_loading_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_progressive_loading_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_progressive_loading_strategies.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_sampling_core.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_sampling_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_sampling_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_sampling_strategies.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_trajectory_sampling_core.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_trajectory_sampling_evaluate.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_trajectory_sampling_process.py +0 -0
- {cloudanalyzer-0.2.0 → cloudanalyzer-0.4.0}/tests/test_web_trajectory_sampling_strategies.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudanalyzer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: CLI-first QA toolkit for point cloud, trajectory, and 3D perception outputs
|
|
5
5
|
Author: rsasaki0109
|
|
6
6
|
License-Expression: MIT
|
|
@@ -36,6 +36,10 @@ Requires-Dist: mypy; extra == "dev"
|
|
|
36
36
|
Requires-Dist: pkginfo>=1.12.0; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest; extra == "dev"
|
|
38
38
|
Requires-Dist: twine>=6.0.0; extra == "dev"
|
|
39
|
+
Provides-Extra: slam
|
|
40
|
+
Requires-Dist: kiss-icp>=1.2.0; extra == "slam"
|
|
41
|
+
Requires-Dist: kiss-slam>=0.0.2; extra == "slam"
|
|
42
|
+
Requires-Dist: small_gicp>=1.0.0; extra == "slam"
|
|
39
43
|
Dynamic: license-file
|
|
40
44
|
|
|
41
45
|
# CloudAnalyzer
|
|
@@ -47,12 +47,34 @@ class GroundEvaluateStrategy(Protocol):
|
|
|
47
47
|
"""Evaluate ground segmentation quality."""
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def _voxel_keys(points: np.ndarray, voxel_size: float) ->
|
|
51
|
-
"""Compute voxel grid keys for an Nx3 point array.
|
|
50
|
+
def _voxel_keys(points: np.ndarray, voxel_size: float) -> np.ndarray:
|
|
51
|
+
"""Compute unique voxel grid keys for an Nx3 point array.
|
|
52
|
+
|
|
53
|
+
Returns an (M, 3) int64 array of unique (i, j, k) voxel indices, sorted
|
|
54
|
+
lexicographically. The original implementation built a ``set`` of Python
|
|
55
|
+
tuples via a per-row generator, which dominated runtime on city-scale
|
|
56
|
+
inputs (millions of points × 4 calls per evaluation).
|
|
57
|
+
"""
|
|
52
58
|
if points.shape[0] == 0:
|
|
53
|
-
return
|
|
59
|
+
return np.empty((0, 3), dtype=np.int64)
|
|
54
60
|
indices = np.floor(points / voxel_size).astype(np.int64)
|
|
55
|
-
return
|
|
61
|
+
return np.unique(indices, axis=0)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _voxel_intersection_size(a: np.ndarray, b: np.ndarray) -> int:
|
|
65
|
+
"""Count voxel keys present in both ``a`` and ``b``.
|
|
66
|
+
|
|
67
|
+
Both inputs are expected to be the unique (M, 3) int64 output of
|
|
68
|
+
:func:`_voxel_keys`. Packs each row into a single ``np.void`` of the row's
|
|
69
|
+
byte length so ``np.intersect1d`` can run in C.
|
|
70
|
+
"""
|
|
71
|
+
if a.size == 0 or b.size == 0:
|
|
72
|
+
return 0
|
|
73
|
+
item_size = a.dtype.itemsize * a.shape[1]
|
|
74
|
+
void_dtype = np.dtype((np.void, item_size))
|
|
75
|
+
a_view = np.ascontiguousarray(a).view(void_dtype).ravel()
|
|
76
|
+
b_view = np.ascontiguousarray(b).view(void_dtype).ravel()
|
|
77
|
+
return int(np.intersect1d(a_view, b_view, assume_unique=True).size)
|
|
56
78
|
|
|
57
79
|
|
|
58
80
|
def confusion_metrics(tp: int, fp: int, fn: int, tn: int) -> dict[str, float]:
|
|
@@ -83,10 +105,10 @@ class VoxelConfusionGroundEvaluateStrategy:
|
|
|
83
105
|
ref_ground_voxels = _voxel_keys(request.reference_ground, request.voxel_size)
|
|
84
106
|
ref_nonground_voxels = _voxel_keys(request.reference_nonground, request.voxel_size)
|
|
85
107
|
|
|
86
|
-
tp =
|
|
87
|
-
fp =
|
|
88
|
-
fn =
|
|
89
|
-
tn =
|
|
108
|
+
tp = _voxel_intersection_size(est_ground_voxels, ref_ground_voxels)
|
|
109
|
+
fp = _voxel_intersection_size(est_ground_voxels, ref_nonground_voxels)
|
|
110
|
+
fn = _voxel_intersection_size(est_nonground_voxels, ref_ground_voxels)
|
|
111
|
+
tn = _voxel_intersection_size(est_nonground_voxels, ref_nonground_voxels)
|
|
90
112
|
metrics = confusion_metrics(tp, fp, fn, tn)
|
|
91
113
|
|
|
92
114
|
return GroundEvaluateResult(
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Stable, minimal interface for point-cloud map evaluation.
|
|
2
|
+
|
|
3
|
+
This slice started as ``ca/experiments/map_evaluate/`` with two
|
|
4
|
+
non-comparable strategies on separate metric-family lanes:
|
|
5
|
+
|
|
6
|
+
- ``nn_thresholds`` — reference-based (GT-aware) MapEval-style accuracy and
|
|
7
|
+
completeness@τ via per-point nearest-neighbor distances (scipy cKDTree).
|
|
8
|
+
- ``voxel_entropy`` — reference-free self-consistency proxy via voxelized
|
|
9
|
+
neighborhood occupancy entropy.
|
|
10
|
+
|
|
11
|
+
Because the two strategies do not compete head-to-head, "promoting to core"
|
|
12
|
+
means lifting the **request/result contract plus the adopted reference-based
|
|
13
|
+
strategy** here, leaving ``voxel_entropy`` in ``ca/experiments/map_evaluate``
|
|
14
|
+
as the orthogonal reference-free option. Callers that just want GT-based
|
|
15
|
+
metrics can now depend on ``ca.core.map_evaluate`` directly and the CLI
|
|
16
|
+
no longer reaches into ``ca.experiments``.
|
|
17
|
+
|
|
18
|
+
The reference-free lane remains experimental until we settle on a single
|
|
19
|
+
GT-free metric — anyone needing it for now imports from
|
|
20
|
+
``ca.experiments.map_evaluate.voxel_entropy`` explicitly.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from dataclasses import dataclass, field
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Any, Protocol
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------- contract
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(slots=True)
|
|
36
|
+
class MapEvaluateRequest:
|
|
37
|
+
"""Compare an estimated point cloud map to a reference (optional).
|
|
38
|
+
|
|
39
|
+
Strategies with ``reference_required=True`` raise on ``reference_points=None``;
|
|
40
|
+
reference-free strategies treat the same field as unused.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
estimated_points: np.ndarray # (N, 3)
|
|
44
|
+
reference_points: np.ndarray | None = None # (M, 3) when present
|
|
45
|
+
# MapEval-inspired: allow using an external coarse alignment.
|
|
46
|
+
initial_transform_4x4: np.ndarray | None = None # shape (4, 4)
|
|
47
|
+
# "none" = use estimated_points as-is, "initial" = pre-apply initial_transform_4x4.
|
|
48
|
+
align_mode: str = "none"
|
|
49
|
+
downsample_voxel_size: float = 0.0
|
|
50
|
+
# Optional output dir for strategy-specific artifacts (colored PLYs, etc.)
|
|
51
|
+
artifact_dir: str | None = None
|
|
52
|
+
# MapEval "accuracy_level" thresholds for inlier ratios.
|
|
53
|
+
thresholds_m: tuple[float, ...] = (0.2, 0.1, 0.08, 0.05, 0.01)
|
|
54
|
+
# A coarse voxel size useful for structure-aware proxies.
|
|
55
|
+
structure_voxel_size: float = 0.5
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass(slots=True)
|
|
59
|
+
class MapEvaluateResult:
|
|
60
|
+
"""Common output for all strategies.
|
|
61
|
+
|
|
62
|
+
Classification fields (``metric_family``, ``reference_required``, ``mode``,
|
|
63
|
+
``sampling_policy``) describe *how* the metrics were computed so consumers
|
|
64
|
+
(CI gates, reports, batch aggregators) can keep reference-based and
|
|
65
|
+
reference-free metrics in separate lanes without parsing metric names.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
strategy: str
|
|
69
|
+
design: str
|
|
70
|
+
metrics: dict[str, float]
|
|
71
|
+
artifacts: dict[str, Any]
|
|
72
|
+
metric_family: str = "unspecified"
|
|
73
|
+
reference_required: bool = False
|
|
74
|
+
mode: str = "exact"
|
|
75
|
+
sampling_policy: dict[str, Any] = field(default_factory=dict)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class MapEvaluateStrategy(Protocol):
|
|
79
|
+
"""Protocol kept in core after promoting the reference-based strategy."""
|
|
80
|
+
|
|
81
|
+
name: str
|
|
82
|
+
design: str
|
|
83
|
+
|
|
84
|
+
def evaluate(self, request: MapEvaluateRequest) -> MapEvaluateResult:
|
|
85
|
+
"""Evaluate a map and return classified metrics."""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# ---------------------------------------------------------------- helpers
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _require_xyz(points: np.ndarray, name: str) -> np.ndarray:
|
|
92
|
+
arr = np.asarray(points, dtype=np.float64)
|
|
93
|
+
if arr.ndim != 2 or arr.shape[1] != 3:
|
|
94
|
+
raise ValueError(f"{name} must be shape (N, 3); got {arr.shape}")
|
|
95
|
+
return arr
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _require_transform_4x4(matrix: np.ndarray, name: str) -> np.ndarray:
|
|
99
|
+
mat = np.asarray(matrix, dtype=np.float64)
|
|
100
|
+
if mat.shape != (4, 4):
|
|
101
|
+
raise ValueError(f"{name} must be shape (4, 4); got {mat.shape}")
|
|
102
|
+
return mat
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def apply_transform(points: np.ndarray, transform_4x4: np.ndarray) -> np.ndarray:
|
|
106
|
+
pts = _require_xyz(points, "points")
|
|
107
|
+
t = _require_transform_4x4(transform_4x4, "transform_4x4")
|
|
108
|
+
if pts.shape[0] == 0:
|
|
109
|
+
return pts
|
|
110
|
+
hom = np.concatenate([pts, np.ones((pts.shape[0], 1), dtype=np.float64)], axis=1)
|
|
111
|
+
out = (hom @ t.T)[:, :3]
|
|
112
|
+
return np.asarray(out, dtype=np.float64)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def aligned_estimated_points(request: MapEvaluateRequest) -> np.ndarray:
|
|
116
|
+
est = _require_xyz(request.estimated_points, "estimated_points")
|
|
117
|
+
mode = (request.align_mode or "none").strip().lower()
|
|
118
|
+
if mode == "none":
|
|
119
|
+
return est
|
|
120
|
+
if mode == "initial":
|
|
121
|
+
if request.initial_transform_4x4 is None:
|
|
122
|
+
raise ValueError("align_mode='initial' requires initial_transform_4x4.")
|
|
123
|
+
return apply_transform(est, request.initial_transform_4x4)
|
|
124
|
+
raise ValueError(f"Unsupported align_mode: {request.align_mode!r}. Use 'none' or 'initial'.")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def ensure_artifact_dir(request: MapEvaluateRequest, subdir: str) -> Path | None:
|
|
128
|
+
"""Return an ensured artifact directory path or None if disabled."""
|
|
129
|
+
if request.artifact_dir is None:
|
|
130
|
+
return None
|
|
131
|
+
root = Path(request.artifact_dir)
|
|
132
|
+
out = root / subdir
|
|
133
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
134
|
+
return out
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def voxel_downsample(points: np.ndarray, voxel_size: float) -> np.ndarray:
|
|
138
|
+
"""Deterministic voxel downsample by centroid per voxel."""
|
|
139
|
+
pts = _require_xyz(points, "points")
|
|
140
|
+
if pts.shape[0] == 0 or voxel_size <= 0:
|
|
141
|
+
return pts
|
|
142
|
+
keys = np.floor(pts / voxel_size).astype(np.int64)
|
|
143
|
+
order = np.lexsort((keys[:, 2], keys[:, 1], keys[:, 0]))
|
|
144
|
+
keys_sorted = keys[order]
|
|
145
|
+
pts_sorted = pts[order]
|
|
146
|
+
unique, start_idx = np.unique(keys_sorted, axis=0, return_index=True)
|
|
147
|
+
centroids: list[np.ndarray] = []
|
|
148
|
+
for i, s in enumerate(start_idx):
|
|
149
|
+
e = start_idx[i + 1] if i + 1 < len(start_idx) else pts_sorted.shape[0]
|
|
150
|
+
centroids.append(pts_sorted[s:e].mean(axis=0))
|
|
151
|
+
out = np.vstack(centroids) if centroids else np.zeros((0, 3), dtype=np.float64)
|
|
152
|
+
_ = unique # kept to mirror the index ordering for documentation
|
|
153
|
+
return np.asarray(out)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# ------------------------------------------------------- adopted strategy
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _min_distances_kdtree(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
160
|
+
"""Per-point min Euclidean distance from ``a`` to ``b`` via scipy cKDTree."""
|
|
161
|
+
if a.shape[0] == 0:
|
|
162
|
+
return np.zeros((0,), dtype=np.float64)
|
|
163
|
+
if b.shape[0] == 0:
|
|
164
|
+
return np.full((a.shape[0],), np.inf, dtype=np.float64)
|
|
165
|
+
|
|
166
|
+
from scipy.spatial import cKDTree
|
|
167
|
+
|
|
168
|
+
tree = cKDTree(np.asarray(b, dtype=np.float64))
|
|
169
|
+
distances, _ = tree.query(np.asarray(a, dtype=np.float64), k=1)
|
|
170
|
+
return np.asarray(distances, dtype=np.float64)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _error_colors(dist_m: np.ndarray, vmax_m: float) -> np.ndarray:
|
|
174
|
+
"""Green→red ramp for distance visualization."""
|
|
175
|
+
vmax = float(max(vmax_m, 1e-12))
|
|
176
|
+
x = np.clip(dist_m / vmax, 0.0, 1.0)
|
|
177
|
+
r = x
|
|
178
|
+
g = 1.0 - x
|
|
179
|
+
b = np.zeros_like(x)
|
|
180
|
+
return np.column_stack([r, g, b]).astype(np.float64)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _write_colored_ply(points: np.ndarray, colors: np.ndarray, path: str) -> None:
|
|
184
|
+
import open3d as o3d
|
|
185
|
+
|
|
186
|
+
pcd = o3d.geometry.PointCloud()
|
|
187
|
+
pcd.points = o3d.utility.Vector3dVector(np.asarray(points, dtype=np.float64))
|
|
188
|
+
pcd.colors = o3d.utility.Vector3dVector(np.asarray(colors, dtype=np.float64))
|
|
189
|
+
o3d.io.write_point_cloud(path, pcd, write_ascii=False)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@dataclass(slots=True)
|
|
193
|
+
class NNThresholdMapEvaluateStrategy:
|
|
194
|
+
"""MapEval-style accuracy@τ / completeness@τ via per-point NN distances.
|
|
195
|
+
|
|
196
|
+
Promoted from ``ca/experiments/map_evaluate/nn_thresholds.py`` as the
|
|
197
|
+
adopted reference-based map evaluation strategy. The reference-free
|
|
198
|
+
``voxel_entropy`` lane stays under ``ca.experiments`` because the two
|
|
199
|
+
strategies do not compete on the same metric family.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
name: str = "nn_thresholds"
|
|
203
|
+
design: str = "functional"
|
|
204
|
+
|
|
205
|
+
def evaluate(self, request: MapEvaluateRequest) -> MapEvaluateResult:
|
|
206
|
+
est_aligned = aligned_estimated_points(request)
|
|
207
|
+
est = voxel_downsample(_require_xyz(est_aligned, "estimated_points"), request.downsample_voxel_size)
|
|
208
|
+
if request.reference_points is None:
|
|
209
|
+
raise ValueError("nn_thresholds requires reference_points (GT).")
|
|
210
|
+
ref = voxel_downsample(_require_xyz(request.reference_points, "reference_points"), request.downsample_voxel_size)
|
|
211
|
+
|
|
212
|
+
est_to_ref = _min_distances_kdtree(est, ref)
|
|
213
|
+
ref_to_est = _min_distances_kdtree(ref, est)
|
|
214
|
+
|
|
215
|
+
thresholds = tuple(float(x) for x in request.thresholds_m)
|
|
216
|
+
metrics: dict[str, float] = {
|
|
217
|
+
"n_est": float(est.shape[0]),
|
|
218
|
+
"n_ref": float(ref.shape[0]),
|
|
219
|
+
"mean_est_to_ref_m": float(np.mean(est_to_ref)) if est_to_ref.size else float("inf"),
|
|
220
|
+
"mean_ref_to_est_m": float(np.mean(ref_to_est)) if ref_to_est.size else float("inf"),
|
|
221
|
+
"chamfer_m": (
|
|
222
|
+
float(np.mean(est_to_ref)) + float(np.mean(ref_to_est))
|
|
223
|
+
if (est_to_ref.size and ref_to_est.size)
|
|
224
|
+
else float("inf")
|
|
225
|
+
),
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
for t in thresholds:
|
|
229
|
+
metrics[f"accuracy@{t:.3f}m"] = float(np.mean(est_to_ref <= t)) if est_to_ref.size else 0.0
|
|
230
|
+
metrics[f"completeness@{t:.3f}m"] = float(np.mean(ref_to_est <= t)) if ref_to_est.size else 0.0
|
|
231
|
+
|
|
232
|
+
# One scalar summary (F-score) using the first threshold.
|
|
233
|
+
t0 = thresholds[0] if thresholds else 0.2
|
|
234
|
+
acc = metrics.get(f"accuracy@{t0:.3f}m", 0.0)
|
|
235
|
+
com = metrics.get(f"completeness@{t0:.3f}m", 0.0)
|
|
236
|
+
fscore = (2 * acc * com / (acc + com)) if (acc + com) > 0 else 0.0
|
|
237
|
+
metrics[f"fscore@{t0:.3f}m"] = float(fscore)
|
|
238
|
+
|
|
239
|
+
artifacts: dict[str, object] = {
|
|
240
|
+
"thresholds_m": thresholds,
|
|
241
|
+
"downsample_voxel_size": float(request.downsample_voxel_size),
|
|
242
|
+
"align_mode": request.align_mode,
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
# Optional: MapEval-style raw/inlier error visualization PLYs.
|
|
246
|
+
out_dir = ensure_artifact_dir(request, "map_evaluate/nn_thresholds")
|
|
247
|
+
if out_dir is not None and est.shape[0] > 0:
|
|
248
|
+
vmax = thresholds[0] if thresholds else 0.2
|
|
249
|
+
raw_colors = _error_colors(est_to_ref, vmax_m=vmax)
|
|
250
|
+
raw_path = str(out_dir / "estimated_error_raw.ply")
|
|
251
|
+
_write_colored_ply(est, raw_colors, raw_path)
|
|
252
|
+
|
|
253
|
+
inlier_mask = est_to_ref <= vmax
|
|
254
|
+
inlier_points = est[inlier_mask]
|
|
255
|
+
inlier_colors = raw_colors[inlier_mask]
|
|
256
|
+
inlier_path = str(out_dir / f"estimated_error_inlier_{vmax:.3f}m.ply")
|
|
257
|
+
_write_colored_ply(inlier_points, inlier_colors, inlier_path)
|
|
258
|
+
|
|
259
|
+
artifacts["estimated_error_raw_ply"] = raw_path
|
|
260
|
+
artifacts[f"estimated_error_inlier_{vmax:.3f}m_ply"] = inlier_path
|
|
261
|
+
|
|
262
|
+
downsample_voxel = float(request.downsample_voxel_size)
|
|
263
|
+
mode = "voxelized" if downsample_voxel > 0 else "exact"
|
|
264
|
+
sampling_policy: dict[str, object] = {
|
|
265
|
+
"downsample_voxel_size_m": downsample_voxel,
|
|
266
|
+
"thresholds_m": list(thresholds),
|
|
267
|
+
"align_mode": request.align_mode,
|
|
268
|
+
"nn_backend": "scipy_ckdtree",
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return MapEvaluateResult(
|
|
272
|
+
strategy=self.name,
|
|
273
|
+
design=self.design,
|
|
274
|
+
metrics=metrics,
|
|
275
|
+
artifacts=artifacts,
|
|
276
|
+
metric_family="reference_based_nn_thresholds",
|
|
277
|
+
reference_required=True,
|
|
278
|
+
mode=mode,
|
|
279
|
+
sampling_policy=sampling_policy,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def evaluate_map(
|
|
284
|
+
request: MapEvaluateRequest,
|
|
285
|
+
strategy: MapEvaluateStrategy | None = None,
|
|
286
|
+
) -> MapEvaluateResult:
|
|
287
|
+
"""Evaluate a map using the stabilized strategy (defaults to NNThreshold)."""
|
|
288
|
+
eval_strategy = strategy or NNThresholdMapEvaluateStrategy()
|
|
289
|
+
return eval_strategy.evaluate(request)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
__all__ = [
|
|
293
|
+
"MapEvaluateRequest",
|
|
294
|
+
"MapEvaluateResult",
|
|
295
|
+
"MapEvaluateStrategy",
|
|
296
|
+
"NNThresholdMapEvaluateStrategy",
|
|
297
|
+
"aligned_estimated_points",
|
|
298
|
+
"apply_transform",
|
|
299
|
+
"ensure_artifact_dir",
|
|
300
|
+
"evaluate_map",
|
|
301
|
+
"voxel_downsample",
|
|
302
|
+
]
|