--- a +++ b/Thoracic Organs Segmentation code/OpticalFlow3D/cimgmatlab.h @@ -0,0 +1,387 @@ +/************************************************************************* + * cimgmatlab.h + * ------------- + * + * cimgmatlab.h is a "plugin" for the CImg library that allows to convert + * CImg<T> images from/to MATLAB arrays, so that CImg can be used to write + * MATLAB mex files. It also swaps the "x" and "y" coordinates when going + * from / to MATLAB array, i.e. the usual image-processing annoying MATLAB + * behaviour of considering images as matrices. + * + * Added to the CImg<T> class are: + * + * - a constructor : CImg(const mxArray *matlabArray, bool vdata = false) + * the vdata serves to decide whether a 3D matlab array should give + * rise to a 3D CImg object or a "2D vectorial" one. + * + * - a assignment operator : CImg & operator=(const mxArray *matlabArray) + * (I use myself extremely seldom and might remove it in the future). + * + * - a routine converting a CImg image to a matlab array: + * mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS, + * bool squeeze = false) const + * the squeeze argument serves the opposite purpose than the vdata from + * the constructor. + * + * For a bit more documentation, the manual is this header, see the more + * detailed comments in the source code (i.e. RTFM) + * + * + * Its usage should be straightforward: + * + * - file cimgmatlab.h must be in a directory that the compiler can locate. + * - prior to include CImg.h, mex.h must be included first, else it will + * result in a compiler error. + * - after the inclusion of mex.h, one must define the macro cimg_plugin as + * "cimgmatlab.h" or <cimgmatlab.h> or <CImg/plugins/cimgmatlab.h> or + * a variation that matches your local installation of CImg package and + * plugins probably via the appropriate specification of the include path + * "-Ipath/to/cimg/and/plugins" at mex cmdline. + * + * You would probably have this kind of declaration: + * + * // The begining of my fantastic mex file code... + * #include <mex.h> + * ... + * #define cimg_plugin <cimgmatlab.h> + * #include <CImg.h> + * ... + * // and now I can implement my new killer MATLAB function! + * .... + * + * + * Copyright (c) 2004-2008 Francois Lauze + * Licence: the Gnu Lesser General Public License + * http://www.gnu.org/licenses/lgpl.html + * + * MATLAB is copyright of The MathWorks, Inc, http://www.mathworks.com + * + * Any comments, improvements and potential bug corrections are welcome, so + * write to me at francois@diku.dk, or use CImg forums, I promise I'll try + * to read them once in a while. BTW who modified the cpMatlabData with the + * cimg::type<t>::is_float() test (good idea!) + * + ***************************************************************************/ + +#define CIMGMATLAB_VER 0102 +#ifndef mex_h +#error the file mex.h must be included prior to inclusion of cimgmatlab.h +#endif +#ifndef cimg_version +#error cimgmatlab.h requires that CImg.h is included! +#endif + +/********************************************************** + * introduction of mwSize and mwIndex types in relatively * + * recent versions of matlab, 7.3.0 from what I gathered. * + * here is hopefully a needed fix for older versions * + **********************************************************/ +#if !defined(MX_API_VER) || MX_API_VER < 0x7030000 +typedef int mwSize; +#endif + +/********************************************************* + * begin of included methods * + * They are just added as member functions / constructor * + * for the CImg<T> class. * + *********************************************************/ + +private: + /********************************************************************** + * internally used to transfer MATLAB array values to CImg<> objects, + * check wether the array type is a "numerical" one (including logical) + */ + static int isNumericalClassID(mxClassID id) + { + // all these constants are defined in matrix.h included by mex.h + switch (id) { + case mxLOGICAL_CLASS: + case mxDOUBLE_CLASS: + case mxSINGLE_CLASS: + case mxINT8_CLASS: + case mxUINT8_CLASS: + case mxINT16_CLASS: + case mxUINT16_CLASS: + case mxINT32_CLASS: + case mxUINT32_CLASS: + case mxINT64_CLASS: + case mxUINT64_CLASS: + return 1; + default: + return 0; + } + } + + /*************************************************** + * driving routine that will copy the content of + * a MATLAB array to this->data + * The type names used are defined in matlab c/c++ + * header file tmwtypes.h + */ + void makeImageFromMatlabData(const mxArray *matlabArray, mxClassID classID) + { + if (classID == mxLOGICAL_CLASS) + { + // logical type works a bit differently than the numerical types + mxLogical *mdata = mxGetLogicals(matlabArray); + cpMatlabData((const mxLogical *)mdata); + } + else + { + void *mdata = (void *)mxGetPr(matlabArray); + + switch (classID) { + case mxDOUBLE_CLASS: + cpMatlabData((const real64_T *)mdata); + break; + case mxSINGLE_CLASS: + cpMatlabData((const real32_T *)mdata); + break; + case mxINT8_CLASS: + cpMatlabData((const int8_T *)mdata); + break; + case mxUINT8_CLASS: + cpMatlabData((const uint8_T *)mdata); + break; + case mxINT16_CLASS: + cpMatlabData((const int16_T *)mdata); + break; + case mxUINT16_CLASS: + cpMatlabData((const uint16_T *)mdata); + break; + case mxINT32_CLASS: + cpMatlabData((const int32_T *)mdata); + break; + case mxUINT32_CLASS: + cpMatlabData((const uint32_T *)mdata); + break; + case mxINT64_CLASS: + cpMatlabData((const int64_T *)mdata); + break; + case mxUINT64_CLASS: + cpMatlabData((const uint64_T *)mdata); + break; + } + } + } + + /*********************************************************** + * the actual memory copy and base type conversion is then + * performed by this routine that handles the annoying x-y + * problem of MATLAB when dealing with images: we switch + * line and column storage: the MATLAB A(x,y) becomes the + * CImg img(y,x) + */ + template <typename t> void cpMatlabData(const t* mdata) + { + if (cimg::type<t>::is_float()) + { + cimg_forXYZV(*this, x, y, z, v) + { + (*this)(x, y, z, v) = (T)(mdata[((v*depth + z)*width+x)*height+y]); + } + } + else + { + cimg_forXYZV(*this, x, y, z, v) + { + (*this)(x, y, z, v) = (T)(int)(mdata[((v*depth + z)*width+x)*height+y]); + } + } + } + +public: + + /****************************************************************** + * Consruct a CImg<T> object from a MATLAB mxArray. + * The MATLAB array must be AT MOST 4-dimensional. The boolean + * argument vdata is employed in the case the the input mxArray + * has dimension 3, say M x N x K. In that case, if vdata is true, + * the last dimension is assumed to be "vectorial" and the + * resulting CImg<T> object has dimension N x M x 1 x K. Otherwise, + * the resulting object has dimension N x M x K x 1. + * When MATLAB array has dimension 2 or 4, vdata has no effects. + * No shared memory mechanisms are used, it would be the easiest + * to crash Matlab (from my own experience...) + */ + CImg(const mxArray *matlabArray, bool vdata = false) + : is_shared(false) + { + mwSize nbdims = mxGetNumberOfDimensions(matlabArray); + mxClassID classID = mxGetClassID(matlabArray); + if (nbdims > 4 || !isNumericalClassID(classID)) + { + data=NULL; + width=height=depth=dim=0; +#if cimg_debug>1 + cimg::warn("MATLAB array is more than 4D or/and " + "not numerical, returning null image."); +#endif + } + else + { + const mwSize *dims = mxGetDimensions(matlabArray); + depth = dim = 1; + width = (unsigned)dims[1]; + height = (unsigned)dims[0]; + if (nbdims == 4) + { + depth = (unsigned)dims[2]; + dim = (unsigned)dims[3]; + } + else if (nbdims == 3) + { + if (vdata) + { + dim = (unsigned)dims[2]; + } + else + { + depth = (unsigned)dims[2]; + } + } + + data = new T[size()]; + makeImageFromMatlabData(matlabArray, classID); + } + } + + /******************************************************************* + * operator=(). Copy mxMarray data mArray into the current image + * Works as the previous constructor, but without the vdata stuff. + * don't know if it is of any use... + */ + CImg & operator=(const mxArray *matlabArray) + { + int nbdims = (int)mxGetNumberOfDimensions(matlabArray); + int classID = mxGetClassID(matlabArray); + if (nbdims > 4 || !isNumericalClassID(classID)) + { + delete [] data; + data = NULL; + width=height=depth=dim=0; +#if cimg_debug>1 + cimg::warn("MATLAB array is more than 4D or/and " + "not numerical, returning null image."); +#endif + } + else + { + const mwSize *dims = mxGetDimensions(matlabArray); + depth = dim = 1; + width = (unsigned)dims[1]; + height = (unsigned)dims[0]; + if (nbdims > 2) + { + depth = (unsigned)dims[2]; + } + if (nbdims > 3) + { + dim = (unsigned)dims[3]; + } + + delete [] data; + data = new T[size()]; + + makeImageFromMatlabData(matlabArray, classID); + } + } + +private: + /***************************************************************** + * private routines used for transfering a CImg<T> to a mxArray + * here also, we have to exchange the x and y dims so we get the + * expected MATLAB array. + */ + template <typename c> void populate_maltlab_array(c *mdata) const + { + cimg_forXYZV(*this, x, y, z, v) + { + mdata[((v*depth + z)*width+x)*height+y] = (c)(*this)(x, y, z, v); + } + } + + /************************************************* + * the specialized version for "logical" entries + */ + void populate_maltlab_array(mxLogical *mdata) const + { + cimg_forXYZV(*this, x, y, z, v) + { + mdata[((v*depth + z)*width+x)*height+y] = (mxLogical)((*this)(x, y, z, v)!=0); + } + } + +public: + /****************************************** + * export a CImg image to a MATLAB array. + **/ + mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS, bool squeeze = false) const + { + if (!isNumericalClassID(classID)) + { +#if cimg_debug>1 + cimg::warn("Invalid MATLAB Class Id Specified."); +#endif + return NULL; + } + + mwSize dims[4]; + dims[0] = (mwSize)height; + dims[1] = (mwSize)width; + dims[2] = (mwSize)depth; + dims[3] = (mwSize)dim; + + if (squeeze && depth == 1) + { + dims[2] = (mwSize)dim; + dims[3] = (mwSize)1; + } + + mxArray *matlabArray = mxCreateNumericArray((mwSize)4, dims, classID, mxREAL); + + if (classID == mxLOGICAL_CLASS) + { + mxLogical *mdata = mxGetLogicals(matlabArray); + populate_maltlab_array(mdata); + } + else + { + void *mdata = mxGetPr(matlabArray); + switch (classID) { + case mxDOUBLE_CLASS: + populate_maltlab_array((real64_T *)mdata); + break; + case mxSINGLE_CLASS: + populate_maltlab_array((real32_T *)mdata); + break; + case mxINT8_CLASS: + populate_maltlab_array((int8_T *)mdata); + break; + case mxUINT8_CLASS: + populate_maltlab_array((uint8_T *)mdata); + break; + case mxINT16_CLASS: + populate_maltlab_array((int16_T *)mdata); + break; + case mxUINT16_CLASS: + populate_maltlab_array((uint16_T *)mdata); + break; + case mxINT32_CLASS: + populate_maltlab_array((int32_T *)mdata); + break; + case mxUINT32_CLASS: + populate_maltlab_array((uint32_T *)mdata); + break; + case mxINT64_CLASS: + populate_maltlab_array((int64_T *)mdata); + break; + case mxUINT64_CLASS: + populate_maltlab_array((uint64_T *)mdata); + break; + } + } + return matlabArray; + } + +// end of cimgmatlab.h