text: /** MxArray and ConstMap declaration.
   * @file MxArray.hpp
   * @author Kota Yamaguchi
   * @date 2012
   */
  #ifndef __MXARRAY_HPP__
  #define __MXARRAY_HPP__
  
  #include <functional>
  #include <map>
  #include <stdint.h>
  #include <string>
  #include "mex.h"
  #include "opencv2/opencv.hpp"
  
  using namespace std;
  using namespace cv;
  
  /** mxArray object wrapper for data conversion and manipulation.
   */
  class MxArray
  {
    public:
      /** MxArray constructor from mxArray*.
       * @param arr mxArray pointer given by mexFunction.
       */
      MxArray(const mxArray *arr) : p_(arr) {}
      /** Copy constructor.
       * @param arr Another MxArray.
       */
      MxArray(const MxArray& arr) : p_(arr.p_) {}
      /** Assignment operator.
       */
      MxArray& operator=(const MxArray& rhs);
      /** MxArray constructor from int.
       * @param i int value.
       */
      explicit MxArray(const int i);
      /** MxArray constructor from double.
       * @param d double value.
       */
      explicit MxArray(const double d);
      /** MxArray constructor from bool.
       * @param b bool value.
       */
      explicit MxArray(const bool b);
      /** MxArray constructor from std::string.
       * @param s reference to a string value.
       */
      explicit MxArray(const std::string& s);
      /** Convert cv::Mat to MxArray.
       * @param mat cv::Mat object.
       * @param classid classid of mxArray. e.g., mxDOUBLE_CLASS. When
       *                mxUNKNOWN_CLASS is specified, classid will be
       *                automatically determined from the type of cv::Mat.
       *                default: mxUNKNOWN_CLASS.
       * @param transpose Optional transposition to the return value so that rows
       *                  and columns of the 2D Mat are mapped to the 2nd and 1st
       *                  dimensions in MxArray, respectively. This does not
       *                  apply the N-D array conversion. default true.
       * @return MxArray object.
       *
       * Convert cv::Mat object to an MxArray. When the cv::Mat object is 2D, the
       * width, height, and channels are mapped to the first, second, and third
       * dimensions of the MxArray unless transpose flag is set to false. When
       * the cv::Mat object is N-D, (dim 1, dim 2,...dim N, channels) are mapped
       * to (dim 2, dim 1, ..., dim N, dim N+1), respectively.
       *
       * Example:
       * @code
       * cv::Mat x(120, 90, CV_8UC3, Scalar(0));
       * mxArray* plhs[0] = MxArray(x);
       * @endcode
       */
      explicit MxArray(const cv::Mat& mat,
                       mxClassID classid=mxUNKNOWN_CLASS,
                       bool transpose=true);
      /** Convert float cv::SparseMat to MxArray.
       * @param mat cv::SparseMat object.
       * @return MxArray object.
       */
      explicit MxArray(const cv::SparseMat& mat);
      /** Convert cv::Moments to MxArray.
       * @param m cv::Moments object.
       * @return MxArray object.
       */
      explicit MxArray(const cv::Moments& m);
      /** Convert cv::KeyPoint to MxArray.
       * @param p cv::KeyPoint object.
       * @return MxArray object.
       */
      explicit MxArray(const cv::KeyPoint& p);
      /** MxArray constructor from vector<KeyPoint>. Make a cell array.
       * @param v vector of KeyPoint.
       */
      explicit MxArray(const std::vector<cv::KeyPoint>& v);
      /** Convert cv::DMatch to MxArray.
       * @param m cv::DMatch object.
       * @return MxArray object.
       */
      explicit MxArray(const cv::DMatch& m);
      /** MxArray constructor from vector<T>. Make a cell array.
       * @param v vector of type T.
       */
      explicit MxArray(const std::vector<cv::DMatch>& v);
      /** Convert cv::RotatedRect to MxArray.
       * @param m cv::RotatedRect object.
       * @return MxArray object.
       */
      explicit MxArray(const cv::RotatedRect& m);
      /** Convert cv::TermCriteria to MxArray.
       * @param t cv::TermCriteria object.
       * @return MxArray object.
       */
      explicit MxArray(const cv::TermCriteria& t);
      /** MxArray constructor from vector<T>. Make a cell array.
       * @param v vector of type T.
       */
      template <typename T> explicit MxArray(const std::vector<T>& v);
      /** MxArray constructor from cv::Point_<T>.
       * @param p cv::Point_<T> object.
       * @return two-element numeric MxArray.
       */
      template <typename T> explicit MxArray(const cv::Point_<T>& p);
      /** MxArray constructor from cv::Point3_<T>.
       * @param p cv::Point3_<T> object.
       * @return three-element numeric MxArray.
       */
      template <typename T> explicit MxArray(const cv::Point3_<T>& p);
      /** MxArray constructor from cv::Size_<T>.
       * @return two-element numeric MxArray.
       */
      template <typename T> explicit MxArray(const cv::Size_<T>& s);
      /** MxArray constructor from cv::Rect_<T>.
       * @return four-element numeric MxArray [x, y, width, height].
       */
      template <typename T> explicit MxArray(const cv::Rect_<T>& r);
      /** MxArray constructor from cv::Scalar_<T>.
       * @return four-element numeric MxArray.
       */
      template <typename T> explicit MxArray(const cv::Scalar_<T>& s);
      /** Generic constructor for a struct array.
       * @param fields field names.
       * @param nfields number of field names.
       * @param m size of the first dimension.
       * @param n size of the second dimension.
       *
       * Example:
       * @code
       * const char* fields[] = {"field1", "field2"};
       * MxArray m(fields, 2);
       * m.set("field1", 1);
       * m.set("field2", "field2 value");
       * @endcode
       */
      MxArray(const char**fields, int nfields, int m=1, int n=1);
      /** Destructor. This does not free the underlying mxArray*.
       */
      virtual ~MxArray() {}
      /** Create a new cell array.
       * @param m Number of rows.
       * @param n Number of cols.
       */
      static inline MxArray Cell(int m=1, int n=1)
      {
          return MxArray(mxCreateCellMatrix(m,n));
      }
      /** Create a new struct array.
       * @param fields Field names.
       * @param nfields Number of fields.
       * @param m Number of rows.
       * @param n Number of cols.
       */
      static inline MxArray Struct(const char**fields=NULL,
                                   int nfields=0,
                                   int m=1,
                                   int n=1)
      {
          return MxArray(mxCreateStructMatrix(m, n, nfields, fields));
      }
      /** Clone mxArray. This allocates new mxArray*.
       * @return MxArray object.
       */
      MxArray clone() { return MxArray(mxDuplicateArray(p_)); }
      /** Destroy allocated mxArray. Use this to destroy a temporary mxArray not
       *  to be used in matlab.
       * @return newly allocated MxArray object.
       */
      void destroy() { mxDestroyArray(const_cast<mxArray*>(p_)); }
      /** Implicit conversion to const mxArray*.
       * @return const mxArray* pointer.
       */
      operator const mxArray*() const { return p_; };
      /** Implicit conversion to mxArray*. Be careful that this internally cast
       *  away mxArray* constness.
       * @return mxArray* pointer.
       */
      operator mxArray*() const { return const_cast<mxArray*>(p_); };
      /** Convert MxArray to int.
       * @return int value.
       */
      int toInt() const;
      /** Convert MxArray to double.
       * @return double value.
       */
      double toDouble() const;
      /** Convert MxArray to bool.
       * @return bool value.
       */
      bool toBool() const;
      /** Convert MxArray to std::string.
       * @return std::string value.
       */
      std::string toString() const;
      /** Convert MxArray to cv::Mat.
       * @param depth depth of cv::Mat. e.g., CV_8U, CV_32F.  When CV_USERTYPE1
       *                is specified, depth will be automatically determined from
       *                the classid of the MxArray. default: CV_USERTYPE1.
       * @param transpose Optional transposition to the return value so that rows
       *                  and columns of the 2D Mat are mapped to the 2nd and 1st
       *                  dimensions in MxArray, respectively. This does not
       *                  apply the N-D array conversion. default true.
       * @return cv::Mat object.
       *
       * Convert a MxArray object to a cv::Mat object. When the dimensionality of
       * the MxArray is more than 2, the last dimension will be mapped to the
       * channels of the cv::Mat. Also, if the resulting cv::Mat is 2D, the 1st
       * and 2nd dimensions of the MxArray are mapped to rows and columns of the
       * cv::Mat unless transpose flag is false. That is, when MxArray is 3D,
       * (dim 1, dim 2, dim 3) are mapped to (cols, rows, channels) of the
       * cv::Mat by default, whereas if MxArray is more than 4D, (dim 1, dim 2,
       * ..., dim N-1, dim N) are mapped to (dim 2, dim 1, ..., dim N-1,
       * channels) of the cv::Mat, respectively.
       *
       * Example:
       * @code
       * cv::Mat x(MxArray(prhs[0]).toMat());
       * @endcode
       */
      cv::Mat toMat(int depth=CV_USRTYPE1, bool transpose=true) const;
      /** Convert MxArray to a single-channel cv::Mat.
       * @param depth depth of cv::Mat. e.g., CV_8U, CV_32F.  When CV_USERTYPE1
       *              is specified, depth will be automatically determined from
       *              the the classid of the MxArray. default: CV_USERTYPE1.
       * @param transpose Optional transposition to the return value so that rows
       *                  and columns of the 2D Mat are mapped to the 2nd and 1st
       *                  dimensions in MxArray, respectively. This does not
       *                  apply the N-D array conversion. default true.
       * @return const cv::Mat object.
       *
       * Convert a MxArray object to a single-channel cv::Mat object. If the
       * MxArray is 2D, the 1st and 2nd dimensions of the MxArray are mapped to
       * rows and columns of the cv::Mat unless transpose flag is false. If the
       * MxArray is more than 3D, the 1st and 2nd dimensions of the MxArray are
       * mapped to 2nd and 1st dimensions of the cv::Mat. That is, when MxArray
       * is 2D, (dim 1, dim 2) are mapped to (cols, rows) of the cv::Mat by
       * default, whereas if MxArray is more than 3D, (dim 1, dim 2, dim 3, ...,
       * dim N) are mapped to (dim 2, dim 1, dim 3, ..., dim N) of the cv::Mat,
       * respectively.
       *
       * Example:
       * @code
       * cv::Mat x(MxArray(prhs[0]).toMatND());
       * @endcode
       */
      cv::MatND toMatND(int depth=CV_USRTYPE1, bool transpose=true) const;
      /** Convert double sparse MxArray to float cv::SparseMat.
       * @return cv::SparseMat object.
       */
      cv::SparseMat toSparseMat() const;
      /** Convert MxArray to cv::Moments.
       * @param index index of the struct array.
       * @return cv::Moments.
       */
      cv::Moments toMoments(mwIndex index=0) const;
      /** Convert MxArray to cv::KeyPoint.
       * @param index index of the struct array.
       * @return cv::KeyPoint.
       */
      cv::KeyPoint toKeyPoint(mwIndex index=0) const;
      /** Convert MxArray to cv::DMatch.
       * @param index index of the struct array.
       * @return cv::DMatch.
       */
      cv::DMatch toDMatch(mwIndex index=0) const;
      /** Convert MxArray to cv::Range.
       * @return cv::Range.
       */
      cv::Range toRange() const;
      /** Convert MxArray to cv::TermCriteria.
       * @param index index of the struct array.
       * @return cv::TermCriteria.
       */
      cv::TermCriteria toTermCriteria(mwIndex index=0) const;
      /** Convert MxArray to Point_<T>.
       * @return cv::Point_<T> value.
       */
      template <typename T> cv::Point_<T> toPoint_() const;
      /** Convert MxArray to Point3_<T>.
       * @return cv::Poin3_<T> value.
       */
      template <typename T> cv::Point3_<T> toPoint3_() const;
      /** Convert MxArray to Size_<T>.
       * @return cv::Size_<T> value.
       */
      template <typename T> cv::Size_<T> toSize_() const;
      /** Convert MxArray to Rect_<T>.
       * @return cv::Rect_<T> value.
       */
      template <typename T> cv::Rect_<T> toRect_() const;
      /** Convert MxArray to Scalar_<T>.
       * @return cv::Scalar_<T> value.
       */
      template <typename T> cv::Scalar_<T> toScalar_() const;
      /** Convert MxArray to std::vector<T> for a primitive type.
       * @return std::vector<T> value.
       *
       * The method is intended for conversion to a raw numeric vector such
       * as std::vector<int> or std::vector<double>. Example:
       *
       * @code
       * MxArray numArray(prhs[0]);
       * vector<double> vd = numArray.toVector<double>();
       * @endcode
       */
      template <typename T> std::vector<T> toVector() const;
      /** Convert MxArray to std::vector<T> by a specified conversion method.
       * @param f member function of MxArray (e.g., &MxArray::toMat,
       *          &MxArray::toInt).
       * @return std::vector<T> value.
       *
       * The method constructs std::vector<T> by applying conversion method f to
       * each cell array element. This is similar to std::transform function. An
       * example usage is shown below:
       *
       * @code
       * MxArray cellArray(prhs[0]);
       * const_mem_fun_ref_t<Point3i,MxArray> converter(&MxArray::toPoint3_<int>);
       * vector<Point3i> v = cellArray.toVector(converter);
       * @endcode
       */
      template <typename T>
      std::vector<T> toVector(std::const_mem_fun_ref_t<T, MxArray> f) const;
      /** Alias to toPoint_<int>.
       */
      inline cv::Point toPoint() const { return toPoint_<int>(); }
      /** Alias to toPoint_<float>.
       */
      inline cv::Point2f toPoint2f() const { return toPoint_<float>(); }
      /** Alias to toPoint3_<float>.
       */
      inline cv::Point3f toPoint3f() const { return toPoint3_<float>(); }
      /** Alias to toSize_<int>.
       */
      inline cv::Size toSize() const { return toSize_<int>(); }
      /** Alias to toRect_<int>.
       */
      inline cv::Rect toRect() const { return toRect_<int>(); }
      /** Alias to toScalar_<double>
       */
      inline cv::Scalar toScalar() const { return toScalar_<double>(); }   
  
      /** Class ID of mxArray.
       */
      inline mxClassID classID() const { return mxGetClassID(p_); }
      /** Class name of mxArray.
       */
      inline const std::string className() const
      {
          return std::string(mxGetClassName(p_));
      }
      /** Number of elements in an array.
       */
      inline mwSize numel() const { return mxGetNumberOfElements(p_); }
      /** Number of dimensions.
       */
      inline mwSize ndims() const { return mxGetNumberOfDimensions(p_); }
      /** Array of each dimension.
       */
      inline const mwSize* dims() const { return mxGetDimensions(p_); };
      /** Number of rows in an array.
       */
      inline mwSize rows() const { return mxGetM(p_); }
      /** Number of columns in an array.
       */
      inline mwSize cols() const { return mxGetN(p_); }
      /** Number of fields in a struct array.
       */
      inline int nfields() const { return mxGetNumberOfFields(p_); }
      /** Get field name of a struct array.
       * @param index index of the struct array.
       * @return std::string.
       */
      std::string fieldname(int index=0) const;
      /** Get field names of a struct array.
       * @return std::string.
       */
      std::vector<std::string> fieldnames() const;
      /** Number of elements in IR, PR, and PI arrays.
       */
      inline mwSize nzmax() const { return mxGetNzmax(p_); }
      /** Offset from first element to desired element.
       * @param i index of the first dimension of the array.
       * @param j index of the second dimension of the array.
       * @return linear offset of the specified subscript index.
       */
      mwIndex subs(mwIndex i, mwIndex j=0) const;
      /** Offset from first element to desired element.
       * @param si subscript index of the array.
       * @return linear offset of the specified subscript index.
       */
      mwIndex subs(const std::vector<mwIndex>& si) const;
      /** Determine whether input is cell array.
       */
      inline bool isCell() const { return mxIsCell(p_); }
      /** Determine whether input is string array.
       */
      inline bool isChar() const { return mxIsChar(p_); }
      /** Determine whether array is member of specified class.
       */
      inline bool isClass(std::string s) const
      {
          return mxIsClass(p_, s.c_str());
      }
      /** Determine whether data is complex.
       */
      inline bool isComplex() const { return mxIsComplex(p_); }
      /** Determine whether mxArray represents data as double-precision,
       * floating-point numbers.
       */
      inline bool isDouble() const { return mxIsDouble(p_); }
      /** Determine whether array is empty.
       */
      inline bool isEmpty() const { return mxIsEmpty(p_); }
      /** Determine whether input is finite.
       */
      static inline bool isFinite(double d) { return mxIsFinite(d); }
      /** Determine whether array was copied from MATLAB global workspace.
       */
      inline bool isFromGlobalWS() const { return mxIsFromGlobalWS(p_); };
      /** Determine whether input is infinite.
       */
      static inline bool isInf(double d) { return mxIsInf(d); }
      /** Determine whether array represents data as signed 8-bit integers.
       */
      inline bool isInt8() const { return mxIsInt8(p_); }
      /** Determine whether array represents data as signed 16-bit integers.
       */
      inline bool isInt16() const { return mxIsInt16(p_); }
      /** Determine whether array represents data as signed 32-bit integers.
       */
      inline bool isInt32() const { return mxIsInt32(p_); }
      /** Determine whether array represents data as signed 64-bit integers.
       */
      inline bool isInt64() const { return mxIsInt64(p_); }
      /** Determine whether array is of type mxLogical.
       */
      inline bool isLogical() const { return mxIsLogical(p_); }
      /** Determine whether scalar array is of type mxLogical.
       */
      inline bool isLogicalScalar() const { return mxIsLogicalScalar(p_); }
      /** Determine whether scalar array of type mxLogical is true.
       */
      inline bool isLogicalScalarTrue() const
      {
          return mxIsLogicalScalarTrue(p_);
      }
      /** Determine whether array is numeric.
       */
      inline bool isNumeric() const { return mxIsNumeric(p_); }
      /** Determine whether array represents data as single-precision,
       * floating-point numbers.
       */
      inline bool isSingle() const { return mxIsSingle(p_); }
      /** Determine whether input is sparse array.
       */
      inline bool isSparse() const { return mxIsSparse(p_); }
      /** Determine whether input is structure array.
       */
      inline bool isStruct() const { return mxIsStruct(p_); }
      /** Determine whether array represents data as unsigned 8-bit integers.
       */
      inline bool isUint8() const { return mxIsUint8(p_); }
      /** Determine whether array represents data as unsigned 16-bit integers.
       */
      inline bool isUint16() const { return mxIsUint16(p_); }
      /** Determine whether array represents data as unsigned 32-bit integers.
       */
      inline bool isUint32() const { return mxIsUint32(p_); }
      /** Determine whether array represents data as unsigned 64-bit integers.
       */
      inline bool isUint64() const { return mxIsUint64(p_); }
      /** Determine whether a struct array has a specified field.
       */
      bool isField(const std::string& fieldName, mwIndex index=0) const
      {
          return isStruct() &&
                 mxGetField(p_, index, fieldName.c_str()) != NULL;
      }
      /** Template for element accessor.
       * @param index index of the array element.
       * @return value of the element at index.
       *
       * Example:
       * @code
       * MxArray m(prhs[0]);
       * double d = m.at<double>(0);
       * @endcode
       */
      template <typename T> T at(mwIndex index) const;
      /** Template for element accessor.
       * @param i index of the first dimension.
       * @param j index of the second dimension.
       * @return value of the element at (i,j).
       */
      template <typename T> T at(mwIndex i, mwIndex j) const;
      /** Template for element accessor.
       * @param si subscript index of the element.
       * @return value of the element at subscript index.
       */
      template <typename T> T at(const std::vector<mwIndex>& si) const;
      /** Struct element accessor.
       * @param fieldName field name of the struct array.
       * @param index index of the struct array.
       * @return value of the element at the specified field.
       */
      MxArray at(const std::string& fieldName, mwIndex index=0) const;
      /** Template for element write accessor.
       * @param index offset of the array element.
       * @param value value of the field.
       */
      template <typename T> void set(mwIndex index, const T& value);
      /** Template for element write accessor.
       * @param i index of the first dimension of the array element.
       * @param j index of the first dimension of the array element.
       * @param value value of the field.
       */
      template <typename T> void set(mwIndex i, mwIndex j, const T& value);
      /** Template for element write accessor.
       * @param si subscript index of the element.
       * @param value value of the field.
       */
      template <typename T> void set(const std::vector<mwIndex>& si,
                                     const T& value);
      /** Template for struct element write accessor.
       * @param fieldName field name of the struct array.
       * @param value value of the field.
       * @param index linear index of the struct array element.
       */
      template <typename T> void set(const std::string& fieldName,
                                     const T& value,
                                     mwIndex index=0);
      /** Determine whether input is NaN (Not-a-Number).
       */
      static inline bool isNaN(double d) { return mxIsNaN(d); }
      /** Value of infinity.
       */
      static inline double Inf() { return mxGetInf(); }
      /** Value of NaN (Not-a-Number).
       */
      static inline double NaN() { return mxGetNaN(); }
      /** Value of EPS.
       */
      static inline double Eps() { return mxGetEps(); }
    private:
      /** mxArray c object.
       */
      const mxArray* p_;
  };
  
  /** std::map wrapper with one-line initialization and lookup method.
   * Initialization
   * @code
   * const ConstMap<std::string,int> BorderType = ConstMap<std::string,int>
   *     ("Replicate",  cv::BORDER_REPLICATE)
   *     ("Constant",   cv::BORDER_CONSTANT)
   *     ("Reflect",    cv::BORDER_REFLECT);
   * @endcode
   * Lookup
   * @code
   * BorderType["Constant"] // => cv::BORDER_CONSTANT
   * @endcode
   */
  template <typename T, typename U>
  class ConstMap
  {
    public:
      /// Constructor with a single key-value pair
      ConstMap(const T& key, const U& val)
      {
          m_[key] = val;
      }
      /// Consecutive insertion operator
      ConstMap<T, U>& operator()(const T& key, const U& val)
      {
          m_[key] = val;
          return *this;
      }
      /// Implicit converter to std::map
      operator std::map<T, U>() { return m_; }
      /// Lookup operator; fail if not found
      U operator [](const T& key) const
      {
          typename std::map<T,U>::const_iterator it = m_.find(key);
          if (it==m_.end())
              mexErrMsgIdAndTxt("mexopencv:error", "Value not found");
          return (*it).second;
      }
    private:
      std::map<T, U> m_;
  };
  
  template <typename T>
  MxArray::MxArray(const std::vector<T>& v) : p_(mxCreateCellMatrix(1, v.size()))
  {
      if (!p_)
          mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
      for (int i = 0; i < v.size(); ++i)
          mxSetCell(const_cast<mxArray*>(p_), i, MxArray(v[i]));
  }
  
  template <typename T>
  MxArray::MxArray(const cv::Point_<T>& p) :
      p_(mxCreateNumericMatrix(1, 2, mxDOUBLE_CLASS,mxREAL))
  {
      if (!p_)
          mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
      double *x = mxGetPr(p_);
      x[0] = p.x;
      x[1] = p.y;
  }
  
  template <typename T>
  MxArray::MxArray(const cv::Point3_<T>& p) :
      p_(mxCreateNumericMatrix(1, 3, mxDOUBLE_CLASS,mxREAL))
  {
      if (!p_)
          mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
      double *x = mxGetPr(p_);
      x[0] = p.x;
      x[1] = p.y;
      x[2] = p.z;
  }
  
  template <typename T>
  MxArray::MxArray(const cv::Size_<T>& s) :
      p_(mxCreateNumericMatrix(1, 2, mxDOUBLE_CLASS, mxREAL))
  {
      if (!p_)
          mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
      double *x = mxGetPr(p_);
      x[0] = s.width;
      x[1] = s.height;
  }
  
  template <typename T>
  MxArray::MxArray(const cv::Rect_<T>& r) :
      p_(mxCreateNumericMatrix(1, 4, mxDOUBLE_CLASS,mxREAL))
  {
      if (!p_)
          mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
      double *x = mxGetPr(p_);
      x[0] = r.x;
      x[1] = r.y;
      x[2] = r.width;
      x[3] = r.height;
  }
  
  template <typename T>
  MxArray::MxArray(const cv::Scalar_<T>& s) :
      p_(mxCreateNumericMatrix(1, 4, mxDOUBLE_CLASS,mxREAL))
  {
      if (!p_)
          mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
      double *x = mxGetPr(p_);
      x[0] = s[0];
      x[1] = s[1];
      x[2] = s[2];
      x[3] = s[3];
  }
  
  template <typename T>
  cv::Point_<T> MxArray::toPoint_() const
  {
      if (!isNumeric() || numel()!=2)
          mexErrMsgIdAndTxt("mexopencv:error", "MxArray is not a Point");
      return cv::Point_<T>(at<T>(0), at<T>(1));
  }
  
  template <typename T>
  cv::Point3_<T> MxArray::toPoint3_() const
  {
      if (!isNumeric() || numel()!=3)
          mexErrMsgIdAndTxt("mexopencv:error", "MxArray is not a Point");
      return cv::Point3_<T>(at<T>(0), at<T>(1), at<T>(2));
  }
  
  template <typename T>
  cv::Size_<T> MxArray::toSize_() const
  {
      if (!isNumeric() || numel()!=2)
          mexErrMsgIdAndTxt("mexopencv:error",
                            "MxArray is incompatible to cv::Size");
      return cv::Size_<T>(at<T>(0), at<T>(1));
  }
  
  template <typename T>
  cv::Rect_<T> MxArray::toRect_() const
  {
      if (!isNumeric() || numel()!=4)
          mexErrMsgIdAndTxt("mexopencv:error",
                            "MxArray is incompatible to cv::Rect");
      return cv::Rect_<T>(at<T>(0), at<T>(1), at<T>(2), at<T>(3));
  }
  
  template <typename T>
  cv::Scalar_<T> MxArray::toScalar_() const
  {
      int n = numel();
      if (!isNumeric() || n < 1 || 4 < n)
          mexErrMsgIdAndTxt("mexopencv:error",
                            "MxArray is incompatible to cv::Scalar");
      switch (n)
      {
          case 1: return cv::Scalar_<T>(at<T>(0));
          case 2: return cv::Scalar_<T>(at<T>(0), at<T>(1));
          case 3: return cv::Scalar_<T>(at<T>(0), at<T>(1), at<T>(2));
          case 4: return cv::Scalar_<T>(at<T>(0), at<T>(1), at<T>(2), at<T>(3));
      }
  }
  
  template <typename T>
  std::vector<T> MxArray::toVector() const
  {
      int n = numel();
      std::vector<T> vt(n);
      if (isNumeric())
          for (int i = 0; i < n; ++i)
              vt[i] = at<T>(i);
      else if (isCell())
          for (int i = 0; i < n; ++i)
              vt[i] = MxArray(mxGetCell(p_, i)).at<T>(0);
      else
          mexErrMsgIdAndTxt("mexopencv:error", "Cannot convert to std::vector");
      return vt;
  }
  
  template <typename T>
  std::vector<T> MxArray::toVector(std::const_mem_fun_ref_t<T,MxArray> f) const
  {
      std::vector<MxArray> v = toVector<MxArray>();
      std::vector<T> vt;
      vt.reserve(v.size());
      for (std::vector<MxArray>::iterator it=v.begin(); it<v.end(); ++it)
          vt.push_back(f(*it));
      return vt;
  }
  
  template <typename T>
  T MxArray::at(mwIndex index) const
  {
      if (!p_ || numel() <= index)
          mexErrMsgIdAndTxt("mexopencv:error", "Accessing invalid range");
      switch (classID())
      {
          case mxCHAR_CLASS:
              return static_cast<T>(*(mxGetChars(p_)+index));
          case mxDOUBLE_CLASS:
              return static_cast<T>(*(mxGetPr(p_)+index));
          case mxINT8_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<int8_t*>(mxGetData(p_))+index));
          case mxUINT8_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<uint8_t*>(mxGetData(p_))+index));
          case mxINT16_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<int16_t*>(mxGetData(p_))+index));
          case mxUINT16_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<uint16_t*>(mxGetData(p_))+index));
          case mxINT32_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<int32_t*>(mxGetData(p_))+index));
          case mxUINT32_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<uint32_t*>(mxGetData(p_))+index));
          case mxINT64_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<int64_t*>(mxGetData(p_))+index));
          case mxUINT64_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<uint64_t*>(mxGetData(p_))+index));
          case mxSINGLE_CLASS:
              return static_cast<T>(
                  *(reinterpret_cast<float*>(mxGetData(p_))+index));
          case mxLOGICAL_CLASS:
              return static_cast<T>(*(mxGetLogicals(p_)+index));
          case mxCELL_CLASS:
          case mxSTRUCT_CLASS:
          case mxFUNCTION_CLASS:
          default:
              mexErrMsgIdAndTxt("mexopencv:error", "MxArray is not primitive");
              return static_cast<T>(0);
      }
  }
  
  template <typename T>
  T MxArray::at(mwIndex i, mwIndex j) const
  {
      return at<T>(subs(i,j));
  }
  
  template <typename T>
  T MxArray::at(const std::vector<mwIndex>& si) const
  {
      return at<T>(subs(si));
  }
  
  template <typename T>
  void MxArray::set(mwIndex index, const T& value)
  {
      if (index < 0 || numel() <= index)
          mexErrMsgIdAndTxt("mexopencv:error", "Accessing invalid range");
      switch (classID())
      {
          case mxCHAR_CLASS:
              *(mxGetChars(p_)+index) = static_cast<mxChar>(value); break;
          case mxDOUBLE_CLASS:
              *(mxGetPr(p_)+index) = static_cast<double>(value); break;
          case mxINT8_CLASS:
              *(reinterpret_cast<int8_t*>(mxGetData(p_))+index) =
                  static_cast<int8_t>(value); break;
          case mxUINT8_CLASS:
              *(reinterpret_cast<uint8_t*>(mxGetData(p_))+index) =
                  static_cast<uint8_t>(value); break;
          case mxINT16_CLASS:
              *(reinterpret_cast<int16_t*>(mxGetData(p_))+index) =
                  static_cast<int16_t>(value); break;
          case mxUINT16_CLASS:
              *(reinterpret_cast<uint16_t*>(mxGetData(p_))+index) =
                  static_cast<uint16_t>(value); break;
          case mxINT32_CLASS:
              *(reinterpret_cast<int32_t*>(mxGetData(p_))+index) =
                  static_cast<int32_t>(value); break;
          case mxUINT32_CLASS:
              *(reinterpret_cast<uint32_t*>(mxGetData(p_))+index) =
                  static_cast<uint32_t>(value); break;
          case mxINT64_CLASS:
              *(reinterpret_cast<int64_t*>(mxGetData(p_))+index) =
                  static_cast<int64_t>(value); break;
          case mxUINT64_CLASS:
              *(reinterpret_cast<uint64_t*>(mxGetData(p_))+index) =
                  static_cast<uint64_t>(value); break;
          case mxSINGLE_CLASS:
              *(reinterpret_cast<float*>(mxGetData(p_))+index) =
                  static_cast<float>(value); break;
          case mxLOGICAL_CLASS:
              *(mxGetLogicals(p_)+index) = static_cast<mxLogical>(value); break;
          case mxCELL_CLASS:
              mxSetCell(const_cast<mxArray*>(p_), index, MxArray(value)); break;
          case mxSTRUCT_CLASS:
          case mxFUNCTION_CLASS:
          default:
              mexErrMsgIdAndTxt("mexopencv:error", "MxArray type is not valid");
      }
  }
  
  template <typename T>
  void MxArray::set(mwIndex i, mwIndex j, const T& value)
  {
      set<T>(subs(i,j),value);
  }
  
  template <typename T>
  void MxArray::set(const std::vector<mwIndex>& si, const T& value)
  {
      set<T>(subs(si),value);
  }
  
  template <typename T>
  void MxArray::set(const std::string& fieldName, const T& value, mwIndex index)
  {
      if (!isStruct())
          mexErrMsgIdAndTxt("mexopencv:error", "MxArray is not struct");
      if (!isField(fieldName))
      {
          if (mxAddField(const_cast<mxArray*>(p_), fieldName.c_str())<0)
              mexErrMsgIdAndTxt("mexopencv:error",
                                "Failed to create a field '%s'",
                                fieldName.c_str());
      }
      mxSetField(const_cast<mxArray*>(p_), index, fieldName.c_str(),
                 static_cast<mxArray*>(MxArray(value)));
  }
  
  /** Cell element accessor.
   * @param index index of the cell array.
   * @return MxArray of the element at index.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * MxArray m = cellArray.at<MxArray>(0);
   * @endcode
   */
  template <> MxArray MxArray::at(mwIndex index) const;
  
  /** Template for element write accessor.
   * @param index offset of the array element.
   * @param value value of the field.
   */
  template <> void MxArray::set(mwIndex index, const MxArray& value);
  
  /** Convert MxArray to std::vector<MxArray>.
   * @return std::vector<MxArray> value.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * vector<MxArray> v = cellArray.toVector<MxArray>();
   * @endcode
   */
  template <> std::vector<MxArray> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<std::string>.
   * @return std::vector<std::string> value.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * vector<string> v = cellArray.toVector<string>();
   * @endcode
   */
  template <> std::vector<std::string> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<cv::Mat>.
   * @return std::vector<cv::Mat> value.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * vector<Mat> v = cellArray.toVector<Mat>();
   * @endcode
   */
  template <> std::vector<cv::Mat> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<Point>.
   * @return std::vector<Point> value.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * vector<Point> v = cellArray.toVector<Point>();
   * @endcode
   */
  template <> std::vector<cv::Point> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<Point2f>.
   * @return std::vector<Point2f> value.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * vector<Point2f> v = cellArray.toVector<Point2f>();
   * @endcode
   */
  template <> std::vector<cv::Point2f> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<Point3f>.
   * @return std::vector<Point3f> value.
   *
   * Example:
   * @code
   * MxArray cellArray(prhs[0]);
   * vector<Point3f> v = cellArray.toVector<Point3f>();
   * @endcode
   */
  template <> std::vector<cv::Point3f> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<cv::KeyPoint>.
   * @return std::vector<cv::KeyPoint> value.
   *
   * Example:
   * @code
   * MxArray structArray(prhs[0]);
   * vector<KeyPoint> v = structArray.toVector<KeyPoint>();
   * @endcode
   */
  template <> std::vector<cv::KeyPoint> MxArray::toVector() const;
  
  /** Convert MxArray to std::vector<cv::DMatch>.
   * @return std::vector<cv::DMatch> value.
   *
   * Example:
   * @code
   * MxArray structArray(prhs[0]);
   * vector<DMatch> v = structArray.toVector<DMatch>();
   * @endcode
   */
  template <> std::vector<cv::DMatch> MxArray::toVector() const;
  
  #endif // __MXARRAY_HPP__
  