diff --git a/CMakeLists.txt b/CMakeLists.txt index 4148520e7b8adaa51f7cbadae02f828cf22e8174..856769139da280892e1a01d99cf4f83dd60fee13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,14 +22,12 @@ find_package(Eigen3 3.3 REQUIRED NO_MODULE) # make cache variables for install destinations include(GNUInstallDirs) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - if (DEFINED ENV{CONDA_PREFIX}) - set(CMAKE_INSTALL_LIBDIR "lib") - set(CMAKE_INSTALL_PREFIX "$ENV{CONDA_PREFIX}") - else() - set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install") - endif() -endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) +if (DEFINED ENV{CONDA_PREFIX}) + set(CMAKE_INSTALL_LIBDIR "lib") + set(CMAKE_INSTALL_PREFIX "$ENV{CONDA_PREFIX}") +else() + set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install") +endif() add_subdirectory(cpp) add_subdirectory(wrp) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 8c0ddac3188a98b2f07ba00cf63518ed31b4a785..80a241c95734744182ac0ba8b04006b6ab289514 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,9 +1,12 @@ project(_cpp) add_library(_cpp SHARED + CgalLabelledImage.h LabelledTetrahedralMesh.h + CgalLabelledImage.cpp LabelledTetrahedralMesh.cpp ) target_link_libraries(_cpp PUBLIC Eigen3::Eigen) +target_link_libraries(_cpp PUBLIC CGAL::CGAL) install(TARGETS _cpp DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") \ No newline at end of file diff --git a/cpp/CgalLabelledImage.cpp b/cpp/CgalLabelledImage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed754bac786d5353dbf01dd049109c36f9425392 --- /dev/null +++ b/cpp/CgalLabelledImage.cpp @@ -0,0 +1,25 @@ +#include <iostream> + +#include "CgalLabelledImage.h" + + +CGAL::Image_3 buildCgalImage(Eigen::Array<unsigned short, Eigen::Dynamic, 1> image_array, Eigen::Array<int, 3, 1> shape, Eigen::Array<double, 3, 1> voxelsize) +{ + _image* image = _createImage( + shape(0), shape(1), shape(2), 1, + voxelsize(0), voxelsize(1), voxelsize(2), 2, + WK_FIXED, SGN_UNSIGNED + ); + + auto it = image_array.begin(); + for (int x=0; x<shape(0); x++) { + for (int y=0; y<shape(1); y++) { + for (int z=0; z<shape(2); z++) { + CGAL::IMAGEIO::static_evaluate<unsigned short>(image, x, y, z) = *it; + ++it; + } + } + } + + return CGAL::Image_3(image); +} diff --git a/cpp/CgalLabelledImage.h b/cpp/CgalLabelledImage.h new file mode 100644 index 0000000000000000000000000000000000000000..ba288125b6cc28bddac3b9ca0f3637b9de98f7d6 --- /dev/null +++ b/cpp/CgalLabelledImage.h @@ -0,0 +1,8 @@ +#pragma once + +#include <CGAL/Image_3.h> + +#include <Eigen/Dense> + + +CGAL::Image_3 buildCgalImage(Eigen::Array<unsigned short, Eigen::Dynamic, 1> image_array, Eigen::Array<int, 3, 1> shape, Eigen::Array<double, 3, 1> voxelsize={1.0, 1.0, 1.0}); \ No newline at end of file diff --git a/src/pybind_example/labelled_tetrahedral_mesh.py b/src/pybind_example/labelled_tetrahedral_mesh.py index 7014b328d75f16f644535a5b3496a64e10863848..4699c0f0ec24f4d76310cb5c72baf992000b14ed 100644 --- a/src/pybind_example/labelled_tetrahedral_mesh.py +++ b/src/pybind_example/labelled_tetrahedral_mesh.py @@ -1 +1,10 @@ -from ._wrp import LabelledTetrahedralMesh, make_tetrahedron \ No newline at end of file +from typing import Iterable, Optional + +import numpy as np + +from ._wrp import LabelledTetrahedralMesh, make_tetrahedron +from ._wrp import build_cgal_image as _build_cgal_image + + +def build_cgal_image(img: np.ndarray, voxelsize: Optional[Iterable[float]]=(1., 1., 1.)) -> bool: + return _build_cgal_image(img.ravel().astype(np.uint16), img.shape, voxelsize) diff --git a/tests/test_cgal_image.py b/tests/test_cgal_image.py new file mode 100644 index 0000000000000000000000000000000000000000..9506048491d2ef6b7bd1eda014fdbed76da616fb --- /dev/null +++ b/tests/test_cgal_image.py @@ -0,0 +1,23 @@ +import unittest + +import numpy as np + +from pybind_example.labelled_tetrahedral_mesh import build_cgal_image + + +class TestCgalImage(unittest.TestCase): + + def setUp(self): + self.image = np.zeros((10, 8, 6), dtype=np.uint16) + self.image[:, :, 4:] = 1 + self.image[:, :4, :4] = 2 + self.image[:, 4:, :4] = 3 + + self.voxelsize = [0.5, 0.5, 1] + + def tearDown(self): + pass + + def test_cgal_image(self): + res = build_cgal_image(self.image, voxelsize=self.voxelsize) + assert res == 0 diff --git a/wrp/LabelledTetrahedralMeshWrapper.cpp b/wrp/LabelledTetrahedralMeshWrapper.cpp index 8fcc884ecf74ee2dc0adc1f19ac7aa2e41bdc846..744befaa7970b07c328b7915dc0e43d36e27d1f4 100644 --- a/wrp/LabelledTetrahedralMeshWrapper.cpp +++ b/wrp/LabelledTetrahedralMeshWrapper.cpp @@ -2,10 +2,21 @@ #include <pybind11/stl.h> // This header is needed to work with STL containers like std::vector #include <pybind11/eigen.h> +#include "CgalLabelledImage.h" #include "LabelledTetrahedralMesh.h" namespace py = pybind11; + +int cgalLabelledImage(Eigen::Array<unsigned short, Eigen::Dynamic, 1> image_array, Eigen::Array<int, 3, 1> shape, Eigen::Array<double, 3, 1> voxelsize) +{ + CGAL::Image_3 image = buildCgalImage(image_array, shape, voxelsize); + if ((image.xdim() != shape(0)) || (image.ydim() != shape(1)) || (image.zdim() != shape(2))) { + return EXIT_FAILURE; + } + return 0; +} + PYBIND11_MODULE(_wrp, m) { py::class_<LabelledTetrahedralMesh>(m, "LabelledTetrahedralMesh") .def(py::init<>()) @@ -16,4 +27,6 @@ PYBIND11_MODULE(_wrp, m) { .def("add_tetra", &LabelledTetrahedralMesh::addTetra, py::arg("tetra"), py::arg("label")); m.def("make_tetrahedron", &makeTetrahedron); + + m.def("build_cgal_image", &cgalLabelledImage, py::arg("image_array"), py::arg("shape"), py::arg("voxelsize")); } \ No newline at end of file