Skip to content
Snippets Groups Projects
splinterpolator.h 6.43 KiB
Newer Older
//  
//  splinterpolator.h
//
// Jesper Andersson, FMRIB Image Analysis Group
//
// Copyright (C) 2008 University of Oxford 
//
//     CCOPYRIGHT
//

#ifndef splinterpolator_h
#define splinterpolator_h

#include <vector>
#include <string>
#include <cmath>
#include "newmat.h"
#include "miscmaths/miscmaths.h"

namespace SPLINTERPOLATOR {

enum ExtrapolationType {Zeros, Constant, Mirror, Periodic};

class SplinterpolatorException: public std::exception
{
private:
  std::string m_msg;
public:
  SplinterpolatorException(const std::string& msg) throw(): m_msg(msg) {}

  virtual const char *what() const throw() {
    return string("FslSplines::" + m_msg).c_str();
  }

  ~SplinterpolatorException() throw() {}
};

template<class T>
class Splinterpolator
{
public:
  // Constructors
  Splinterpolator() : _valid(false) {}
  Splinterpolator(const T *data, const std::vector<unsigned int>& dim, unsigned int order=3, std::vector<ExtrapolationType> et(3,Zeros))
  {
    common_construction(data,dim,order,et);
  }
  Splinterpolator(const T *data, const std::vector<unsigned int>& dim, unsigned int order, ExtrapolationType et)
  {
    std::vector<ExtrapolationType>   ett(dim.size(),et);
    common_construction(data,dim,order,ett);
  }
  // Destructor
  ~Splinterpolator() { if(_valid) delete [] _coef; }

  //
  // Here we declare nested helper-class SplineColumn
  //
  class SplineColumn
  {
  public:
    // Constructor
    SplineColumn(unsigned int sz, unsigned int step) : _sz(sz), _step(step) { _col = new double[_sz]; }
    // Destructor
    ~SplineColumn() { delete [] _col; }
    // Extract a column from a volume
    Get(const T  *dp)
    {
      for (unsigned int i=0; i<_sz; i++, dp+=_step) _col[i] = static_cast<double>(*dp);
    }
    // Insert column into volume
    Set(T *dp)
    {
      T   test = 1.5;
      if (test == 1) {  // If T is not float or double
        for (unsigned int i=0; i<_sz; i++, dp+=_step) *dp = static_cast<T>(_col[i] + 0.5);   // Round to nearest integer
      }
      else {
        for (unsigned int i=0; i<_sz; i++, dp+=_step) *dp = static_cast<T>(_col[i]);
      }
    }
    // Deconvolve column
    Deconv(unsigned int order, ExtrapolationType et) {};

  private:
    unsigned int  _sz;
    unsigned int  _step;
    double        *_col;

    SplineColumn(const SplineColumn& sc);              // Don't allow copy-construction
    SplineColumn& operator=(const SplineColumn& sc);   // Dont allow assignment
  };

  void Set(const T *data, const std::vector<unsigned int>& dim, unsigned int order=3, std::vector<ExtrapolationType> et(3,Zeros))
  {
    if (_valid) delete [] _coef;
    common_construction(data,dim,order,et);
  }
  
private:
  bool                            _valid;         // Decides if neccessary information has been set or not
  T                               *_coef;         // Volume of spline coefficients
  unsigned int                    _order;         // Order of splines
  std::vector<unsigned int>       _dim;           // Dimensions of data
  std::vector<ExtrapolationType>  _et;            // How to do extrapolation
  //
  // Private helper-functions
  //
  void common_construction(const T *data, const std::vector<unsigned int>& dim, unsigned int order, const std::vector<ExtrapolationType>& et);
  void calc_coef(const T *data);
  void deconv_along(unsigned int dim);
  //
  // Disallowed member functions
  //
  Splinterpolator(const Splinterpolator& s);             // Don't allow copy-construction
  Splinterpolator& operator=(const Splinterpolator& s);  // Don't allow assignment
};

template<class T>
void Splinterpolator<T>::common_construction(const T *data, const std::vector<unsigned int>& dim, unsigned int order, const std::vector<ExtrapolationType>& et)
{
  if (!dim.size()) throw SplinterpolatorException("Splinterpolator::common_construction: data has zeros dimensions");
  if (!dim.size() > 5) throw SplinterpolatorException("Splinterpolator::common_construction: data cannot have more than 5 dimensions");
  if (dim.size() != et.size()) throw SplinterpolatorException("Splinterpolator::common_construction: dim and et must have the same size");
  for (unsigned int i=0; i<dim.size(); i++) if (!dim[i]) throw SplinterpolatorException("Splinterpolator::common_construction: data cannot have zeros size in any direction");
  if (order > 7) throw SplinterpolatorException("Splinterpolator::common_construction: spline order must be lesst than 7");
  if (!data) throw SplinterpolatorException("Splinterpolator::common_construction: zero data pointer");
  
  for (unsigned int ts=1, i=0; i<dim.size(); i++) ts *= dim[i];
  _coef = new T[ts];
  _order = order;
  _dim.resize(5); = dim;
  _et = et;

  calc_coef(data);

  _valid = true;
}

template<class T>
void Splinterpolator<T>::calc_coef(const T *data)
{
  // Put the original data into _coef
  //
  for (unsigned int ts=1, i=0; i<dim.size(); i++) ts *= dim[i];
  memcpy(_coef,data,ts*sizeof(T));

  if (_order < 2) return;  // If nearest neighbour or linear, that's all we need 

  // Loop over all non-singleton dimensions and deconvolve along them
  //
  std::vector<unsigned int>  tdim(dim.size()-1,0); 
  for (unsigned int cdir=0; cdir<dim.size(); cdir++) {
    if (dim[cdir] > 1) deconv_along(cdir)
  }

  return;
}

template<class T>
void Splinterpolator<T>::deconv_along(unsigned int dim);
{
  T  *dp = _coef;

  // Set up to reflect "missing" dimension
  //
  std::vector<unsigned int>   rdim(4,1);     // Sizes along remaining dimensions
  std::vector<unsigned int>   rstep(4,1);    // Step-sizes (in "volume") of remaining dimensions
  unsigned int                mdim = 1;      // Size along "missing" dimension
  unsigned int                mstep = 1;     // Step-size along "missing" dimension
  for (unsigned int i=0, j=0, s=1; i<5; i++) {
    if (i == dim) {  // If it is our "missing" dimension
      mdim = _dim(i);
      mstep = ss;
    }
    else {
      rdim[j] = _dim[i];
      rstep[j++] = ss;
    }
    ss *= _dim[i];
  }

  SplineColumn<T>  col(mdim,mstep);           // Column helps us do the job

  for (unsigned int l=0; l<rdim[3]; l++, dp+=rstep[3]) {
    for (unsigned int k=0; k<rdim[2]; k++, dp+=rstep[2]) {
      for (unsigned int j=0; j<rdim[1]; j++, dp+=rstep[1]) {
	for (unsigned int i=0; i<rdim[0]; i++, dp+=rstep[0]) {
	  col.Get(dp);     // Extract a column from the volume
          col.Deconv(_order,_et[dim]);    // Deconvolve it
          col.Set(dp);     // Put back the deconvolved column
	}
      }
    }
  }
  return;
}

} // End namespace SPLINTERPOLATOR

#endif // End #ifndef splinterpolator.h