bioimage-cpp 0.4.0__tar.gz → 0.5.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.
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/PKG-INFO +1 -1
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/transformation/affine.hxx +37 -48
- bioimage_cpp-0.5.0/include/bioimage_cpp/transformation/coordinate.hxx +129 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/transformation.cxx +112 -0
- bioimage_cpp-0.5.0/src/bioimage_cpp/_version.py +1 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/transformation/__init__.py +2 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/transformation/_transformation.py +106 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_transformation.py +121 -0
- bioimage_cpp-0.4.0/src/bioimage_cpp/_version.py +0 -1
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/.github/workflows/docs.yml +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/.github/workflows/tests.yml +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/.github/workflows/wheels.yml +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/.gitignore +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/AGENTS.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/CMakeLists.txt +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/LICENSE +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/MIGRATION_GUIDE.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/README.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/affinities/check_compute_affinities.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/affinities/check_compute_embedding_distances.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/distance/benchmark.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/distance/check_non_maximum_distance_suppression.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/filters/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/filters/_bench_utils.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/filters/benchmark.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/filters/check_parity.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/flow/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/flow/_reference_impl.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/flow/benchmark.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/flow/check_flow_density.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/flow/create_test_data.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/_grid_affinity_compatibility.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/_rag_compatibility.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/_compatibility.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/check_edge_weighted.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/check_gasp.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/check_mala.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/check_node_and_edge_weighted.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/agglomeration/diagnose.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/benchmark_accumulate_labels.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/benchmark_bfs.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/check_grid_affinity_edges.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/check_grid_affinity_lifted_edges.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/check_rag_2d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/check_rag_3d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/_compatibility.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/check_fusion_move.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/check_greedy_additive.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/check_kernighan_lin.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/evaluate_solvers.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/lifted_multicut/repro_lifted_edges_segfault.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/_compatibility.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/check_chained.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/check_decomposer.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/check_fusion_move.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/check_greedy_additive.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/check_greedy_fixation.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/check_kernighan_lin.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/multicut/evaluate_solvers.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/mutex_watershed/check_mutex_clustering.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/graph/mutex_watershed/check_semantic_mutex_clustering.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/label_multiset/benchmark.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/local_maxima/benchmark.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/_label_equivalence.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/_mutex_watershed_equivalence.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/_semantic_mws_equivalence.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/_watershed_equivalence.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/_watershed_from_affinities_equivalence.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/benchmark_mutex_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_label_2d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_label_3d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_mutex_watershed_2d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_mutex_watershed_3d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_relabel_sequential.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_semantic_mutex_watershed_2d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_semantic_mutex_watershed_3d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_watershed_2d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_watershed_3d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_watershed_from_affinities_2d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/segmentation/check_watershed_from_affinities_3d.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/transformation/PERFORMANCE_NOTES.md +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/transformation/check_affine.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/utils/_mesh_smoothing_reference.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/utils/benchmark_mesh_smoothing.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/utils/benchmark_union_find.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/_lifted_problem.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/lifted_multicut_from_affinities.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/multicut_from_affinities.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/mutex_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/serialize_grid_lifted_problem.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/serialize_lifted_problem.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/examples/segmentation/watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/affinities/compute_affinities.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/affinities/compute_embedding_distances.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/array_view.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/blocking.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/edge_hash.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/grid.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/indexed_heap.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/mutex_storage.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/profile.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/relabel.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/semantic_labels.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/detail/threading.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/distance_transform.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/filters/convolve.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/filters/eigenvalues.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/filters/gaussian.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/filters/kernel.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/flow/flow_density.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/agglomerative_clustering.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/cluster_policy_base.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/detail.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/edge_weighted.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/gasp.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/mala.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration/node_and_edge_weighted.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/agglomeration.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/breadth_first_search.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/connected_components.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/detail/fusion_contract.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/edge_weighted_watershed.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/feature_accumulation.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/grid_edge_projection.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/grid_features.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/grid_graph.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/label_accumulation.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_from_affinities.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut/detail.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut/fusion_move.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut/greedy_additive.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut/kernighan_lin.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut/lifted_from_node_labels.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut/objective.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/lifted_multicut.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut/detail.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut/fusion_move.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut/greedy_additive.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut/greedy_fixation.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut/kernighan_lin.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut/objective.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/multicut.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/mutex_watershed/clustering.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/mutex_watershed/semantic.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/mutex_watershed.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/node_label_projection.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/proposal_generator.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/proposal_generators/greedy_additive_multicut.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/proposal_generators/watershed.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/rag_coordinates.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/region_adjacency_graph.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/graph/undirected_graph.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/label_multiset/downsample.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/label_multiset/from_labels.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/label_multiset/merger.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/label_multiset/multiset.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/label_multiset/read_subset.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/mesh_smoothing.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/non_maximum_distance_suppression.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/overlap.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/run_length.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/segmentation/connected_components.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/segmentation/mutex_watershed.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/segmentation/relabel_sequential.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/segmentation/semantic_mutex_watershed.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/segmentation/watershed.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/take_dict.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/include/bioimage_cpp/util/union_find.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/pyproject.toml +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/affinities.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/affinities.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/blocking.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/blocking.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/distance.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/distance.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/filters.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/filters.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/flow.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/flow.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/graph.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/graph.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/ground_truth.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/ground_truth.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/label_multiset.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/label_multiset.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/module.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/segmentation.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/segmentation.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/transformation.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/util.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/util.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/utils.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bindings/utils.hxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/_data.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/affinities/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/affinities/compute_affinities.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/affinities/compute_embedding_distances.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/distance/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/distance/_distance.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/filters/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/filters/_filters.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/flow/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/flow/_flow.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/_external.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/_shared.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/agglomeration.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/features/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/lifted_multicut/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/multicut/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/graph/mutex_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/label_multiset/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/segmentation/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/segmentation/label.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/segmentation/mutex_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/segmentation/relabel_sequential.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/segmentation/watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/utils.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/cpp/segmentation/mutex_watershed.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/cpp/segmentation/semantic_mutex_watershed.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/cpp/take_dict.cxx +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/affinities/test_compute_affinities.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/affinities/test_compute_embedding_distances.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/distance/test_distance_transform.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/distance/test_non_maximum_distance_suppression.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/agglomeration/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/agglomeration/_helpers.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/agglomeration/test_edge_weighted.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/agglomeration/test_gasp.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/agglomeration/test_mala.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/agglomeration/test_node_and_edge_weighted.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/_helpers.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/conftest.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/test_external_problem.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/test_fusion_move.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/test_greedy_additive.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/test_kernighan_lin.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/test_lifted_edges_from_node_labels.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/lifted_multicut/test_objective.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/_helpers.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/conftest.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_chain_decomposer.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_external_problem.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_fusion_move.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_greedy_additive.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_greedy_fixation.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_kernighan_lin.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_objective.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/multicut/test_proposal_generators.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_breadth_first_search.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_connected_components.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_edge_weighted_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_grid_affinity_multicut_integration.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_grid_features.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_grid_graph.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_mutex_watershed_graph.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_node_label_projection.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_rag_accumulate_labels.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_rag_coordinates.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_rag_features.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_rag_lifted_features.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_rag_multicut_integration.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_region_adjacency_graph.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_semantic_mutex_watershed_graph.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/graph/test_undirected_graph.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/label_multiset/__init__.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/label_multiset/test_against_nifty.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/label_multiset/test_downsample.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/label_multiset/test_merger.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/label_multiset/test_read_subset.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/segmentation/test_label.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/segmentation/test_mutex_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/segmentation/test_relabel_sequential.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/segmentation/test_semantic_mutex_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/segmentation/test_watershed.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/segmentation/test_watershed_from_affinities.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_blocking.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_filters.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_flow.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_ground_truth_overlap.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_util_union_find.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_utils_compute_rle.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_utils_mesh_smoothing.py +0 -0
- {bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/tests/test_utils_take_dict.py +0 -0
|
@@ -495,6 +495,40 @@ inline double cubic_3d(
|
|
|
495
495
|
return value;
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
+
// Dispatch to the per-voxel sampler for the requested interpolation order. Shared by the affine and
|
|
499
|
+
// map_coordinates kernels so the interpolation backend lives in exactly one place. `order` must be in
|
|
500
|
+
// 0..5 (validated by the public entry points before the sampling loop).
|
|
501
|
+
template <class T>
|
|
502
|
+
inline double sample_2d(
|
|
503
|
+
const T *data, std::ptrdiff_t in_h, std::ptrdiff_t in_w,
|
|
504
|
+
double cy, double cx, const int order, double fill
|
|
505
|
+
) {
|
|
506
|
+
switch (order) {
|
|
507
|
+
case 0: return nearest_2d(data, in_h, in_w, cy, cx, fill);
|
|
508
|
+
case 1: return linear_2d(data, in_h, in_w, cy, cx, fill);
|
|
509
|
+
case 2: return bspline_2d<2>(data, in_h, in_w, cy, cx, fill);
|
|
510
|
+
case 3: return cubic_2d(data, in_h, in_w, cy, cx, fill);
|
|
511
|
+
case 4: return bspline_2d<4>(data, in_h, in_w, cy, cx, fill);
|
|
512
|
+
default: return bspline_2d<5>(data, in_h, in_w, cy, cx, fill); // 5
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
template <class T>
|
|
517
|
+
inline double sample_3d(
|
|
518
|
+
const T *data,
|
|
519
|
+
std::ptrdiff_t in_d, std::ptrdiff_t in_h, std::ptrdiff_t in_w,
|
|
520
|
+
double cz, double cy, double cx, const int order, double fill
|
|
521
|
+
) {
|
|
522
|
+
switch (order) {
|
|
523
|
+
case 0: return nearest_3d(data, in_d, in_h, in_w, cz, cy, cx, fill);
|
|
524
|
+
case 1: return linear_3d(data, in_d, in_h, in_w, cz, cy, cx, fill);
|
|
525
|
+
case 2: return bspline_3d<2>(data, in_d, in_h, in_w, cz, cy, cx, fill);
|
|
526
|
+
case 3: return cubic_3d(data, in_d, in_h, in_w, cz, cy, cx, fill);
|
|
527
|
+
case 4: return bspline_3d<4>(data, in_d, in_h, in_w, cz, cy, cx, fill);
|
|
528
|
+
default: return bspline_3d<5>(data, in_d, in_h, in_w, cz, cy, cx, fill); // 5
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
498
532
|
} // namespace detail
|
|
499
533
|
|
|
500
534
|
// ----- 2D entry point -------------------------------------------------------
|
|
@@ -554,27 +588,7 @@ void affine_transform_2d(
|
|
|
554
588
|
double cy = row_y;
|
|
555
589
|
double cx = row_x;
|
|
556
590
|
for (std::ptrdiff_t j = 0; j < out_w; ++j) {
|
|
557
|
-
double value;
|
|
558
|
-
switch (order) {
|
|
559
|
-
case 0:
|
|
560
|
-
value = detail::nearest_2d(in_data, in_h, in_w, cy, cx, fill);
|
|
561
|
-
break;
|
|
562
|
-
case 1:
|
|
563
|
-
value = detail::linear_2d(in_data, in_h, in_w, cy, cx, fill);
|
|
564
|
-
break;
|
|
565
|
-
case 2:
|
|
566
|
-
value = detail::bspline_2d<2>(in_data, in_h, in_w, cy, cx, fill);
|
|
567
|
-
break;
|
|
568
|
-
case 3:
|
|
569
|
-
value = detail::cubic_2d(in_data, in_h, in_w, cy, cx, fill);
|
|
570
|
-
break;
|
|
571
|
-
case 4:
|
|
572
|
-
value = detail::bspline_2d<4>(in_data, in_h, in_w, cy, cx, fill);
|
|
573
|
-
break;
|
|
574
|
-
default: // 5
|
|
575
|
-
value = detail::bspline_2d<5>(in_data, in_h, in_w, cy, cx, fill);
|
|
576
|
-
break;
|
|
577
|
-
}
|
|
591
|
+
const double value = detail::sample_2d(in_data, in_h, in_w, cy, cx, order, fill);
|
|
578
592
|
*out_ptr++ = detail::to_output<T>(value);
|
|
579
593
|
cy += m01;
|
|
580
594
|
cx += m11;
|
|
@@ -655,33 +669,8 @@ void affine_transform_3d(
|
|
|
655
669
|
double cy = row_y;
|
|
656
670
|
double cx = row_x;
|
|
657
671
|
for (std::ptrdiff_t j = 0; j < out_w; ++j) {
|
|
658
|
-
double value
|
|
659
|
-
|
|
660
|
-
case 0:
|
|
661
|
-
value = detail::nearest_3d(in_data, in_d, in_h, in_w,
|
|
662
|
-
cz, cy, cx, fill);
|
|
663
|
-
break;
|
|
664
|
-
case 1:
|
|
665
|
-
value = detail::linear_3d(in_data, in_d, in_h, in_w,
|
|
666
|
-
cz, cy, cx, fill);
|
|
667
|
-
break;
|
|
668
|
-
case 2:
|
|
669
|
-
value = detail::bspline_3d<2>(in_data, in_d, in_h, in_w,
|
|
670
|
-
cz, cy, cx, fill);
|
|
671
|
-
break;
|
|
672
|
-
case 3:
|
|
673
|
-
value = detail::cubic_3d(in_data, in_d, in_h, in_w,
|
|
674
|
-
cz, cy, cx, fill);
|
|
675
|
-
break;
|
|
676
|
-
case 4:
|
|
677
|
-
value = detail::bspline_3d<4>(in_data, in_d, in_h, in_w,
|
|
678
|
-
cz, cy, cx, fill);
|
|
679
|
-
break;
|
|
680
|
-
default: // 5
|
|
681
|
-
value = detail::bspline_3d<5>(in_data, in_d, in_h, in_w,
|
|
682
|
-
cz, cy, cx, fill);
|
|
683
|
-
break;
|
|
684
|
-
}
|
|
672
|
+
const double value = detail::sample_3d(in_data, in_d, in_h, in_w,
|
|
673
|
+
cz, cy, cx, order, fill);
|
|
685
674
|
*out_ptr++ = detail::to_output<T>(value);
|
|
686
675
|
cz += m02;
|
|
687
676
|
cy += m12;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Coordinate-based resampling (the analogue of ``scipy.ndimage.map_coordinates``). For every output
|
|
4
|
+
// voxel the source coordinate to sample is read from an explicit ``coordinates`` array, instead of
|
|
5
|
+
// being computed from an affine matrix. The per-voxel interpolation reuses the affine samplers
|
|
6
|
+
// (``detail::sample_2d`` / ``detail::sample_3d``) so the interpolation backend lives in one place.
|
|
7
|
+
//
|
|
8
|
+
// This kernel is pure and in-memory (NumPy in, NumPy out); reading the source data and producing the
|
|
9
|
+
// coordinate (deformation) field are the caller's responsibility.
|
|
10
|
+
|
|
11
|
+
#include "bioimage_cpp/transformation/affine.hxx"
|
|
12
|
+
|
|
13
|
+
namespace bioimage_cpp::transformation {
|
|
14
|
+
|
|
15
|
+
namespace detail {
|
|
16
|
+
|
|
17
|
+
// Validate that ``coordinates`` is a ``(D, *output_shape)`` field, i.e. it carries one source
|
|
18
|
+
// coordinate per output voxel along its leading axis.
|
|
19
|
+
template <std::size_t D, class T>
|
|
20
|
+
void require_coordinates(const ConstArrayView<double> &coordinates, const ArrayView<T> &output) {
|
|
21
|
+
if (coordinates.ndim() != static_cast<std::ptrdiff_t>(D + 1)) {
|
|
22
|
+
throw std::invalid_argument(
|
|
23
|
+
"coordinates must have ndim=" + std::to_string(D + 1) +
|
|
24
|
+
", got ndim=" + std::to_string(coordinates.ndim())
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
if (coordinates.shape[0] != static_cast<std::ptrdiff_t>(D)) {
|
|
28
|
+
throw std::invalid_argument(
|
|
29
|
+
"coordinates.shape[0] must equal the data dimension " + std::to_string(D) +
|
|
30
|
+
", got " + std::to_string(coordinates.shape[0])
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
for (std::size_t axis = 0; axis < D; ++axis) {
|
|
34
|
+
if (coordinates.shape[axis + 1] != output.shape[axis]) {
|
|
35
|
+
throw std::invalid_argument(
|
|
36
|
+
"coordinates spatial shape (coordinates.shape[1:]) must match the output shape"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
} // namespace detail
|
|
43
|
+
|
|
44
|
+
// ----- 2D entry point -------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
template <class T>
|
|
47
|
+
void map_coordinates_2d(
|
|
48
|
+
const ConstArrayView<T> &input,
|
|
49
|
+
ArrayView<T> &output,
|
|
50
|
+
const ConstArrayView<double> &coordinates,
|
|
51
|
+
const int order,
|
|
52
|
+
const T fill_value
|
|
53
|
+
) {
|
|
54
|
+
detail::require_views<2, T>(input, output);
|
|
55
|
+
detail::require_coordinates<2, T>(coordinates, output);
|
|
56
|
+
if (order < 0 || order > 5) {
|
|
57
|
+
throw std::invalid_argument(
|
|
58
|
+
"order must be in 0..5, got " + std::to_string(order)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const auto out_h = output.shape[0];
|
|
63
|
+
const auto out_w = output.shape[1];
|
|
64
|
+
if (out_h == 0 || out_w == 0) return;
|
|
65
|
+
|
|
66
|
+
const auto in_h = input.shape[0];
|
|
67
|
+
const auto in_w = input.shape[1];
|
|
68
|
+
|
|
69
|
+
// coordinates is C-contiguous with shape (2, out_h, out_w), so axis-d coordinates form a
|
|
70
|
+
// contiguous block of n_out doubles starting at d * n_out.
|
|
71
|
+
const std::ptrdiff_t n_out = out_h * out_w;
|
|
72
|
+
const double *cy = coordinates.data;
|
|
73
|
+
const double *cx = coordinates.data + n_out;
|
|
74
|
+
|
|
75
|
+
const double fill = static_cast<double>(fill_value);
|
|
76
|
+
const T *in_data = input.data;
|
|
77
|
+
T *out_ptr = output.data;
|
|
78
|
+
|
|
79
|
+
for (std::ptrdiff_t p = 0; p < n_out; ++p) {
|
|
80
|
+
const double value = detail::sample_2d(in_data, in_h, in_w, cy[p], cx[p], order, fill);
|
|
81
|
+
out_ptr[p] = detail::to_output<T>(value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ----- 3D entry point -------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
template <class T>
|
|
88
|
+
void map_coordinates_3d(
|
|
89
|
+
const ConstArrayView<T> &input,
|
|
90
|
+
ArrayView<T> &output,
|
|
91
|
+
const ConstArrayView<double> &coordinates,
|
|
92
|
+
const int order,
|
|
93
|
+
const T fill_value
|
|
94
|
+
) {
|
|
95
|
+
detail::require_views<3, T>(input, output);
|
|
96
|
+
detail::require_coordinates<3, T>(coordinates, output);
|
|
97
|
+
if (order < 0 || order > 5) {
|
|
98
|
+
throw std::invalid_argument(
|
|
99
|
+
"order must be in 0..5, got " + std::to_string(order)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const auto out_d = output.shape[0];
|
|
104
|
+
const auto out_h = output.shape[1];
|
|
105
|
+
const auto out_w = output.shape[2];
|
|
106
|
+
if (out_d == 0 || out_h == 0 || out_w == 0) return;
|
|
107
|
+
|
|
108
|
+
const auto in_d = input.shape[0];
|
|
109
|
+
const auto in_h = input.shape[1];
|
|
110
|
+
const auto in_w = input.shape[2];
|
|
111
|
+
|
|
112
|
+
// coordinates is C-contiguous with shape (3, out_d, out_h, out_w).
|
|
113
|
+
const std::ptrdiff_t n_out = out_d * out_h * out_w;
|
|
114
|
+
const double *cz = coordinates.data;
|
|
115
|
+
const double *cy = coordinates.data + n_out;
|
|
116
|
+
const double *cx = coordinates.data + 2 * n_out;
|
|
117
|
+
|
|
118
|
+
const double fill = static_cast<double>(fill_value);
|
|
119
|
+
const T *in_data = input.data;
|
|
120
|
+
T *out_ptr = output.data;
|
|
121
|
+
|
|
122
|
+
for (std::ptrdiff_t p = 0; p < n_out; ++p) {
|
|
123
|
+
const double value = detail::sample_3d(in_data, in_d, in_h, in_w,
|
|
124
|
+
cz[p], cy[p], cx[p], order, fill);
|
|
125
|
+
out_ptr[p] = detail::to_output<T>(value);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
} // namespace bioimage_cpp::transformation
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include "bioimage_cpp/array_view.hxx"
|
|
4
4
|
#include "bioimage_cpp/detail/grid.hxx"
|
|
5
5
|
#include "bioimage_cpp/transformation/affine.hxx"
|
|
6
|
+
#include "bioimage_cpp/transformation/coordinate.hxx"
|
|
6
7
|
|
|
7
8
|
#include <nanobind/ndarray.h>
|
|
8
9
|
|
|
@@ -113,6 +114,86 @@ void bind_affine_for_dtype(nb::module_ &m, const char *name_2d, const char *name
|
|
|
113
114
|
);
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
template <std::size_t D, class T>
|
|
118
|
+
OutputArray<T> map_coordinates_t(
|
|
119
|
+
ConstArray<T> input,
|
|
120
|
+
MatrixArray coordinates,
|
|
121
|
+
OutputArray<T> output,
|
|
122
|
+
const int order,
|
|
123
|
+
const T fill_value
|
|
124
|
+
) {
|
|
125
|
+
if (input.ndim() != D) {
|
|
126
|
+
throw std::invalid_argument(
|
|
127
|
+
"input must have ndim=" + std::to_string(D) +
|
|
128
|
+
", got ndim=" + std::to_string(input.ndim())
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (output.ndim() != D) {
|
|
132
|
+
throw std::invalid_argument(
|
|
133
|
+
"output must have ndim=" + std::to_string(D) +
|
|
134
|
+
", got ndim=" + std::to_string(output.ndim())
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (coordinates.ndim() != D + 1) {
|
|
138
|
+
throw std::invalid_argument(
|
|
139
|
+
"coordinates must have ndim=" + std::to_string(D + 1) +
|
|
140
|
+
", got ndim=" + std::to_string(coordinates.ndim())
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const auto input_shape = shape_of(input);
|
|
145
|
+
const auto input_strides = detail::c_order_strides(input_shape);
|
|
146
|
+
const auto coordinates_shape = shape_of(coordinates);
|
|
147
|
+
const auto coordinates_strides = detail::c_order_strides(coordinates_shape);
|
|
148
|
+
const auto output_shape = shape_of(output);
|
|
149
|
+
const auto output_strides = detail::c_order_strides(output_shape);
|
|
150
|
+
|
|
151
|
+
ConstArrayView<T> input_view{input.data(), input_shape, input_strides};
|
|
152
|
+
ArrayView<T> output_view{output.data(), output_shape, output_strides};
|
|
153
|
+
ConstArrayView<double> coordinates_view{
|
|
154
|
+
coordinates.data(), coordinates_shape, coordinates_strides
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
{
|
|
158
|
+
nb::gil_scoped_release release;
|
|
159
|
+
if constexpr (D == 2) {
|
|
160
|
+
transformation::map_coordinates_2d<T>(
|
|
161
|
+
input_view, output_view, coordinates_view, order, fill_value
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
transformation::map_coordinates_3d<T>(
|
|
165
|
+
input_view, output_view, coordinates_view, order, fill_value
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return output;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
template <class T>
|
|
174
|
+
void bind_map_coordinates_for_dtype(nb::module_ &m, const char *name_2d, const char *name_3d) {
|
|
175
|
+
m.def(
|
|
176
|
+
name_2d,
|
|
177
|
+
&map_coordinates_t<2, T>,
|
|
178
|
+
nb::arg("input"),
|
|
179
|
+
nb::arg("coordinates"),
|
|
180
|
+
nb::arg("output"),
|
|
181
|
+
nb::arg("order"),
|
|
182
|
+
nb::arg("fill_value"),
|
|
183
|
+
"Apply a 2D coordinate-based resampling into a pre-allocated NumPy array."
|
|
184
|
+
);
|
|
185
|
+
m.def(
|
|
186
|
+
name_3d,
|
|
187
|
+
&map_coordinates_t<3, T>,
|
|
188
|
+
nb::arg("input"),
|
|
189
|
+
nb::arg("coordinates"),
|
|
190
|
+
nb::arg("output"),
|
|
191
|
+
nb::arg("order"),
|
|
192
|
+
nb::arg("fill_value"),
|
|
193
|
+
"Apply a 3D coordinate-based resampling into a pre-allocated NumPy array."
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
116
197
|
} // namespace
|
|
117
198
|
|
|
118
199
|
void bind_transformation(nb::module_ &m) {
|
|
@@ -146,6 +227,37 @@ void bind_transformation(nb::module_ &m) {
|
|
|
146
227
|
bind_affine_for_dtype<double>(
|
|
147
228
|
m, "_affine_transform_2d_float64", "_affine_transform_3d_float64"
|
|
148
229
|
);
|
|
230
|
+
|
|
231
|
+
bind_map_coordinates_for_dtype<std::uint8_t>(
|
|
232
|
+
m, "_map_coordinates_2d_uint8", "_map_coordinates_3d_uint8"
|
|
233
|
+
);
|
|
234
|
+
bind_map_coordinates_for_dtype<std::uint16_t>(
|
|
235
|
+
m, "_map_coordinates_2d_uint16", "_map_coordinates_3d_uint16"
|
|
236
|
+
);
|
|
237
|
+
bind_map_coordinates_for_dtype<std::uint32_t>(
|
|
238
|
+
m, "_map_coordinates_2d_uint32", "_map_coordinates_3d_uint32"
|
|
239
|
+
);
|
|
240
|
+
bind_map_coordinates_for_dtype<std::uint64_t>(
|
|
241
|
+
m, "_map_coordinates_2d_uint64", "_map_coordinates_3d_uint64"
|
|
242
|
+
);
|
|
243
|
+
bind_map_coordinates_for_dtype<std::int8_t>(
|
|
244
|
+
m, "_map_coordinates_2d_int8", "_map_coordinates_3d_int8"
|
|
245
|
+
);
|
|
246
|
+
bind_map_coordinates_for_dtype<std::int16_t>(
|
|
247
|
+
m, "_map_coordinates_2d_int16", "_map_coordinates_3d_int16"
|
|
248
|
+
);
|
|
249
|
+
bind_map_coordinates_for_dtype<std::int32_t>(
|
|
250
|
+
m, "_map_coordinates_2d_int32", "_map_coordinates_3d_int32"
|
|
251
|
+
);
|
|
252
|
+
bind_map_coordinates_for_dtype<std::int64_t>(
|
|
253
|
+
m, "_map_coordinates_2d_int64", "_map_coordinates_3d_int64"
|
|
254
|
+
);
|
|
255
|
+
bind_map_coordinates_for_dtype<float>(
|
|
256
|
+
m, "_map_coordinates_2d_float32", "_map_coordinates_3d_float32"
|
|
257
|
+
);
|
|
258
|
+
bind_map_coordinates_for_dtype<double>(
|
|
259
|
+
m, "_map_coordinates_2d_float64", "_map_coordinates_3d_float64"
|
|
260
|
+
);
|
|
149
261
|
}
|
|
150
262
|
|
|
151
263
|
} // namespace bioimage_cpp::bindings
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.5.0"
|
{bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/src/bioimage_cpp/transformation/_transformation.py
RENAMED
|
@@ -36,6 +36,32 @@ _AFFINE_3D_BY_DTYPE = {
|
|
|
36
36
|
np.dtype("float64"): _core._affine_transform_3d_float64,
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
_MAP_COORDINATES_2D_BY_DTYPE = {
|
|
40
|
+
np.dtype("uint8"): _core._map_coordinates_2d_uint8,
|
|
41
|
+
np.dtype("uint16"): _core._map_coordinates_2d_uint16,
|
|
42
|
+
np.dtype("uint32"): _core._map_coordinates_2d_uint32,
|
|
43
|
+
np.dtype("uint64"): _core._map_coordinates_2d_uint64,
|
|
44
|
+
np.dtype("int8"): _core._map_coordinates_2d_int8,
|
|
45
|
+
np.dtype("int16"): _core._map_coordinates_2d_int16,
|
|
46
|
+
np.dtype("int32"): _core._map_coordinates_2d_int32,
|
|
47
|
+
np.dtype("int64"): _core._map_coordinates_2d_int64,
|
|
48
|
+
np.dtype("float32"): _core._map_coordinates_2d_float32,
|
|
49
|
+
np.dtype("float64"): _core._map_coordinates_2d_float64,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_MAP_COORDINATES_3D_BY_DTYPE = {
|
|
53
|
+
np.dtype("uint8"): _core._map_coordinates_3d_uint8,
|
|
54
|
+
np.dtype("uint16"): _core._map_coordinates_3d_uint16,
|
|
55
|
+
np.dtype("uint32"): _core._map_coordinates_3d_uint32,
|
|
56
|
+
np.dtype("uint64"): _core._map_coordinates_3d_uint64,
|
|
57
|
+
np.dtype("int8"): _core._map_coordinates_3d_int8,
|
|
58
|
+
np.dtype("int16"): _core._map_coordinates_3d_int16,
|
|
59
|
+
np.dtype("int32"): _core._map_coordinates_3d_int32,
|
|
60
|
+
np.dtype("int64"): _core._map_coordinates_3d_int64,
|
|
61
|
+
np.dtype("float32"): _core._map_coordinates_3d_float32,
|
|
62
|
+
np.dtype("float64"): _core._map_coordinates_3d_float64,
|
|
63
|
+
}
|
|
64
|
+
|
|
39
65
|
|
|
40
66
|
def _normalize_matrix(matrix, ndim: int) -> np.ndarray:
|
|
41
67
|
array = np.asarray(matrix, dtype=np.float64)
|
|
@@ -340,3 +366,83 @@ def affine_transform(
|
|
|
340
366
|
output = _validate_or_allocate_out(out, output_shape, dtype)
|
|
341
367
|
run(contiguous, normalized_matrix, starts, output, order, typed_fill)
|
|
342
368
|
return output
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _normalize_coordinates(coordinates, ndim: int) -> tuple[np.ndarray, tuple[int, ...]]:
|
|
372
|
+
array = np.ascontiguousarray(coordinates, dtype=np.float64)
|
|
373
|
+
if array.ndim != ndim + 1:
|
|
374
|
+
raise ValueError(
|
|
375
|
+
f"coordinates must have ndim={ndim + 1} (a leading axis of length {ndim} plus the "
|
|
376
|
+
f"output shape), got ndim={array.ndim}"
|
|
377
|
+
)
|
|
378
|
+
if array.shape[0] != ndim:
|
|
379
|
+
raise ValueError(
|
|
380
|
+
f"coordinates.shape[0] must equal the data dimension {ndim}, got {array.shape[0]}"
|
|
381
|
+
)
|
|
382
|
+
output_shape = tuple(int(s) for s in array.shape[1:])
|
|
383
|
+
return array, output_shape
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def map_coordinates(
|
|
387
|
+
data: np.ndarray,
|
|
388
|
+
coordinates,
|
|
389
|
+
*,
|
|
390
|
+
order: int = 1,
|
|
391
|
+
fill_value: Number = 0,
|
|
392
|
+
out: np.ndarray | None = None,
|
|
393
|
+
) -> np.ndarray:
|
|
394
|
+
"""Resample a 2D or 3D array at explicit, per-output-voxel source coordinates.
|
|
395
|
+
|
|
396
|
+
Like ``scipy.ndimage.map_coordinates``, but specialized to a same-rank resampling: for each
|
|
397
|
+
output voxel the source coordinate to sample is read from ``coordinates`` and the input is
|
|
398
|
+
interpolated there. ``coordinates`` has shape ``(ndim, *output_shape)`` in NumPy axis order, so
|
|
399
|
+
``coordinates[d]`` holds the axis-``d`` source coordinate of every output voxel. The output has
|
|
400
|
+
the same number of dimensions as ``data`` (a 2D or 3D resampling), so ``output_shape`` =
|
|
401
|
+
``coordinates.shape[1:]`` has ``ndim`` entries. This is the deformation-field counterpart of
|
|
402
|
+
:func:`affine_transform` (which derives the same per-voxel source coordinate from an affine
|
|
403
|
+
matrix) and shares its interpolation backend.
|
|
404
|
+
|
|
405
|
+
Supported interpolation orders match :func:`affine_transform`:
|
|
406
|
+
|
|
407
|
+
- ``0`` — nearest neighbour.
|
|
408
|
+
- ``1`` — linear (bi-/tri-linear).
|
|
409
|
+
- ``2`` — quadratic B-spline (3 taps per axis).
|
|
410
|
+
- ``3`` — local Keys cubic convolution (4 taps; Catmull-Rom, ``a=-0.5``); reproduces input
|
|
411
|
+
exactly at integer coordinates.
|
|
412
|
+
- ``4`` — quartic B-spline (5 taps per axis).
|
|
413
|
+
- ``5`` — quintic B-spline (6 taps per axis).
|
|
414
|
+
|
|
415
|
+
Orders ``2``, ``4``, ``5`` evaluate the cardinal B-spline kernel directly on the input samples
|
|
416
|
+
(no prefilter); they are low-pass smoothing, not interpolating. See :func:`affine_transform`
|
|
417
|
+
for the full discussion.
|
|
418
|
+
|
|
419
|
+
The output preserves the input dtype; integer outputs round to nearest and clamp to the dtype
|
|
420
|
+
range. Coordinates that map outside the input contribute ``fill_value``.
|
|
421
|
+
|
|
422
|
+
Pass a pre-allocated, C-contiguous, writable NumPy array as ``out`` to write the result in
|
|
423
|
+
place; it must have shape ``coordinates.shape[1:]`` and dtype equal to ``data.dtype``.
|
|
424
|
+
"""
|
|
425
|
+
array = np.asarray(data)
|
|
426
|
+
if array.ndim not in (2, 3):
|
|
427
|
+
raise ValueError(f"data must be 2D or 3D, got ndim={array.ndim}")
|
|
428
|
+
|
|
429
|
+
order = int(order)
|
|
430
|
+
if order not in (0, 1, 2, 3, 4, 5):
|
|
431
|
+
raise ValueError(f"order must be in 0..5, got {order}")
|
|
432
|
+
|
|
433
|
+
table = _MAP_COORDINATES_2D_BY_DTYPE if array.ndim == 2 else _MAP_COORDINATES_3D_BY_DTYPE
|
|
434
|
+
dtype = array.dtype
|
|
435
|
+
try:
|
|
436
|
+
run = table[dtype]
|
|
437
|
+
except KeyError as error:
|
|
438
|
+
supported = ", ".join(str(name) for name in table)
|
|
439
|
+
raise TypeError(
|
|
440
|
+
f"data must have one of dtypes ({supported}), got dtype={dtype}"
|
|
441
|
+
) from error
|
|
442
|
+
|
|
443
|
+
coords, output_shape = _normalize_coordinates(coordinates, array.ndim)
|
|
444
|
+
contiguous = np.ascontiguousarray(array)
|
|
445
|
+
typed_fill = _normalize_fill_value(fill_value, dtype)
|
|
446
|
+
output = _validate_or_allocate_out(out, output_shape, dtype)
|
|
447
|
+
run(contiguous, coords, output, order, typed_fill)
|
|
448
|
+
return output
|
|
@@ -408,3 +408,124 @@ def test_invalid_inputs_raise():
|
|
|
408
408
|
bic.transformation.affine_transform(data, _matrix(2), bounding_box=(slice(None, None, 2), slice(None)))
|
|
409
409
|
with pytest.raises(TypeError, match="dtype"):
|
|
410
410
|
bic.transformation.affine_transform(np.zeros((4, 4), dtype=np.bool_), _matrix(2))
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
# ---------------------------------------------------------------------------
|
|
414
|
+
# map_coordinates
|
|
415
|
+
# ---------------------------------------------------------------------------
|
|
416
|
+
|
|
417
|
+
_ALL_DTYPES = [
|
|
418
|
+
np.uint8, np.uint16, np.uint32, np.uint64,
|
|
419
|
+
np.int8, np.int16, np.int32, np.int64,
|
|
420
|
+
np.float32, np.float64,
|
|
421
|
+
]
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _affine_coords(matrix, shape):
|
|
425
|
+
"""The (ndim, *shape) coordinate field that reproduces `matrix` as an explicit deformation."""
|
|
426
|
+
ndim = len(shape)
|
|
427
|
+
grid = np.indices(shape, dtype=np.float64)
|
|
428
|
+
coords = np.empty_like(grid)
|
|
429
|
+
for d in range(ndim):
|
|
430
|
+
acc = np.full(shape, matrix[d, ndim], dtype=np.float64)
|
|
431
|
+
for k in range(ndim):
|
|
432
|
+
acc = acc + matrix[d, k] * grid[k]
|
|
433
|
+
coords[d] = acc
|
|
434
|
+
return coords
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
@pytest.mark.parametrize("order", [0, 1, 2, 3, 4, 5])
|
|
438
|
+
@pytest.mark.parametrize("dtype", _ALL_DTYPES)
|
|
439
|
+
def test_map_coordinates_matches_affine_2d(order, dtype):
|
|
440
|
+
# A coordinate field built from an affine matrix must reproduce affine_transform exactly: same
|
|
441
|
+
# interpolation backend, so the results are bit-identical for every order and dtype.
|
|
442
|
+
data = (np.arange(5 * 7) % 17).astype(dtype).reshape(5, 7)
|
|
443
|
+
matrix = _matrix(2, translation=[0.5, -1.25])
|
|
444
|
+
coords = _affine_coords(matrix, data.shape)
|
|
445
|
+
got = bic.transformation.map_coordinates(data, coords, order=order, fill_value=0)
|
|
446
|
+
ref = bic.transformation.affine_transform(data, matrix, order=order, fill_value=0)
|
|
447
|
+
np.testing.assert_array_equal(got, ref)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
@pytest.mark.parametrize("order", [0, 1, 2, 3, 4, 5])
|
|
451
|
+
@pytest.mark.parametrize("dtype", [np.uint8, np.uint16, np.int32, np.float32, np.float64])
|
|
452
|
+
def test_map_coordinates_matches_affine_3d(order, dtype):
|
|
453
|
+
data = (np.arange(4 * 5 * 6) % 13).astype(dtype).reshape(4, 5, 6)
|
|
454
|
+
matrix = _matrix(3, translation=[0.25, -0.5, 1.0])
|
|
455
|
+
coords = _affine_coords(matrix, data.shape)
|
|
456
|
+
got = bic.transformation.map_coordinates(data, coords, order=order, fill_value=0)
|
|
457
|
+
ref = bic.transformation.affine_transform(data, matrix, order=order, fill_value=0)
|
|
458
|
+
np.testing.assert_array_equal(got, ref)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
@pytest.mark.parametrize("order", [0, 1])
|
|
462
|
+
@pytest.mark.parametrize("ndim", [2, 3])
|
|
463
|
+
def test_map_coordinates_matches_scipy(order, ndim):
|
|
464
|
+
sp = pytest.importorskip("scipy.ndimage")
|
|
465
|
+
rng = np.random.default_rng(0)
|
|
466
|
+
shape = (9, 11) if ndim == 2 else (6, 7, 8)
|
|
467
|
+
data = rng.random(shape).astype(np.float64)
|
|
468
|
+
# random source coordinates strictly inside the volume, so boundary handling is not involved.
|
|
469
|
+
coords = np.stack([rng.uniform(1.0, s - 2.0, size=shape) for s in shape])
|
|
470
|
+
got = bic.transformation.map_coordinates(data, coords, order=order)
|
|
471
|
+
ref = sp.map_coordinates(data, coords, order=order, mode="nearest", prefilter=False)
|
|
472
|
+
np.testing.assert_allclose(got, ref, atol=1e-6)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
@pytest.mark.parametrize("order", [0, 1, 3])
|
|
476
|
+
@pytest.mark.parametrize("shape", [(5, 7), (4, 5, 6)])
|
|
477
|
+
def test_map_coordinates_identity_round_trip(order, shape):
|
|
478
|
+
# Sampling at the integer grid reproduces the input exactly for the interpolating orders.
|
|
479
|
+
data = np.arange(int(np.prod(shape)), dtype=np.float32).reshape(shape)
|
|
480
|
+
coords = np.indices(shape, dtype=np.float64)
|
|
481
|
+
got = bic.transformation.map_coordinates(data, coords, order=order, fill_value=-1)
|
|
482
|
+
np.testing.assert_array_equal(got, data)
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
@pytest.mark.parametrize("order", [0, 1, 3])
|
|
486
|
+
def test_map_coordinates_out_of_bounds_uses_fill(order):
|
|
487
|
+
data = np.arange(16, dtype=np.float32).reshape(4, 4)
|
|
488
|
+
coords = np.full((2, 3, 3), -50.0) # every output voxel maps far outside the input
|
|
489
|
+
got = bic.transformation.map_coordinates(data, coords, order=order, fill_value=7.0)
|
|
490
|
+
np.testing.assert_array_equal(got, np.full((3, 3), 7.0, dtype=np.float32))
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def test_map_coordinates_writes_into_out():
|
|
494
|
+
data = np.arange(20, dtype=np.float64).reshape(4, 5)
|
|
495
|
+
coords = np.indices(data.shape, dtype=np.float64)
|
|
496
|
+
out = np.empty(data.shape, dtype=np.float64)
|
|
497
|
+
returned = bic.transformation.map_coordinates(data, coords, order=1, out=out)
|
|
498
|
+
assert returned is out
|
|
499
|
+
np.testing.assert_array_equal(out, data)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def test_map_coordinates_accepts_noncontiguous_coordinates():
|
|
503
|
+
data = np.arange(20, dtype=np.float64).reshape(4, 5)
|
|
504
|
+
matrix = _matrix(2, translation=[0.5, 0.5])
|
|
505
|
+
coords = _affine_coords(matrix, data.shape)
|
|
506
|
+
noncontig = np.asfortranarray(coords) # coerced to contiguous float64 internally
|
|
507
|
+
assert not noncontig.flags.c_contiguous
|
|
508
|
+
got = bic.transformation.map_coordinates(data, noncontig, order=1)
|
|
509
|
+
ref = bic.transformation.affine_transform(data, matrix, order=1)
|
|
510
|
+
np.testing.assert_array_equal(got, ref)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def test_map_coordinates_invalid_inputs_raise():
|
|
514
|
+
data = np.zeros((4, 5), dtype=np.float32)
|
|
515
|
+
good = np.indices(data.shape).astype(np.float64)
|
|
516
|
+
with pytest.raises(ValueError, match="2D or 3D"):
|
|
517
|
+
bic.transformation.map_coordinates(np.zeros((4,), dtype=np.float32), np.zeros((1, 4)))
|
|
518
|
+
with pytest.raises(ValueError, match="order"):
|
|
519
|
+
bic.transformation.map_coordinates(data, good, order=6)
|
|
520
|
+
# coordinates must have ndim == data.ndim + 1
|
|
521
|
+
with pytest.raises(ValueError, match="ndim"):
|
|
522
|
+
bic.transformation.map_coordinates(data, np.zeros((2, 4), dtype=np.float64))
|
|
523
|
+
# coordinates leading axis must equal data ndim
|
|
524
|
+
with pytest.raises(ValueError, match=r"shape\[0\]"):
|
|
525
|
+
bic.transformation.map_coordinates(data, np.zeros((3, 4, 5), dtype=np.float64))
|
|
526
|
+
with pytest.raises(TypeError, match="dtype"):
|
|
527
|
+
bic.transformation.map_coordinates(np.zeros((4, 5), dtype=np.bool_), good)
|
|
528
|
+
with pytest.raises(ValueError, match="shape"):
|
|
529
|
+
bic.transformation.map_coordinates(data, good, out=np.empty((3, 3), dtype=np.float32))
|
|
530
|
+
with pytest.raises(TypeError, match="dtype"):
|
|
531
|
+
bic.transformation.map_coordinates(data, good, out=np.empty((4, 5), dtype=np.float64))
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bioimage_cpp-0.4.0 → bioimage_cpp-0.5.0}/development/affinities/check_compute_affinities.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|