PTdecode/CImg-1.3.0/plugins/cimgmatlab.h

Wed, 05 Aug 2009 17:32:05 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 05 Aug 2009 17:32:05 +0100
changeset 18
fd1c6f6066da
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

updated README

     1 /*************************************************************************
     2  * cimgmatlab.h
     3  * -------------
     4  *
     5  * cimgmatlab.h  is a "plugin" for the CImg library that allows to convert
     6  * CImg<T> images from/to MATLAB arrays, so that CImg can be used to write
     7  * MATLAB mex files.  It also swaps the "x" and "y" coordinates when going
     8  * from / to MATLAB array, i.e. the usual image-processing annoying MATLAB
     9  * behaviour of considering images as matrices.
    10  *
    11  * Added to the CImg<T> class are:
    12  *
    13  *  - a constructor : CImg(const mxArray *matlabArray, bool vdata = false)
    14  *    the vdata  serves  to  decide  whether a 3D matlab array should give
    15  *    rise to a 3D CImg object or a "2D vectorial" one.
    16  *
    17  *  - a assignment operator : CImg & operator=(const mxArray *matlabArray)
    18  *    (I use myself extremely seldom and might remove it in the future).
    19  *
    20  *  - a routine converting a CImg image to a matlab array:
    21  *    mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS,
    22  *                      bool squeeze = false) const
    23  *    the squeeze argument serves the opposite purpose than the vdata from
    24  *    the constructor.
    25  *
    26  * For a  bit  more documentation, the manual is this header, see the more
    27  * detailed comments in the source code (i.e. RTFM)
    28  *
    29  *
    30  * Its usage should be straightforward:
    31  *
    32  * - file cimgmatlab.h must be in a directory that the compiler can locate.
    33  * - prior to include CImg.h, mex.h  must  be  included first, else it will
    34  *   result in a compiler error.
    35  * - after the inclusion of mex.h, one must define the macro cimg_plugin as
    36  *   "cimgmatlab.h"  or  <cimgmatlab.h> or  <CImg/plugins/cimgmatlab.h>  or
    37  *   a variation that  matches your  local installation of CImg package and
    38  *   plugins probably via the appropriate specification of the include path
    39  *   "-Ipath/to/cimg/and/plugins" at mex cmdline.
    40  *
    41  * You would probably have this kind of declaration:
    42  *
    43  * // The begining of my fantastic mex file code...
    44  * #include <mex.h>
    45  * ...
    46  * #define cimg_plugin  <cimgmatlab.h>
    47  * #include <CImg.h>
    48  * ...
    49  * // and now I can implement my new killer MATLAB function!
    50  * ....
    51  *
    52  *
    53  * Copyright (c) 2004-2008 Francois Lauze
    54  * Licence: the Gnu Lesser General Public License
    55  * http://www.gnu.org/licenses/lgpl.html
    56  *
    57  * MATLAB is copyright of The MathWorks, Inc, http://www.mathworks.com
    58  *
    59  * Any comments, improvements and potential bug corrections are welcome, so
    60  * write to  me at francois@diku.dk, or use CImg forums, I promise I'll try
    61  * to read them once in a while. BTW who modified the cpMatlabData with the
    62  * cimg::type<t>::is_float() test (good idea!)
    63  *
    64  ***************************************************************************/
    66 #define CIMGMATLAB_VER 0102
    67 #ifndef mex_h
    68 #error the file mex.h must be included prior to inclusion of cimgmatlab.h
    69 #endif
    70 #ifndef cimg_version
    71 #error cimgmatlab.h requires that CImg.h is included!
    72 #endif
    74 /**********************************************************
    75  * introduction of mwSize and mwIndex types in relatively *
    76  * recent versions of matlab, 7.3.0 from what I gathered. *
    77  * here is hopefully a needed fix for older versions      *
    78  **********************************************************/
    79 #if !defined(MX_API_VER) ||  MX_API_VER < 0x7030000
    80 typedef int mwSize;
    81 #endif
    83 /*********************************************************
    84  * begin of included methods                             *
    85  * They are just added as member functions / constructor *
    86  * for the CImg<T> class.                                *
    87  *********************************************************/
    89 private:
    90     /**********************************************************************
    91      * internally used to transfer MATLAB array values to CImg<> objects,
    92      * check wether the array type is a "numerical" one (including logical)
    93      */
    94     static int isNumericalClassID(mxClassID id)
    95     {
    96         // all these constants are defined in matrix.h included by mex.h
    97         switch (id) {
    98         case mxLOGICAL_CLASS:
    99         case mxDOUBLE_CLASS:
   100         case mxSINGLE_CLASS:
   101         case mxINT8_CLASS:
   102         case mxUINT8_CLASS:
   103         case mxINT16_CLASS:
   104         case mxUINT16_CLASS:
   105         case mxINT32_CLASS:
   106         case mxUINT32_CLASS:
   107         case mxINT64_CLASS:
   108         case mxUINT64_CLASS:
   109             return 1;
   110         default:
   111             return 0;
   112         }
   113     }
   115     /***************************************************
   116      * driving routine that will copy the content of
   117      * a MATLAB array to this->data
   118      * The type names used are defined in matlab c/c++
   119      * header file tmwtypes.h
   120      */
   121     void makeImageFromMatlabData(const mxArray *matlabArray, mxClassID classID)
   122     {
   123         if (classID == mxLOGICAL_CLASS)
   124         {
   125             // logical type works a bit differently than the numerical types
   126             mxLogical *mdata = mxGetLogicals(matlabArray);
   127             cpMatlabData((const mxLogical *)mdata);
   128         }
   129         else
   130         {
   131             void *mdata = (void *)mxGetPr(matlabArray);
   133             switch (classID) {
   134             case mxDOUBLE_CLASS:
   135                 cpMatlabData((const real64_T *)mdata);
   136                 break;
   137             case mxSINGLE_CLASS:
   138                 cpMatlabData((const real32_T *)mdata);
   139                 break;
   140             case mxINT8_CLASS:
   141                 cpMatlabData((const int8_T *)mdata);
   142                 break;
   143             case mxUINT8_CLASS:
   144                 cpMatlabData((const uint8_T *)mdata);
   145                 break;
   146             case mxINT16_CLASS:
   147                 cpMatlabData((const int16_T *)mdata);
   148                 break;
   149             case mxUINT16_CLASS:
   150                 cpMatlabData((const uint16_T *)mdata);
   151                 break;
   152             case mxINT32_CLASS:
   153                 cpMatlabData((const int32_T *)mdata);
   154                 break;
   155             case mxUINT32_CLASS:
   156                 cpMatlabData((const uint32_T *)mdata);
   157                 break;
   158             case mxINT64_CLASS:
   159                 cpMatlabData((const int64_T *)mdata);
   160                 break;
   161             case mxUINT64_CLASS:
   162                 cpMatlabData((const uint64_T *)mdata);
   163                 break;
   164             }
   165         }
   166     }
   168     /***********************************************************
   169      * the actual memory copy and base type conversion is then
   170      * performed by this routine that handles the annoying x-y
   171      * problem of MATLAB when dealing with images: we switch
   172      * line and column storage: the MATLAB A(x,y) becomes the
   173      * CImg img(y,x)
   174      */
   175     template <typename t> void cpMatlabData(const t* mdata)
   176     {
   177         if (cimg::type<t>::is_float())
   178         {
   179             cimg_forXYZV(*this, x, y, z, v)
   180             {
   181                 (*this)(x, y, z, v) = (T)(mdata[((v*depth + z)*width+x)*height+y]);
   182             }
   183         }
   184         else
   185         {
   186             cimg_forXYZV(*this, x, y, z, v)
   187             {
   188                 (*this)(x, y, z, v) = (T)(int)(mdata[((v*depth + z)*width+x)*height+y]);
   189             }
   190         }
   191     }
   193 public:
   195     /******************************************************************
   196      * Consruct a CImg<T> object from a MATLAB mxArray.
   197      * The MATLAB array must be AT MOST 4-dimensional. The boolean
   198      * argument vdata is employed in the case the the input mxArray
   199      * has dimension 3, say M x N x K. In that case, if vdata is true,
   200      * the last dimension is assumed to be "vectorial" and the
   201      * resulting CImg<T> object has dimension N x M x 1 x K. Otherwise,
   202      * the resulting object has dimension N x M x K x 1.
   203      * When MATLAB array has dimension 2 or 4, vdata has no effects.
   204      * No shared memory mechanisms are used, it would be the easiest
   205      * to crash Matlab (from my own experience...)
   206      */
   207     CImg(const mxArray *matlabArray, bool vdata = false)
   208     : is_shared(false)
   209     {
   210         mwSize nbdims = mxGetNumberOfDimensions(matlabArray);
   211         mxClassID classID = mxGetClassID(matlabArray);
   212         if (nbdims > 4 || !isNumericalClassID(classID))
   213         {
   214             data=NULL;
   215             width=height=depth=dim=0;
   216 #if cimg_debug>1
   217             cimg::warn("MATLAB array is more than 4D or/and "
   218                        "not numerical, returning null image.");
   219 #endif
   220         }
   221         else
   222         {
   223             const mwSize *dims = mxGetDimensions(matlabArray);
   224             depth = dim = 1;
   225             width =  (unsigned)dims[1];
   226             height = (unsigned)dims[0];
   227             if (nbdims == 4)
   228             {
   229                 depth = (unsigned)dims[2];
   230                 dim =   (unsigned)dims[3];
   231             }
   232             else if (nbdims == 3)
   233             {
   234                 if (vdata)
   235                 {
   236                     dim = (unsigned)dims[2];
   237                 }
   238                 else
   239                 {
   240                     depth = (unsigned)dims[2];
   241                 }
   242             }
   244             data = new T[size()];
   245             makeImageFromMatlabData(matlabArray, classID);
   246         }
   247     }
   249     /*******************************************************************
   250      * operator=(). Copy  mxMarray data mArray into the current image
   251      * Works as the previous constructor, but without the vdata stuff.
   252      * don't know if it is of any use...
   253      */
   254     CImg & operator=(const mxArray *matlabArray)
   255     {
   256         int nbdims = (int)mxGetNumberOfDimensions(matlabArray);
   257         int classID = mxGetClassID(matlabArray);
   258         if (nbdims > 4 || !isNumericalClassID(classID))
   259         {
   260             delete [] data;
   261             data = NULL;
   262             width=height=depth=dim=0;
   263 #if cimg_debug>1
   264             cimg::warn("MATLAB array is more than 4D or/and "
   265                        "not numerical, returning null image.");
   266 #endif
   267         }
   268         else
   269         {
   270             const mwSize *dims = mxGetDimensions(matlabArray);
   271             depth = dim = 1;
   272             width =  (unsigned)dims[1];
   273             height = (unsigned)dims[0];
   274             if (nbdims > 2)
   275             {
   276                 depth = (unsigned)dims[2];
   277             }
   278             if (nbdims > 3)
   279             {
   280                 dim = (unsigned)dims[3];
   281             }
   283             delete [] data;
   284             data = new T[size()];
   286             makeImageFromMatlabData(matlabArray, classID);
   287         }
   288     }
   290 private:
   291     /*****************************************************************
   292      * private routines used for transfering a CImg<T> to a mxArray
   293      * here also, we have to exchange the x and y dims so we get the
   294      * expected MATLAB array.
   295      */
   296     template <typename c> void populate_maltlab_array(c *mdata) const
   297     {
   298         cimg_forXYZV(*this, x, y, z, v)
   299         {
   300             mdata[((v*depth + z)*width+x)*height+y] = (c)(*this)(x, y, z, v);
   301         }
   302     }
   304     /*************************************************
   305      * the specialized version for "logical" entries
   306      */
   307     void populate_maltlab_array(mxLogical *mdata) const
   308     {
   309         cimg_forXYZV(*this, x, y, z, v)
   310         {
   311             mdata[((v*depth + z)*width+x)*height+y] = (mxLogical)((*this)(x, y, z, v)!=0);
   312         }
   313     }
   315 public:
   316     /******************************************
   317      * export a CImg image to a MATLAB array.
   318      **/
   319     mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS, bool squeeze = false) const
   320     {
   321         if (!isNumericalClassID(classID))
   322         {
   323 #if cimg_debug>1
   324             cimg::warn("Invalid MATLAB Class Id Specified.");
   325 #endif
   326             return NULL;
   327         }
   329         mwSize dims[4];
   330         dims[0] = (mwSize)height;
   331         dims[1] = (mwSize)width;
   332         dims[2] = (mwSize)depth;
   333         dims[3] = (mwSize)dim;
   335         if (squeeze && depth == 1)
   336         {
   337             dims[2] = (mwSize)dim;
   338             dims[3] = (mwSize)1;
   339         }
   341         mxArray *matlabArray = mxCreateNumericArray((mwSize)4, dims, classID, mxREAL);
   343         if (classID == mxLOGICAL_CLASS)
   344         {
   345             mxLogical *mdata = mxGetLogicals(matlabArray);
   346             populate_maltlab_array(mdata);
   347         }
   348         else
   349         {
   350             void *mdata = mxGetPr(matlabArray);
   351             switch (classID) {
   352             case mxDOUBLE_CLASS:
   353                 populate_maltlab_array((real64_T *)mdata);
   354                 break;
   355             case mxSINGLE_CLASS:
   356                 populate_maltlab_array((real32_T *)mdata);
   357                 break;
   358             case mxINT8_CLASS:
   359                 populate_maltlab_array((int8_T *)mdata);
   360                 break;
   361             case mxUINT8_CLASS:
   362                 populate_maltlab_array((uint8_T *)mdata);
   363                 break;
   364             case mxINT16_CLASS:
   365                 populate_maltlab_array((int16_T *)mdata);
   366                 break;
   367             case mxUINT16_CLASS:
   368                 populate_maltlab_array((uint16_T *)mdata);
   369                 break;
   370             case mxINT32_CLASS:
   371                 populate_maltlab_array((int32_T *)mdata);
   372                 break;
   373             case mxUINT32_CLASS:
   374                 populate_maltlab_array((uint32_T *)mdata);
   375                 break;
   376             case mxINT64_CLASS:
   377                 populate_maltlab_array((int64_T *)mdata);
   378                 break;
   379             case mxUINT64_CLASS:
   380                 populate_maltlab_array((uint64_T *)mdata);
   381                 break;
   382             }
   383         }
   384         return matlabArray;
   385     }
   387 // end of cimgmatlab.h