// Copyright (c) 2005-2008 INRIA Sophia-Antipolis (France). // 2008 GeometryFactory // All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL: https://github.com/CGAL/cgal/blob/v5.1/CGAL_ImageIO/include/CGAL/Image_3.h $ // $Id: Image_3.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Laurent Rineau, Pierre Alliez #ifndef CGAL_IMAGE_3_H #define CGAL_IMAGE_3_H #include #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_MSVC) # pragma warning(push) # pragma warning(disable:4244 4251) // double float conversion loss of data and dll linkage #endif class vtkImageData; namespace CGAL { namespace ImageIO { template struct Indicator_factory { class Indicator : public CGAL::cpp98::unary_function { const T label; public: Indicator(T i) : label(i) {} double operator()(T x) const { return (x == label) ? 1. : 0.; } }; // end nested class Indicator Indicator indicator(T i) const { return Indicator(i); } }; } // end namespace CGAL::ImageIO class CGAL_IMAGEIO_EXPORT Image_3 { class Image_deleter { const bool own_the_data; public: Image_deleter(bool own_the_data) : own_the_data(own_the_data) {} void operator()(_image* image) { if(!own_the_data && image != 0) { image->data = 0; } ::_freeImage(image); } }; public: enum Own { OWN_THE_DATA, DO_NOT_OWN_THE_DATA }; typedef boost::shared_ptr<_image> Image_shared_ptr; typedef Image_shared_ptr Pointer; protected: Image_shared_ptr image_ptr; // implementation in src/CGAL_ImageIO/Image_3.cpp bool private_read(_image* im, Own own_the_data = OWN_THE_DATA); public: Image_3() : image_ptr() { } Image_3(const Image_3& bi) : image_ptr(bi.image_ptr) { // std::cerr << "Image_3::copy_constructor\n"; } Image_3(_image* im, Own own_the_data = OWN_THE_DATA) { private_read(im, own_the_data); } ~Image_3() { } const _image* image() const { return image_ptr.get(); } _image* image() { return image_ptr.get(); } const void* data() const { return image()->data; } void* data() { return image()->data; } void set_data(void* d) { image()->data = d; } std::size_t xdim() const { return image_ptr->xdim; } std::size_t ydim() const { return image_ptr->ydim; } std::size_t zdim() const { return image_ptr->zdim; } std::size_t size() const { return xdim() * ydim() * zdim(); } double vx() const { return image_ptr->vx; } double vy() const { return image_ptr->vy; } double vz() const { return image_ptr->vz; } double tx() const { return image_ptr->tx; } double ty() const { return image_ptr->ty; } double tz() const { return image_ptr->tz; } float value(const std::size_t i, const std::size_t j, const std::size_t k) const { return ::evaluate(image(),i,j,k); } public: bool read(const char* file) { return private_read(::_readImage(file)); } bool read_raw(const char* file, const unsigned int rx, const unsigned int ry, const unsigned int rz, const double vx = 1, const double vy = 1, const double vz = 1, const unsigned int offset = 0, std::size_t wdim=1, WORD_KIND wk = WK_FIXED, SIGN sign = SGN_UNSIGNED ) { return private_read(::_readImage_raw(file, rx,ry,rz, vx,vy,vz,offset, wdim, wk, sign)); } public: template Target_type trilinear_interpolation(const Coord_type&x, const Coord_type&y, const Coord_type&z, const Target_type& value_outside = Target_type(), Image_transform transform = Image_transform() ) const; // default Image_transform = CGAL::Identity template Target_type trilinear_interpolation(const Coord_type&x, const Coord_type&y, const Coord_type&z, const Target_type& value_outside = Target_type()) const { return trilinear_interpolation< Image_word_type, Target_type>(x, y, z, value_outside, CGAL::Identity()); } template Target_type labellized_trilinear_interpolation(const Coord_type&x, const Coord_type&y, const Coord_type&z, const Target_type& value_outside = Target_type()) const { CGAL::ImageIO::Indicator_factory indicator_factory; return labellized_trilinear_interpolation (x, y, z, value_outside, indicator_factory); } template Target_type labellized_trilinear_interpolation (const Coord_type&x, const Coord_type&y, const Coord_type&z, const Target_type& value_outside, const Indicator_factory indicator_factory) const; }; // end Image_3 template Target_type Image_3::trilinear_interpolation(const Coord_type& x, const Coord_type& y, const Coord_type& z, const Target_type& value_outside, Image_transform transform) const { // Check on double/float coordinates, because (int)-0.1 gives 0 if ( x < 0 || y < 0 || z < 0 ) return value_outside; const Coord_type lx = static_cast(x / image()->vx); const Coord_type ly = static_cast(y / image()->vy); const Coord_type lz = static_cast(z / image()->vz); const std::size_t dimx = xdim(); const std::size_t dimy = ydim(); const std::size_t dimz = zdim(); const std::size_t dimxy = dimx*dimy; if(lx < 0 || ly < 0 || lz < 0 || lz >= Coord_type(dimz-1) || ly >= Coord_type(dimy-1) || lx >= Coord_type(dimx-1)) { return value_outside; } // images are indexed by (z,y,x) const int i1 = (int)(lz); const int j1 = (int)(ly); const int k1 = (int)(lx); const int i2 = i1 + 1; const int j2 = j1 + 1; const int k2 = k1 + 1; /* We assume (x,y,z) lies in the following cube. * a, b, c, d, e, f, g, h are the value of the image at the corresponding * voxels: * * * x z * | / * f___ __ g * /| /| * e/_|____h/ | * | | | | * | |b___|_c| * | / | / * a|/_____d|/ _y * * * a = val(i1, j1, k1) * b = val(i2, j1, k1) * c = val(i2, j2, k1) * d = val(i1, j2, k1) * e = val(i1, j1, k2) * f = val(i2, j1, k2) * g = val(i2, j2, k2) * h = val(i1, j2, k2) */ Image_word_type* ptr = (Image_word_type*)image()->data; ptr += i1 * dimxy + j1 * dimx + k1; const Target_type a = Target_type(transform(*ptr)); const Target_type e = Target_type(transform(*(ptr+1))); ptr += dimxy; // i2 * dimxy + j1 * dimx + k1; const Target_type b = Target_type(transform(*ptr)); const Target_type f = Target_type(transform(*(ptr+1))); ptr += dimx; // i2 * dimxy + j2 * dimx + k1 const Target_type c = Target_type(transform(*ptr)); const Target_type g = Target_type(transform(*(ptr+1))); ptr -= dimxy; // i1 * dimxy + j2 * dimx + k1 const Target_type d = Target_type(transform(*ptr)); const Target_type h = Target_type(transform(*(ptr+1))); // const Target_type a = ((Image_word_type*)image()->data)[i1 * dimxy + j1 * dimx + k1]; // const Target_type b = ((Image_word_type*)image()->data)[i2 * dimxy + j1 * dimx + k1]; // const Target_type c = ((Image_word_type*)image()->data)[i2 * dimxy + j2 * dimx + k1]; // const Target_type d = ((Image_word_type*)image()->data)[i1 * dimxy + j2 * dimx + k1]; // const Target_type e = ((Image_word_type*)image()->data)[i1 * dimxy + j1 * dimx + k2]; // const Target_type f = ((Image_word_type*)image()->data)[i2 * dimxy + j1 * dimx + k2]; // const Target_type g = ((Image_word_type*)image()->data)[i2 * dimxy + j2 * dimx + k2]; // const Target_type h = ((Image_word_type*)image()->data)[i1 * dimxy + j2 * dimx + k2]; // const Target_type outside = Target_type(transform(value_outside); // if(x < 0.f || // y < 0.f || // z < 0.f || // i1 >= dimz || // j1 >= dimy || // k1 >= dimx) // { // return outside; // } // Target_type a, b, c, d, e, f, g, h; // if(k1 < 0) { // a = b = c = d = outside; // } // else { // if(j1 < 0) { // a = b = outside; // } // else { // if(i1 < 0) // a = outside; // else // a = ((Image_word_type*)image()->data)[i1 * dimxy + j1 * dimx + k1]; // if(i2 >= dimz) // b = outside; // else // b = ((Image_word_type*)image()->data)[i2 * dimxy + j1 * dimx + k1]; // } // if(j2 >= dimy) { // c = d = outside; // } // else { // if(i1 < 0) // d = outside; // else // d = ((Image_word_type*)image()->data)[i1 * dimxy + j2 * dimx + k1]; // if(i2 >= dimz) // c = outside; // else // c = ((Image_word_type*)image()->data)[i2 * dimxy + j2 * dimx + k1]; // } // } // if(k2 >= dimx) { // e = f = g = h = outside; // } // else { // if(j1 < 0) { // e = f = outside; // } // else { // if(i1 < 0) // e = outside; // else // e = ((Image_word_type*)image()->data)[i1 * dimxy + j1 * dimx + k2]; // if(i2 >= dimz) // f = outside; // else // f = ((Image_word_type*)image()->data)[i2 * dimxy + j1 * dimx + k2]; // } // if(j2 >= dimy) { // g = h = outside; // } // else { // if(i1 < 0) // h = outside; // else // h = ((Image_word_type*)image()->data)[i1 * dimxy + j2 * dimx + k2]; // if(i2 >= dimz) // g = outside; // else // g = ((Image_word_type*)image()->data)[i2 * dimxy + j2 * dimx + k2]; // } // } const Target_type di2 = i2 - lz; const Target_type di1 = lz - i1; const Target_type dj2 = j2 - ly; const Target_type dj1 = ly - j1; const Target_type dk2 = k2 - lx; const Target_type dk1 = lx - k1; // std::cerr << di2 << " " << di1 << "\n"; // std::cerr << dj2 << " " << dj1 << "\n"; // std::cerr << dk2 << " " << dk1 << "\n"; return ( ( ( a * di2 + b * di1 ) * dj2 + ( d * di2 + c * di1 ) * dj1 ) * dk2 + ( ( e * di2 + f * di1 ) * dj2 + ( h * di2 + g * di1 ) * dj1 ) * dk1 ); } // end trilinear_interpolation template Target_type Image_3::labellized_trilinear_interpolation (const Coord_type& x, const Coord_type& y, const Coord_type& z, const Target_type& value_outside, const Indicator_factory indicator_factory) const { // Check on double/float coordinates, because (int)-0.1 gives 0 if ( x < 0 || y < 0 || z < 0 ) return value_outside; Coord_type lx = x / image()->vx; Coord_type ly = y / image()->vy; Coord_type lz = z / image()->vz; const std::size_t dimx = xdim(); const std::size_t dimy = ydim(); const std::size_t dimz = zdim(); if( lx < 0 || ly < 0 || lz < 0 || lz >= Coord_type(dimz-1) || ly >= Coord_type(dimy-1) || lx >= Coord_type(dimx-1)) { return value_outside; } // images are indexed by (z,y,x) const int i1 = (int)(lz); const int j1 = (int)(ly); const int k1 = (int)(lx); const int i2 = i1 + 1; const int j2 = j1 + 1; std::array index; index[0] = (i1 * dimy + j1) * dimx + k1; index[1] = index[0] + 1; index[2] = (i1 * dimy + j2) * dimx + k1; index[3] = index[2] + 1; index[4] = (i2 * dimy + j1) * dimx + k1; index[5] = index[4] + 1; index[6] = (i2 * dimy + j2) * dimx + k1; index[7] = index[6] + 1; std::array labels; labels[0] = ((Image_word_type*)image()->data)[index[0]]; int lc = 1; for(int lci=1; lci<8; ++lci){ bool found = false; Image_word_type iwt = ((Image_word_type*)image()->data)[index[lci]]; for(int lcj=0; lcj < lc; ++lcj){ if(iwt == labels[lcj]){ found = true; break; } } if(found) continue; labels[lc] = iwt; ++lc; } CGAL_HISTOGRAM_PROFILER( "Number of labels around a vertex, Image_3::labellized_trilinear_interpolation()", static_cast(lc)); if(lc == 1) { return static_cast(labels[0]); } double best_value = 0.; Image_word_type best = 0; for(int i = 0; i < lc; ++i) { Image_word_type iwt = labels[i]; const double r = trilinear_interpolation( x, y, z, value_outside, indicator_factory.indicator(iwt)); if(r > best_value) { best = iwt; best_value = r; } } // CGAL_assertion(best_value > 0.5); return static_cast(best); } } // end namespace CGAL #ifdef CGAL_HEADER_ONLY #include #endif // CGAL_HEADER_ONLY #if defined(BOOST_MSVC) # pragma warning(pop) #endif #include #endif // CGAL_IMAGE_3_H