From bdff151b4297a265c1200c75ac06001c4e22f821 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Sun, 30 Apr 2023 16:36:55 +0100 Subject: [PATCH 1/4] Add reading NIFTI files (*.nii) --- .../Plugins/Mesh_3/Io_image_plugin.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp index 68c3053d876..1e150b3a9ed 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -1086,9 +1087,10 @@ private Q_SLOTS: QString Io_image_plugin::nameFilters() const { return QString("Inrimage files (*.inr *.inr.gz) ;; " - "Analyze files (*.hdr *.img *img.gz) ;; " + "Analyze files (*.hdr *.img *.img.gz) ;; " "Stanford Exploration Project files (*.H *.HH) ;; " - "NRRD image files (*.nrrd)"); + "NRRD image files (*.nrrd)" + "NIFTI image files (*.nii)"); } bool Io_image_plugin::canLoad(QFileInfo) const @@ -1143,6 +1145,23 @@ Io_image_plugin::load(QFileInfo fileinfo, bool& ok, bool add_to_scene) #endif } + // read a NIFTI file + if(fileinfo.suffix() == "nii") + { +#ifdef CGAL_USE_VTK + vtkNew reader; + reader->SetFileName(fileinfo.filePath().toUtf8()); + reader->Update(); + auto vtk_image = reader->GetOutput(); + vtk_image->Print(std::cerr); + *image = CGAL::IO::read_vtk_image_data(vtk_image); // copy the image data +#else + CGAL::Three::Three::warning("VTK is required to read NRRD files"); + delete image; + return QList(); +#endif + } + // read a sep file else if (fileinfo.suffix() == "H" || fileinfo.suffix() == "HH") { From 939002b1ecf996baa4a8f85d4db609942c357ce2 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 2 May 2023 13:09:47 +0100 Subject: [PATCH 2/4] Add functions that enable to change the origin --- CGAL_ImageIO/include/CGAL/Image_3.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CGAL_ImageIO/include/CGAL/Image_3.h b/CGAL_ImageIO/include/CGAL/Image_3.h index e653e9de83b..28ae90e31c8 100644 --- a/CGAL_ImageIO/include/CGAL/Image_3.h +++ b/CGAL_ImageIO/include/CGAL/Image_3.h @@ -150,6 +150,10 @@ public: float ty() const { return image_ptr->ty; } float tz() const { return image_ptr->tz; } + float& tx(){ return image_ptr->tx; } + float& ty(){ return image_ptr->ty; } + float& tz(){ return image_ptr->tz; } + float value(const std::size_t i, const std::size_t j, const std::size_t k) const From 9350333d72e5bf39fc9827cdff5f64992049904c Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 2 May 2023 15:36:27 +0200 Subject: [PATCH 3/4] fix the reader plugin --- Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp index 1e150b3a9ed..f37bcf2b374 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp @@ -1089,7 +1089,7 @@ QString Io_image_plugin::nameFilters() const return QString("Inrimage files (*.inr *.inr.gz) ;; " "Analyze files (*.hdr *.img *.img.gz) ;; " "Stanford Exploration Project files (*.H *.HH) ;; " - "NRRD image files (*.nrrd)" + "NRRD image files (*.nrrd) ;; " "NIFTI image files (*.nii)"); } @@ -1156,7 +1156,7 @@ Io_image_plugin::load(QFileInfo fileinfo, bool& ok, bool add_to_scene) vtk_image->Print(std::cerr); *image = CGAL::IO::read_vtk_image_data(vtk_image); // copy the image data #else - CGAL::Three::Three::warning("VTK is required to read NRRD files"); + CGAL::Three::Three::warning("VTK is required to read NIfTI files"); delete image; return QList(); #endif From c5cf38e6a7b20ff38852bfc18edf9bbeb199571f Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 2 May 2023 15:37:38 +0200 Subject: [PATCH 4/4] allow different word type in the image item --- .../demo/Polyhedron/Scene_image_item.cpp | 187 +++++++++++------- 1 file changed, 113 insertions(+), 74 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_image_item.cpp b/Polyhedron/demo/Polyhedron/Scene_image_item.cpp index 229aff8a7ff..c5c4bb4269a 100644 --- a/Polyhedron/demo/Polyhedron/Scene_image_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_image_item.cpp @@ -20,6 +20,7 @@ typedef Edge_container Ec; typedef Viewer_interface Vi; namespace internal { +template class Image_accessor { public: @@ -33,47 +34,47 @@ public: int dx() const { return dx_; } int dy() const { return dy_; } int dz() const { return dz_; } - std::size_t xdim() const { return im_.xdim(); } - std::size_t ydim() const { return im_.ydim(); } - std::size_t zdim() const { return im_.zdim(); } - double vx() const { return im_.vx(); } - double vy() const { return im_.vy(); } - double vz() const { return im_.vz(); } + std::size_t xdim() const { return im_->xdim(); } + std::size_t ydim() const { return im_->ydim(); } + std::size_t zdim() const { return im_->zdim(); } + double vx() const { return im_->vx(); } + double vy() const { return im_->vy(); } + double vz() const { return im_->vz(); } - double tx() const { return im_.image()->tx; } - double ty() const { return im_.image()->ty; } - double tz() const { return im_.image()->tz; } + double tx() const { return im_->image()->tx; } + double ty() const { return im_->image()->ty; } + double tz() const { return im_->image()->tz; } private: - unsigned char non_null_neighbor_data(std::size_t i, + Word_type non_null_neighbor_data(std::size_t i, std::size_t j, std::size_t k) const; - unsigned char image_data(std::size_t i, std::size_t j, std::size_t k) const; + Word_type image_data(std::size_t i, std::size_t j, std::size_t k) const; - void add_to_normal(unsigned char v, + void add_to_normal(Word_type v, float& x, float& y, float& z, int dx, int dy, int dz) const; private: - const Image& im_; + const Image* im_; int dx_, dy_, dz_; - const QColor default_color_; - std::map colors_; + QColor default_color_; + std::map colors_; }; - -Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz) -: im_(im) +template +Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz) +: im_(&im) , dx_(dx) , dy_(dy) , dz_(dz) , default_color_() , colors_() { - const std::size_t xdim = im_.xdim(); - const std::size_t ydim = im_.ydim(); - const std::size_t zdim = im_.zdim(); + const std::size_t xdim = im_->xdim(); + const std::size_t ydim = im_->ydim(); + const std::size_t zdim = im_->zdim(); for(std::size_t i=0 ; i::iterator it = colors_.begin(), + for ( auto it = colors_.begin(), end = colors_.end() ; it != end ; ++it, i += 1.) { double hue = starting_hue + 1./double(colors_.size()) * i; @@ -98,18 +99,19 @@ Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz) } } +template bool -Image_accessor:: +Image_accessor:: is_vertex_active(std::size_t i, std::size_t j, std::size_t k) const { - unsigned char v1 = image_data(i-dx_, j-dy_, k-dz_); - unsigned char v2 = image_data(i-dx_, j-dy_, k ); - unsigned char v3 = image_data(i-dx_, j , k-dz_); - unsigned char v4 = image_data(i-dx_, j , k ); - unsigned char v5 = image_data(i , j-dy_, k-dz_); - unsigned char v6 = image_data(i , j-dy_, k ); - unsigned char v7 = image_data(i , j , k-dz_); - unsigned char v8 = image_data(i , j , k ); + Word_type v1 = image_data(i-dx_, j-dy_, k-dz_); + Word_type v2 = image_data(i-dx_, j-dy_, k ); + Word_type v3 = image_data(i-dx_, j , k-dz_); + Word_type v4 = image_data(i-dx_, j , k ); + Word_type v5 = image_data(i , j-dy_, k-dz_); + Word_type v6 = image_data(i , j-dy_, k ); + Word_type v7 = image_data(i , j , k-dz_); + Word_type v8 = image_data(i , j , k ); // don't draw interior vertices if ( v1 != 0 && v2 != 0 && v3 != 0 && v4 != 0 && @@ -121,33 +123,35 @@ is_vertex_active(std::size_t i, std::size_t j, std::size_t k) const return ( v1 != 0 || v2 != 0 || v3 != 0 || v4 != 0 || v5 != 0 || v6 != 0 || v7 != 0 || v8 != 0 ); } - +template const QColor& -Image_accessor::vertex_color(std::size_t i, std::size_t j, std::size_t k) const +Image_accessor::vertex_color(std::size_t i, std::size_t j, std::size_t k) const { - unsigned char c = non_null_neighbor_data(i,j,k); + Word_type c = non_null_neighbor_data(i,j,k); if ( 0 == c ) { return default_color_; } - std::map::const_iterator color = colors_.find(c); + auto color = colors_.find(c); if ( colors_.end() == color ) { return default_color_; } return color->second; } -unsigned char -Image_accessor::image_data(std::size_t i, std::size_t j, std::size_t k) const +template +Word_type +Image_accessor::image_data(std::size_t i, std::size_t j, std::size_t k) const { - if ( i(im_.image(),i,j,k); + if ( ixdim() && jydim() && kzdim() ) + return CGAL::IMAGEIO::static_evaluate(im_->image(),i,j,k); else return 0; } -unsigned char -Image_accessor:: +template +Word_type +Image_accessor:: non_null_neighbor_data(std::size_t i, std::size_t j, std::size_t k) const { - unsigned char v = image_data(i-dx_, j-dy_, k-dz_); + Word_type v = image_data(i-dx_, j-dy_, k-dz_); if ( v != 0 ) { return v; } v = image_data(i-dx_, j-dy_, k ); @@ -174,12 +178,13 @@ non_null_neighbor_data(std::size_t i, std::size_t j, std::size_t k) const return 0; } +template void -Image_accessor:: +Image_accessor:: normal(std::size_t i, std::size_t j, std::size_t k, float& x, float& y, float& z) const { - unsigned char v = image_data(i-dx_, j-dy_, k-dz_); + Word_type v = image_data(i-dx_, j-dy_, k-dz_); add_to_normal(v,x,y,z, 1 , 1 , 1); v = image_data( i-dx_, j-dy_, k); @@ -204,9 +209,10 @@ normal(std::size_t i, std::size_t j, std::size_t k, add_to_normal(v,x,y,z, -1 , -1 , -1); } +template void -Image_accessor:: -add_to_normal(unsigned char v, +Image_accessor:: +add_to_normal(Word_type v, float& x, float& y, float& z, int dx, int dy, int dz) const { @@ -218,14 +224,11 @@ add_to_normal(unsigned char v, } } - - class Vertex_buffer_helper { public: - Vertex_buffer_helper(const Image_accessor& data, bool is_ogl_4_3); - - void fill_buffer_data(); + virtual void fill_buffer_data() = 0; + virtual ~Vertex_buffer_helper() {} float* colors() { return colors_.data(); } float* normals() { return normals_.data(); } @@ -236,6 +239,19 @@ public: std::size_t normal_size() const { return normals_.size(); } std::size_t vertex_size() const { return vertices_.size(); } std::size_t quad_size() const { return quads_.size(); } +protected: + std::vector colors_, normals_, vertices_; + std::vector quads_; +}; + +template +class Vertex_buffer_helper_impl : public Vertex_buffer_helper +{ +public: + Vertex_buffer_helper_impl(Image_accessor&& data, bool is_ogl_4_3); + + ~Vertex_buffer_helper_impl() override {} + void fill_buffer_data() override; private: void treat_vertex(std::size_t i, std::size_t j, std::size_t k); @@ -254,26 +270,28 @@ private: int dz() const { return data_.dz(); } private: - static int vertex_not_found_; + static constexpr int vertex_not_found_ = -1; - const Image_accessor& data_; + const Image_accessor data_; typedef std::map Indices; Indices indices_; - std::vector colors_, normals_, vertices_; - std::vector quads_; bool is_ogl_4_3; }; -int Vertex_buffer_helper::vertex_not_found_ = -1; +// template +// int Vertex_buffer_helper_impl::vertex_not_found_ = -1; -Vertex_buffer_helper:: -Vertex_buffer_helper(const Image_accessor& data, bool b) - : data_(data), is_ogl_4_3(b) + +template +Vertex_buffer_helper_impl:: +Vertex_buffer_helper_impl(Image_accessor&& data, bool b) + : data_(std::move(data)), is_ogl_4_3(b) {} +template void -Vertex_buffer_helper:: +Vertex_buffer_helper_impl:: fill_buffer_data() { std::size_t i,j,k; @@ -289,8 +307,9 @@ fill_buffer_data() } } +template void -Vertex_buffer_helper::treat_vertex(std::size_t i, std::size_t j, std::size_t k) +Vertex_buffer_helper_impl::treat_vertex(std::size_t i, std::size_t j, std::size_t k) { if ( data_.is_vertex_active(i,j,k) ) { @@ -301,8 +320,9 @@ Vertex_buffer_helper::treat_vertex(std::size_t i, std::size_t j, std::size_t k) } } +template void -Vertex_buffer_helper::push_color(std::size_t i, std::size_t j, std::size_t k) +Vertex_buffer_helper_impl::push_color(std::size_t i, std::size_t j, std::size_t k) { const QColor& color = data_.vertex_color(i,j,k); if ( ! color.isValid() ) { return; } @@ -311,8 +331,9 @@ Vertex_buffer_helper::push_color(std::size_t i, std::size_t j, std::size_t k) colors_.push_back(float(color.blue())/255.f); } +template void -Vertex_buffer_helper::push_normal(std::size_t i, std::size_t j, std::size_t k) +Vertex_buffer_helper_impl::push_normal(std::size_t i, std::size_t j, std::size_t k) { float x=0.f, y=0.f, z=0.f; data_.normal(i,j,k,x,y,z); @@ -327,8 +348,9 @@ Vertex_buffer_helper::push_normal(std::size_t i, std::size_t j, std::size_t k) normals_.push_back(z); } +template void -Vertex_buffer_helper::push_vertex(std::size_t i, std::size_t j, std::size_t k) +Vertex_buffer_helper_impl::push_vertex(std::size_t i, std::size_t j, std::size_t k) { indices_.insert(std::make_pair(compute_position(i,j,k), vertices_.size()/3)); @@ -352,8 +374,9 @@ Vertex_buffer_helper::push_vertex(std::size_t i, std::size_t j, std::size_t k) vertices_.push_back( (dk - 0.5) * data_.vz() + data_.tz()); } +template void -Vertex_buffer_helper::push_quads(std::size_t i, std::size_t j, std::size_t k) +Vertex_buffer_helper_impl::push_quads(std::size_t i, std::size_t j, std::size_t k) { int pos1 = vertex_index(i-dx(), j , k); int pos2 = vertex_index(i-dx(), j-dy(), k); @@ -372,8 +395,9 @@ Vertex_buffer_helper::push_quads(std::size_t i, std::size_t j, std::size_t k) push_quad(pos1, pos2, pos3, pos4); } +template void -Vertex_buffer_helper::push_quad(int pos1, int pos2, int pos3, int pos4) +Vertex_buffer_helper_impl::push_quad(int pos1, int pos2, int pos3, int pos4) { if ( pos1 != vertex_not_found_ && pos2 != vertex_not_found_ @@ -391,8 +415,9 @@ Vertex_buffer_helper::push_quad(int pos1, int pos2, int pos3, int pos4) } } +template int -Vertex_buffer_helper:: +Vertex_buffer_helper_impl:: compute_position(std::size_t i, std::size_t j, std::size_t k) const { return static_cast( @@ -401,8 +426,9 @@ compute_position(std::size_t i, std::size_t j, std::size_t k) const + k/dz()); } +template int -Vertex_buffer_helper:: +Vertex_buffer_helper_impl:: vertex_index(std::size_t i, std::size_t j, std::size_t k) const { if ( i > data_.xdim() || j > data_.ydim() || k > data_.zdim() ) @@ -751,17 +777,30 @@ void Scene_image_item::initializeBuffers(Viewer_interface *v) const } } +template +internal::Vertex_buffer_helper* +init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3) +{ + internal::Image_accessor image_data_accessor(im, dx, dy, dz); + return new internal::Vertex_buffer_helper_impl(std::move(image_data_accessor), + is_ogl_4_3); +} + void Scene_image_item::computeElements() const { QApplication::setOverrideCursor(Qt::WaitCursor); d->draw_Bbox(bbox(), &d->v_box); if(!d->is_hidden) { - internal::Image_accessor image_data_accessor (*m_image, - d->m_voxel_scale, - d->m_voxel_scale, - d->m_voxel_scale); - d->helper = new internal::Vertex_buffer_helper(image_data_accessor, d->is_ogl_4_3); + // internal::Image_accessor image_data_accessor (*m_image, + // d->m_voxel_scale, + // d->m_voxel_scale, + // d->m_voxel_scale); + // d->helper = new internal::Vertex_buffer_helper(image_data_accessor, d->is_ogl_4_3); + CGAL_IMAGE_IO_CASE(m_image->image(), + d->helper = init_helper(*m_image, + d->m_voxel_scale, d->m_voxel_scale, d->m_voxel_scale, + d->is_ogl_4_3)); d->helper->fill_buffer_data(); getTriangleContainer(0)->allocate( Tc::Smooth_vertices,