From 1db8ff6e684a34769622c64fc3d2d22db9bf5cff Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 24 Oct 2023 13:11:12 +0100 Subject: [PATCH 1/3] Mesh_3::Add handling of *.nii files in one example --- Mesh_3/doc/Mesh_3/Mesh_3.txt | 2 +- .../Mesh_3/mesh_3D_gray_vtk_image.cpp | 56 +++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Mesh_3/doc/Mesh_3/Mesh_3.txt b/Mesh_3/doc/Mesh_3/Mesh_3.txt index abe639826562..146d5629f854 100644 --- a/Mesh_3/doc/Mesh_3/Mesh_3.txt +++ b/Mesh_3/doc/Mesh_3/Mesh_3.txt @@ -693,7 +693,7 @@ View of a remeshed surface. (Left) input mesh (Right) output mesh. Code from sub The following example produces a 3D mesh for a domain whose boundary surface is the isosurface associated to an isovalue inside the input gray-level -3D image. In the distribution you can also find the example \ref Mesh_3/mesh_3D_gray_vtk_image.cpp which can deal with DICOM files as input. +3D image. In the distribution you can also find the example \ref Mesh_3/mesh_3D_gray_vtk_image.cpp which can deal with `*.nii` as well as `DICOM` files as input. \cgalExample{Mesh_3/mesh_3D_gray_image.cpp} diff --git a/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp b/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp index 55799a977477..8c895a87a952 100644 --- a/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp @@ -1,6 +1,8 @@ +#include #include #include +#include #include #include #include @@ -19,6 +21,8 @@ #include #include +#include + typedef short Image_word_type; // Domain @@ -43,36 +47,56 @@ class Less { } }; +namespace fs = std::filesystem; + int main(int argc, char* argv[]) { // Loads image if(argc == 1){ - std::cerr << "Usage: " << argv[0] << " iso_level=1 facet_size=1 facet_distance=0.1 cell_size=1\n"; + std::cerr << "Usage: " << argv[0] << " iso_level=1 facet_size=1 facet_distance=0.1 cell_size=1\n"; return 0; } + vtkImageData* vtk_image; Image_word_type iso = (argc>2)? boost::lexical_cast(argv[2]): 1; double fs = (argc>3)? boost::lexical_cast(argv[3]): 1; double fd = (argc>4)? boost::lexical_cast(argv[4]): 0.1; double cs = (argc>5)? boost::lexical_cast(argv[5]): 1; - vtkDICOMImageReader*dicom_reader = vtkDICOMImageReader::New(); - dicom_reader->SetDirectoryName(argv[1]); - - vtkDemandDrivenPipeline*executive = - vtkDemandDrivenPipeline::SafeDownCast(dicom_reader->GetExecutive()); - if (executive) - { - executive->SetReleaseDataFlag(0, 0); // where 0 is the port index - } + fs::path path(argv[1]); - vtkImageGaussianSmooth* smoother = vtkImageGaussianSmooth::New(); - smoother->SetStandardDeviations(1., 1., 1.); - smoother->SetInputConnection(dicom_reader->GetOutputPort()); - smoother->Update(); - vtkImageData* vtk_image = smoother->GetOutput(); - vtk_image->Print(std::cerr); + if(fs::is_regular_file(path)){ + std::cout << "regular file" << std::endl; + if (path.has_extension()){ + fs::path stem = path.stem(); + if ((path.extension() == "nii") || (stem.has_extension() && (stem.extension() == "nii") && (path.extension() == "gz"))) { + vtkNew reader; + reader->SetFileName(argv[1]); + reader->Update(); + vtk_image = reader->GetOutput(); + vtk_image->Print(std::cerr); + } + } + } + else if (fs::is_directory(path)) { + vtkDICOMImageReader* dicom_reader = vtkDICOMImageReader::New(); + dicom_reader->SetDirectoryName(argv[1]); + + vtkDemandDrivenPipeline* executive = + vtkDemandDrivenPipeline::SafeDownCast(dicom_reader->GetExecutive()); + if (executive) + { + executive->SetReleaseDataFlag(0, 0); // where 0 is the port index + } + + vtkImageGaussianSmooth* smoother = vtkImageGaussianSmooth::New(); + smoother->SetStandardDeviations(1., 1., 1.); + smoother->SetInputConnection(dicom_reader->GetOutputPort()); + smoother->Update(); + vtkImageData* vtk_image = smoother->GetOutput(); + vtk_image->Print(std::cerr); + } CGAL::Image_3 image = CGAL::IO::read_vtk_image_data(vtk_image); if(image.image() == nullptr){ std::cerr << "could not create a CGAL::Image_3 from the vtk image\n"; From 0e9905c4903008e29c32eb3ef4cfa97da8d6ca52 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 24 Oct 2023 14:43:24 +0100 Subject: [PATCH 2/3] Fixes --- Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp b/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp index 8c895a87a952..52d123fd441c 100644 --- a/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_3D_gray_vtk_image.cpp @@ -57,7 +57,7 @@ int main(int argc, char* argv[]) return 0; } - vtkImageData* vtk_image; + vtkImageData* vtk_image = nullptr; Image_word_type iso = (argc>2)? boost::lexical_cast(argv[2]): 1; double fs = (argc>3)? boost::lexical_cast(argv[3]): 1; double fd = (argc>4)? boost::lexical_cast(argv[4]): 0.1; @@ -69,9 +69,8 @@ int main(int argc, char* argv[]) std::cout << "regular file" << std::endl; if (path.has_extension()){ fs::path stem = path.stem(); - if ((path.extension() == "nii") || (stem.has_extension() && (stem.extension() == "nii") && (path.extension() == "gz"))) { - - vtkNew reader; + if ((path.extension() == ".nii") || (stem.has_extension() && (stem.extension() == ".nii") && (path.extension() == ".gz"))) { + vtkNIFTIImageReader* reader = vtkNIFTIImageReader::New(); reader->SetFileName(argv[1]); reader->Update(); vtk_image = reader->GetOutput(); @@ -94,9 +93,13 @@ int main(int argc, char* argv[]) smoother->SetStandardDeviations(1., 1., 1.); smoother->SetInputConnection(dicom_reader->GetOutputPort()); smoother->Update(); - vtkImageData* vtk_image = smoother->GetOutput(); + vtk_image = smoother->GetOutput(); vtk_image->Print(std::cerr); } + if(vtk_image == nullptr){ + std::cout << "No image loaded" << std::endl; + return 0; + } CGAL::Image_3 image = CGAL::IO::read_vtk_image_data(vtk_image); if(image.image() == nullptr){ std::cerr << "could not create a CGAL::Image_3 from the vtk image\n"; From 3cb583ade73d3dfc5e5e0cabf78a731470a48e5a Mon Sep 17 00:00:00 2001 From: ange-clement Date: Fri, 12 Apr 2024 12:16:25 +0200 Subject: [PATCH 3/3] Added nii image "squircle.nii" + Updated example to work with a default dataset. --- Data/data/images/squircle.nii | Bin 0 -> 16736 bytes Mesh_3/examples/Mesh_3/CMakeLists.txt | 2 +- .../examples/Mesh_3/mesh_3D_gray_vtk_image.cpp | 14 +++++++------- 3 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 Data/data/images/squircle.nii diff --git a/Data/data/images/squircle.nii b/Data/data/images/squircle.nii new file mode 100644 index 0000000000000000000000000000000000000000..96d847db2210c9a277cfdcc4de652dbb29facd35 GIT binary patch literal 16736 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 a|7-pJul4)C iso_level=1 facet_size=1 facet_distance=0.1 cell_size=1\n"; - return 0; - } + + // Usage: mesh_3D_gray_vtk_image iso_level=1 facet_size=1 facet_distance=0.1 cell_size=1 + + const std::string fname = (argc>1)?argv[1]:CGAL::data_file_path("images/squircle.nii"); vtkImageData* vtk_image = nullptr; Image_word_type iso = (argc>2)? boost::lexical_cast(argv[2]): 1; @@ -63,7 +63,7 @@ int main(int argc, char* argv[]) double fd = (argc>4)? boost::lexical_cast(argv[4]): 0.1; double cs = (argc>5)? boost::lexical_cast(argv[5]): 1; - fs::path path(argv[1]); + fs::path path(fname); if(fs::is_regular_file(path)){ std::cout << "regular file" << std::endl; @@ -71,7 +71,7 @@ int main(int argc, char* argv[]) fs::path stem = path.stem(); if ((path.extension() == ".nii") || (stem.has_extension() && (stem.extension() == ".nii") && (path.extension() == ".gz"))) { vtkNIFTIImageReader* reader = vtkNIFTIImageReader::New(); - reader->SetFileName(argv[1]); + reader->SetFileName(fname.c_str()); reader->Update(); vtk_image = reader->GetOutput(); vtk_image->Print(std::cerr); @@ -111,7 +111,7 @@ int main(int argc, char* argv[]) Mesh_domain domain = Mesh_domain::create_gray_image_mesh_domain (image, params::image_values_to_subdomain_indices(Less(iso)). - value_outside(0)); + value_outside(iso+1)); /// [Domain creation] // Mesh criteria