Merge pull request #7417 from afabri/Polyhedron-nifti-GF

Polyhedron Demo: Add reading NIFTI files (*.nii)
This commit is contained in:
Laurent Rineau 2023-05-11 16:55:26 +02:00
commit e717b873c5
3 changed files with 138 additions and 76 deletions

View File

@ -150,6 +150,10 @@ public:
float ty() const { return image_ptr->ty; } float ty() const { return image_ptr->ty; }
float tz() const { return image_ptr->tz; } 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, float value(const std::size_t i,
const std::size_t j, const std::size_t j,
const std::size_t k) const const std::size_t k) const

View File

@ -58,6 +58,7 @@
#include <vtkImageData.h> #include <vtkImageData.h>
#include <vtkDICOMImageReader.h> #include <vtkDICOMImageReader.h>
#include <vtkBMPReader.h> #include <vtkBMPReader.h>
#include <vtkNIFTIImageReader.h>
#include <vtkImageReader.h> #include <vtkImageReader.h>
#include <vtkImageGaussianSmooth.h> #include <vtkImageGaussianSmooth.h>
#include <vtkDemandDrivenPipeline.h> #include <vtkDemandDrivenPipeline.h>
@ -1086,9 +1087,10 @@ private Q_SLOTS:
QString Io_image_plugin::nameFilters() const QString Io_image_plugin::nameFilters() const
{ {
return QString("Inrimage files (*.inr *.inr.gz) ;; " 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) ;; " "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 bool Io_image_plugin::canLoad(QFileInfo) const
@ -1143,6 +1145,23 @@ Io_image_plugin::load(QFileInfo fileinfo, bool& ok, bool add_to_scene)
#endif #endif
} }
// read a NIFTI file
if(fileinfo.suffix() == "nii")
{
#ifdef CGAL_USE_VTK
vtkNew<vtkNIFTIImageReader> 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 NIfTI files");
delete image;
return QList<Scene_item*>();
#endif
}
// read a sep file // read a sep file
else if (fileinfo.suffix() == "H" || fileinfo.suffix() == "HH") else if (fileinfo.suffix() == "H" || fileinfo.suffix() == "HH")
{ {

View File

@ -20,6 +20,7 @@ typedef Edge_container Ec;
typedef Viewer_interface Vi; typedef Viewer_interface Vi;
namespace internal { namespace internal {
template <typename Word_type>
class Image_accessor class Image_accessor
{ {
public: public:
@ -33,47 +34,47 @@ public:
int dx() const { return dx_; } int dx() const { return dx_; }
int dy() const { return dy_; } int dy() const { return dy_; }
int dz() const { return dz_; } int dz() const { return dz_; }
std::size_t xdim() const { return im_.xdim(); } std::size_t xdim() const { return im_->xdim(); }
std::size_t ydim() const { return im_.ydim(); } std::size_t ydim() const { return im_->ydim(); }
std::size_t zdim() const { return im_.zdim(); } std::size_t zdim() const { return im_->zdim(); }
double vx() const { return im_.vx(); } double vx() const { return im_->vx(); }
double vy() const { return im_.vy(); } double vy() const { return im_->vy(); }
double vz() const { return im_.vz(); } double vz() const { return im_->vz(); }
double tx() const { return im_.image()->tx; } double tx() const { return im_->image()->tx; }
double ty() const { return im_.image()->ty; } double ty() const { return im_->image()->ty; }
double tz() const { return im_.image()->tz; } double tz() const { return im_->image()->tz; }
private: 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 j,
std::size_t k) const; 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, float& x, float& y, float& z,
int dx, int dy, int dz) const; int dx, int dy, int dz) const;
private: private:
const Image& im_; const Image* im_;
int dx_, dy_, dz_; int dx_, dy_, dz_;
const QColor default_color_; QColor default_color_;
std::map<unsigned char, QColor> colors_; std::map<Word_type, QColor> colors_;
}; };
template <typename Word_type>
Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz) Image_accessor<Word_type>::Image_accessor(const Image& im, int dx, int dy, int dz)
: im_(im) : im_(&im)
, dx_(dx) , dx_(dx)
, dy_(dy) , dy_(dy)
, dz_(dz) , dz_(dz)
, default_color_() , default_color_()
, colors_() , colors_()
{ {
const std::size_t xdim = im_.xdim(); const std::size_t xdim = im_->xdim();
const std::size_t ydim = im_.ydim(); const std::size_t ydim = im_->ydim();
const std::size_t zdim = im_.zdim(); const std::size_t zdim = im_->zdim();
for(std::size_t i=0 ; i<xdim ; i+=dx_) for(std::size_t i=0 ; i<xdim ; i+=dx_)
{ {
@ -81,7 +82,7 @@ Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz)
{ {
for(std::size_t k=0 ; k<zdim ; k+=dz_) for(std::size_t k=0 ; k<zdim ; k+=dz_)
{ {
unsigned char c = image_data(i,j,k); Word_type c = image_data(i,j,k);
if ( 0 != c ) { colors_.insert(std::make_pair(c,QColor())); } if ( 0 != c ) { colors_.insert(std::make_pair(c,QColor())); }
} }
} }
@ -89,7 +90,7 @@ Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz)
double i=0; double i=0;
const double starting_hue = 45./360.; // magenta const double starting_hue = 45./360.; // magenta
for ( std::map<unsigned char, QColor>::iterator it = colors_.begin(), for ( auto it = colors_.begin(),
end = colors_.end() ; it != end ; ++it, i += 1.) end = colors_.end() ; it != end ; ++it, i += 1.)
{ {
double hue = starting_hue + 1./double(colors_.size()) * i; 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 <typename Word_type>
bool bool
Image_accessor:: Image_accessor<Word_type>::
is_vertex_active(std::size_t i, std::size_t j, std::size_t k) const 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_); Word_type v1 = image_data(i-dx_, j-dy_, k-dz_);
unsigned char v2 = image_data(i-dx_, j-dy_, k ); Word_type v2 = image_data(i-dx_, j-dy_, k );
unsigned char v3 = image_data(i-dx_, j , k-dz_); Word_type v3 = image_data(i-dx_, j , k-dz_);
unsigned char v4 = image_data(i-dx_, j , k ); Word_type v4 = image_data(i-dx_, j , k );
unsigned char v5 = image_data(i , j-dy_, k-dz_); Word_type v5 = image_data(i , j-dy_, k-dz_);
unsigned char v6 = image_data(i , j-dy_, k ); Word_type v6 = image_data(i , j-dy_, k );
unsigned char v7 = image_data(i , j , k-dz_); Word_type v7 = image_data(i , j , k-dz_);
unsigned char v8 = image_data(i , j , k ); Word_type v8 = image_data(i , j , k );
// don't draw interior vertices // don't draw interior vertices
if ( v1 != 0 && v2 != 0 && v3 != 0 && v4 != 0 && 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 || return ( v1 != 0 || v2 != 0 || v3 != 0 || v4 != 0 ||
v5 != 0 || v6 != 0 || v7 != 0 || v8 != 0 ); v5 != 0 || v6 != 0 || v7 != 0 || v8 != 0 );
} }
template <typename Word_type>
const QColor& const QColor&
Image_accessor::vertex_color(std::size_t i, std::size_t j, std::size_t k) const Image_accessor<Word_type>::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_; } if ( 0 == c ) { return default_color_; }
std::map<unsigned char, QColor>::const_iterator color = colors_.find(c); auto color = colors_.find(c);
if ( colors_.end() == color ) { return default_color_; } if ( colors_.end() == color ) { return default_color_; }
return color->second; return color->second;
} }
unsigned char template <typename Word_type>
Image_accessor::image_data(std::size_t i, std::size_t j, std::size_t k) const Word_type
Image_accessor<Word_type>::image_data(std::size_t i, std::size_t j, std::size_t k) const
{ {
if ( i<im_.xdim() && j<im_.ydim() && k<im_.zdim() ) if ( i<im_->xdim() && j<im_->ydim() && k<im_->zdim() )
return CGAL::IMAGEIO::static_evaluate<unsigned char>(im_.image(),i,j,k); return CGAL::IMAGEIO::static_evaluate<Word_type>(im_->image(),i,j,k);
else else
return 0; return 0;
} }
unsigned char template <typename Word_type>
Image_accessor:: Word_type
Image_accessor<Word_type>::
non_null_neighbor_data(std::size_t i, std::size_t j, std::size_t k) const 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; } if ( v != 0 ) { return v; }
v = image_data(i-dx_, j-dy_, k ); 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; return 0;
} }
template <typename Word_type>
void void
Image_accessor:: Image_accessor<Word_type>::
normal(std::size_t i, std::size_t j, std::size_t k, normal(std::size_t i, std::size_t j, std::size_t k,
float& x, float& y, float& z) const 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); add_to_normal(v,x,y,z, 1 , 1 , 1);
v = image_data( i-dx_, j-dy_, k); 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); add_to_normal(v,x,y,z, -1 , -1 , -1);
} }
template <typename Word_type>
void void
Image_accessor:: Image_accessor<Word_type>::
add_to_normal(unsigned char v, add_to_normal(Word_type v,
float& x, float& y, float& z, float& x, float& y, float& z,
int dx, int dy, int dz) const int dx, int dy, int dz) const
{ {
@ -218,14 +224,11 @@ add_to_normal(unsigned char v,
} }
} }
class Vertex_buffer_helper class Vertex_buffer_helper
{ {
public: public:
Vertex_buffer_helper(const Image_accessor& data, bool is_ogl_4_3); virtual void fill_buffer_data() = 0;
virtual ~Vertex_buffer_helper() {}
void fill_buffer_data();
float* colors() { return colors_.data(); } float* colors() { return colors_.data(); }
float* normals() { return normals_.data(); } float* normals() { return normals_.data(); }
@ -236,6 +239,19 @@ public:
std::size_t normal_size() const { return normals_.size(); } std::size_t normal_size() const { return normals_.size(); }
std::size_t vertex_size() const { return vertices_.size(); } std::size_t vertex_size() const { return vertices_.size(); }
std::size_t quad_size() const { return quads_.size(); } std::size_t quad_size() const { return quads_.size(); }
protected:
std::vector<float> colors_, normals_, vertices_;
std::vector<unsigned int> quads_;
};
template <typename Word_type>
class Vertex_buffer_helper_impl : public Vertex_buffer_helper
{
public:
Vertex_buffer_helper_impl(Image_accessor<Word_type>&& data, bool is_ogl_4_3);
~Vertex_buffer_helper_impl() override {}
void fill_buffer_data() override;
private: private:
void treat_vertex(std::size_t i, std::size_t j, std::size_t k); 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(); } int dz() const { return data_.dz(); }
private: private:
static int vertex_not_found_; static constexpr int vertex_not_found_ = -1;
const Image_accessor& data_; const Image_accessor<Word_type> data_;
typedef std::map<int, std::size_t> Indices; typedef std::map<int, std::size_t> Indices;
Indices indices_; Indices indices_;
std::vector<float> colors_, normals_, vertices_;
std::vector<unsigned int> quads_;
bool is_ogl_4_3; bool is_ogl_4_3;
}; };
int Vertex_buffer_helper::vertex_not_found_ = -1; // template <typename Word_type>
// int Vertex_buffer_helper_impl<Word_type>::vertex_not_found_ = -1;
Vertex_buffer_helper::
Vertex_buffer_helper(const Image_accessor& data, bool b) template <typename Word_type>
: data_(data), is_ogl_4_3(b) Vertex_buffer_helper_impl<Word_type>::
Vertex_buffer_helper_impl(Image_accessor<Word_type>&& data, bool b)
: data_(std::move(data)), is_ogl_4_3(b)
{} {}
template <typename Word_type>
void void
Vertex_buffer_helper:: Vertex_buffer_helper_impl<Word_type>::
fill_buffer_data() fill_buffer_data()
{ {
std::size_t i,j,k; std::size_t i,j,k;
@ -289,8 +307,9 @@ fill_buffer_data()
} }
} }
template <typename Word_type>
void void
Vertex_buffer_helper::treat_vertex(std::size_t i, std::size_t j, std::size_t k) Vertex_buffer_helper_impl<Word_type>::treat_vertex(std::size_t i, std::size_t j, std::size_t k)
{ {
if ( data_.is_vertex_active(i,j,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 <typename Word_type>
void void
Vertex_buffer_helper::push_color(std::size_t i, std::size_t j, std::size_t k) Vertex_buffer_helper_impl<Word_type>::push_color(std::size_t i, std::size_t j, std::size_t k)
{ {
const QColor& color = data_.vertex_color(i,j,k); const QColor& color = data_.vertex_color(i,j,k);
if ( ! color.isValid() ) { return; } 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); colors_.push_back(float(color.blue())/255.f);
} }
template <typename Word_type>
void void
Vertex_buffer_helper::push_normal(std::size_t i, std::size_t j, std::size_t k) Vertex_buffer_helper_impl<Word_type>::push_normal(std::size_t i, std::size_t j, std::size_t k)
{ {
float x=0.f, y=0.f, z=0.f; float x=0.f, y=0.f, z=0.f;
data_.normal(i,j,k,x,y,z); 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); normals_.push_back(z);
} }
template <typename Word_type>
void void
Vertex_buffer_helper::push_vertex(std::size_t i, std::size_t j, std::size_t k) Vertex_buffer_helper_impl<Word_type>::push_vertex(std::size_t i, std::size_t j, std::size_t k)
{ {
indices_.insert(std::make_pair(compute_position(i,j,k), indices_.insert(std::make_pair(compute_position(i,j,k),
vertices_.size()/3)); 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()); vertices_.push_back( (dk - 0.5) * data_.vz() + data_.tz());
} }
template <typename Word_type>
void void
Vertex_buffer_helper::push_quads(std::size_t i, std::size_t j, std::size_t k) Vertex_buffer_helper_impl<Word_type>::push_quads(std::size_t i, std::size_t j, std::size_t k)
{ {
int pos1 = vertex_index(i-dx(), j , k); int pos1 = vertex_index(i-dx(), j , k);
int pos2 = vertex_index(i-dx(), j-dy(), 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); push_quad(pos1, pos2, pos3, pos4);
} }
template <typename Word_type>
void void
Vertex_buffer_helper::push_quad(int pos1, int pos2, int pos3, int pos4) Vertex_buffer_helper_impl<Word_type>::push_quad(int pos1, int pos2, int pos3, int pos4)
{ {
if ( pos1 != vertex_not_found_ if ( pos1 != vertex_not_found_
&& pos2 != 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 <typename Word_type>
int int
Vertex_buffer_helper:: Vertex_buffer_helper_impl<Word_type>::
compute_position(std::size_t i, std::size_t j, std::size_t k) const compute_position(std::size_t i, std::size_t j, std::size_t k) const
{ {
return static_cast<int>( return static_cast<int>(
@ -401,8 +426,9 @@ compute_position(std::size_t i, std::size_t j, std::size_t k) const
+ k/dz()); + k/dz());
} }
template <typename Word_type>
int int
Vertex_buffer_helper:: Vertex_buffer_helper_impl<Word_type>::
vertex_index(std::size_t i, std::size_t j, std::size_t k) const 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() ) if ( i > data_.xdim() || j > data_.ydim() || k > data_.zdim() )
@ -751,17 +777,30 @@ void Scene_image_item::initializeBuffers(Viewer_interface *v) const
} }
} }
template <typename Word_type>
internal::Vertex_buffer_helper*
init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3)
{
internal::Image_accessor<Word_type> image_data_accessor(im, dx, dy, dz);
return new internal::Vertex_buffer_helper_impl<Word_type>(std::move(image_data_accessor),
is_ogl_4_3);
}
void Scene_image_item::computeElements() const void Scene_image_item::computeElements() const
{ {
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
d->draw_Bbox(bbox(), &d->v_box); d->draw_Bbox(bbox(), &d->v_box);
if(!d->is_hidden) if(!d->is_hidden)
{ {
internal::Image_accessor image_data_accessor (*m_image, // internal::Image_accessor image_data_accessor (*m_image,
d->m_voxel_scale, // d->m_voxel_scale,
d->m_voxel_scale, // 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); // 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<Word>(*m_image,
d->m_voxel_scale, d->m_voxel_scale, d->m_voxel_scale,
d->is_ogl_4_3));
d->helper->fill_buffer_data(); d->helper->fill_buffer_data();
getTriangleContainer(0)->allocate( getTriangleContainer(0)->allocate(
Tc::Smooth_vertices, Tc::Smooth_vertices,