PTdecode/CImg-1.3.0/plugins/cimgmatlab.h

changeset 5
1204ebf9340d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/PTdecode/CImg-1.3.0/plugins/cimgmatlab.h	Mon Aug 03 14:09:20 2009 +0100
     1.3 @@ -0,0 +1,387 @@
     1.4 +/*************************************************************************
     1.5 + * cimgmatlab.h
     1.6 + * -------------
     1.7 + *
     1.8 + * cimgmatlab.h  is a "plugin" for the CImg library that allows to convert
     1.9 + * CImg<T> images from/to MATLAB arrays, so that CImg can be used to write
    1.10 + * MATLAB mex files.  It also swaps the "x" and "y" coordinates when going
    1.11 + * from / to MATLAB array, i.e. the usual image-processing annoying MATLAB
    1.12 + * behaviour of considering images as matrices.
    1.13 + *
    1.14 + * Added to the CImg<T> class are:
    1.15 + *
    1.16 + *  - a constructor : CImg(const mxArray *matlabArray, bool vdata = false)
    1.17 + *    the vdata  serves  to  decide  whether a 3D matlab array should give
    1.18 + *    rise to a 3D CImg object or a "2D vectorial" one.
    1.19 + *
    1.20 + *  - a assignment operator : CImg & operator=(const mxArray *matlabArray)
    1.21 + *    (I use myself extremely seldom and might remove it in the future).
    1.22 + *
    1.23 + *  - a routine converting a CImg image to a matlab array:
    1.24 + *    mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS,
    1.25 + *                      bool squeeze = false) const
    1.26 + *    the squeeze argument serves the opposite purpose than the vdata from
    1.27 + *    the constructor.
    1.28 + *
    1.29 + * For a  bit  more documentation, the manual is this header, see the more
    1.30 + * detailed comments in the source code (i.e. RTFM)
    1.31 + *
    1.32 + *
    1.33 + * Its usage should be straightforward:
    1.34 + *
    1.35 + * - file cimgmatlab.h must be in a directory that the compiler can locate.
    1.36 + * - prior to include CImg.h, mex.h  must  be  included first, else it will
    1.37 + *   result in a compiler error.
    1.38 + * - after the inclusion of mex.h, one must define the macro cimg_plugin as
    1.39 + *   "cimgmatlab.h"  or  <cimgmatlab.h> or  <CImg/plugins/cimgmatlab.h>  or
    1.40 + *   a variation that  matches your  local installation of CImg package and
    1.41 + *   plugins probably via the appropriate specification of the include path
    1.42 + *   "-Ipath/to/cimg/and/plugins" at mex cmdline.
    1.43 + *
    1.44 + * You would probably have this kind of declaration:
    1.45 + *
    1.46 + * // The begining of my fantastic mex file code...
    1.47 + * #include <mex.h>
    1.48 + * ...
    1.49 + * #define cimg_plugin  <cimgmatlab.h>
    1.50 + * #include <CImg.h>
    1.51 + * ...
    1.52 + * // and now I can implement my new killer MATLAB function!
    1.53 + * ....
    1.54 + *
    1.55 + *
    1.56 + * Copyright (c) 2004-2008 Francois Lauze
    1.57 + * Licence: the Gnu Lesser General Public License
    1.58 + * http://www.gnu.org/licenses/lgpl.html
    1.59 + *
    1.60 + * MATLAB is copyright of The MathWorks, Inc, http://www.mathworks.com
    1.61 + *
    1.62 + * Any comments, improvements and potential bug corrections are welcome, so
    1.63 + * write to  me at francois@diku.dk, or use CImg forums, I promise I'll try
    1.64 + * to read them once in a while. BTW who modified the cpMatlabData with the
    1.65 + * cimg::type<t>::is_float() test (good idea!)
    1.66 + *
    1.67 + ***************************************************************************/
    1.68 +
    1.69 +#define CIMGMATLAB_VER 0102
    1.70 +#ifndef mex_h
    1.71 +#error the file mex.h must be included prior to inclusion of cimgmatlab.h
    1.72 +#endif
    1.73 +#ifndef cimg_version
    1.74 +#error cimgmatlab.h requires that CImg.h is included!
    1.75 +#endif
    1.76 +
    1.77 +/**********************************************************
    1.78 + * introduction of mwSize and mwIndex types in relatively *
    1.79 + * recent versions of matlab, 7.3.0 from what I gathered. *
    1.80 + * here is hopefully a needed fix for older versions      *
    1.81 + **********************************************************/
    1.82 +#if !defined(MX_API_VER) ||  MX_API_VER < 0x7030000
    1.83 +typedef int mwSize;
    1.84 +#endif
    1.85 +
    1.86 +/*********************************************************
    1.87 + * begin of included methods                             *
    1.88 + * They are just added as member functions / constructor *
    1.89 + * for the CImg<T> class.                                *
    1.90 + *********************************************************/
    1.91 +
    1.92 +private:
    1.93 +    /**********************************************************************
    1.94 +     * internally used to transfer MATLAB array values to CImg<> objects,
    1.95 +     * check wether the array type is a "numerical" one (including logical)
    1.96 +     */
    1.97 +    static int isNumericalClassID(mxClassID id)
    1.98 +    {
    1.99 +        // all these constants are defined in matrix.h included by mex.h
   1.100 +        switch (id) {
   1.101 +        case mxLOGICAL_CLASS:
   1.102 +        case mxDOUBLE_CLASS:
   1.103 +        case mxSINGLE_CLASS:
   1.104 +        case mxINT8_CLASS:
   1.105 +        case mxUINT8_CLASS:
   1.106 +        case mxINT16_CLASS:
   1.107 +        case mxUINT16_CLASS:
   1.108 +        case mxINT32_CLASS:
   1.109 +        case mxUINT32_CLASS:
   1.110 +        case mxINT64_CLASS:
   1.111 +        case mxUINT64_CLASS:
   1.112 +            return 1;
   1.113 +        default:
   1.114 +            return 0;
   1.115 +        }
   1.116 +    }
   1.117 +
   1.118 +    /***************************************************
   1.119 +     * driving routine that will copy the content of
   1.120 +     * a MATLAB array to this->data
   1.121 +     * The type names used are defined in matlab c/c++
   1.122 +     * header file tmwtypes.h
   1.123 +     */
   1.124 +    void makeImageFromMatlabData(const mxArray *matlabArray, mxClassID classID)
   1.125 +    {
   1.126 +        if (classID == mxLOGICAL_CLASS)
   1.127 +        {
   1.128 +            // logical type works a bit differently than the numerical types
   1.129 +            mxLogical *mdata = mxGetLogicals(matlabArray);
   1.130 +            cpMatlabData((const mxLogical *)mdata);
   1.131 +        }
   1.132 +        else
   1.133 +        {
   1.134 +            void *mdata = (void *)mxGetPr(matlabArray);
   1.135 +
   1.136 +            switch (classID) {
   1.137 +            case mxDOUBLE_CLASS:
   1.138 +                cpMatlabData((const real64_T *)mdata);
   1.139 +                break;
   1.140 +            case mxSINGLE_CLASS:
   1.141 +                cpMatlabData((const real32_T *)mdata);
   1.142 +                break;
   1.143 +            case mxINT8_CLASS:
   1.144 +                cpMatlabData((const int8_T *)mdata);
   1.145 +                break;
   1.146 +            case mxUINT8_CLASS:
   1.147 +                cpMatlabData((const uint8_T *)mdata);
   1.148 +                break;
   1.149 +            case mxINT16_CLASS:
   1.150 +                cpMatlabData((const int16_T *)mdata);
   1.151 +                break;
   1.152 +            case mxUINT16_CLASS:
   1.153 +                cpMatlabData((const uint16_T *)mdata);
   1.154 +                break;
   1.155 +            case mxINT32_CLASS:
   1.156 +                cpMatlabData((const int32_T *)mdata);
   1.157 +                break;
   1.158 +            case mxUINT32_CLASS:
   1.159 +                cpMatlabData((const uint32_T *)mdata);
   1.160 +                break;
   1.161 +            case mxINT64_CLASS:
   1.162 +                cpMatlabData((const int64_T *)mdata);
   1.163 +                break;
   1.164 +            case mxUINT64_CLASS:
   1.165 +                cpMatlabData((const uint64_T *)mdata);
   1.166 +                break;
   1.167 +            }
   1.168 +        }
   1.169 +    }
   1.170 +
   1.171 +    /***********************************************************
   1.172 +     * the actual memory copy and base type conversion is then
   1.173 +     * performed by this routine that handles the annoying x-y
   1.174 +     * problem of MATLAB when dealing with images: we switch
   1.175 +     * line and column storage: the MATLAB A(x,y) becomes the
   1.176 +     * CImg img(y,x)
   1.177 +     */
   1.178 +    template <typename t> void cpMatlabData(const t* mdata)
   1.179 +    {
   1.180 +        if (cimg::type<t>::is_float())
   1.181 +        {
   1.182 +            cimg_forXYZV(*this, x, y, z, v)
   1.183 +            {
   1.184 +                (*this)(x, y, z, v) = (T)(mdata[((v*depth + z)*width+x)*height+y]);
   1.185 +            }
   1.186 +        }
   1.187 +        else
   1.188 +        {
   1.189 +            cimg_forXYZV(*this, x, y, z, v)
   1.190 +            {
   1.191 +                (*this)(x, y, z, v) = (T)(int)(mdata[((v*depth + z)*width+x)*height+y]);
   1.192 +            }
   1.193 +        }
   1.194 +    }
   1.195 +
   1.196 +public:
   1.197 +
   1.198 +    /******************************************************************
   1.199 +     * Consruct a CImg<T> object from a MATLAB mxArray.
   1.200 +     * The MATLAB array must be AT MOST 4-dimensional. The boolean
   1.201 +     * argument vdata is employed in the case the the input mxArray
   1.202 +     * has dimension 3, say M x N x K. In that case, if vdata is true,
   1.203 +     * the last dimension is assumed to be "vectorial" and the
   1.204 +     * resulting CImg<T> object has dimension N x M x 1 x K. Otherwise,
   1.205 +     * the resulting object has dimension N x M x K x 1.
   1.206 +     * When MATLAB array has dimension 2 or 4, vdata has no effects.
   1.207 +     * No shared memory mechanisms are used, it would be the easiest
   1.208 +     * to crash Matlab (from my own experience...)
   1.209 +     */
   1.210 +    CImg(const mxArray *matlabArray, bool vdata = false)
   1.211 +    : is_shared(false)
   1.212 +    {
   1.213 +        mwSize nbdims = mxGetNumberOfDimensions(matlabArray);
   1.214 +        mxClassID classID = mxGetClassID(matlabArray);
   1.215 +        if (nbdims > 4 || !isNumericalClassID(classID))
   1.216 +        {
   1.217 +            data=NULL;
   1.218 +            width=height=depth=dim=0;
   1.219 +#if cimg_debug>1
   1.220 +            cimg::warn("MATLAB array is more than 4D or/and "
   1.221 +                       "not numerical, returning null image.");
   1.222 +#endif
   1.223 +        }
   1.224 +        else
   1.225 +        {
   1.226 +            const mwSize *dims = mxGetDimensions(matlabArray);
   1.227 +            depth = dim = 1;
   1.228 +            width =  (unsigned)dims[1];
   1.229 +            height = (unsigned)dims[0];
   1.230 +            if (nbdims == 4)
   1.231 +            {
   1.232 +                depth = (unsigned)dims[2];
   1.233 +                dim =   (unsigned)dims[3];
   1.234 +            }
   1.235 +            else if (nbdims == 3)
   1.236 +            {
   1.237 +                if (vdata)
   1.238 +                {
   1.239 +                    dim = (unsigned)dims[2];
   1.240 +                }
   1.241 +                else
   1.242 +                {
   1.243 +                    depth = (unsigned)dims[2];
   1.244 +                }
   1.245 +            }
   1.246 +
   1.247 +            data = new T[size()];
   1.248 +            makeImageFromMatlabData(matlabArray, classID);
   1.249 +        }
   1.250 +    }
   1.251 +
   1.252 +    /*******************************************************************
   1.253 +     * operator=(). Copy  mxMarray data mArray into the current image
   1.254 +     * Works as the previous constructor, but without the vdata stuff.
   1.255 +     * don't know if it is of any use...
   1.256 +     */
   1.257 +    CImg & operator=(const mxArray *matlabArray)
   1.258 +    {
   1.259 +        int nbdims = (int)mxGetNumberOfDimensions(matlabArray);
   1.260 +        int classID = mxGetClassID(matlabArray);
   1.261 +        if (nbdims > 4 || !isNumericalClassID(classID))
   1.262 +        {
   1.263 +            delete [] data;
   1.264 +            data = NULL;
   1.265 +            width=height=depth=dim=0;
   1.266 +#if cimg_debug>1
   1.267 +            cimg::warn("MATLAB array is more than 4D or/and "
   1.268 +                       "not numerical, returning null image.");
   1.269 +#endif
   1.270 +        }
   1.271 +        else
   1.272 +        {
   1.273 +            const mwSize *dims = mxGetDimensions(matlabArray);
   1.274 +            depth = dim = 1;
   1.275 +            width =  (unsigned)dims[1];
   1.276 +            height = (unsigned)dims[0];
   1.277 +            if (nbdims > 2)
   1.278 +            {
   1.279 +                depth = (unsigned)dims[2];
   1.280 +            }
   1.281 +            if (nbdims > 3)
   1.282 +            {
   1.283 +                dim = (unsigned)dims[3];
   1.284 +            }
   1.285 +
   1.286 +            delete [] data;
   1.287 +            data = new T[size()];
   1.288 +
   1.289 +            makeImageFromMatlabData(matlabArray, classID);
   1.290 +        }
   1.291 +    }
   1.292 +
   1.293 +private:
   1.294 +    /*****************************************************************
   1.295 +     * private routines used for transfering a CImg<T> to a mxArray
   1.296 +     * here also, we have to exchange the x and y dims so we get the
   1.297 +     * expected MATLAB array.
   1.298 +     */
   1.299 +    template <typename c> void populate_maltlab_array(c *mdata) const
   1.300 +    {
   1.301 +        cimg_forXYZV(*this, x, y, z, v)
   1.302 +        {
   1.303 +            mdata[((v*depth + z)*width+x)*height+y] = (c)(*this)(x, y, z, v);
   1.304 +        }
   1.305 +    }
   1.306 +
   1.307 +    /*************************************************
   1.308 +     * the specialized version for "logical" entries
   1.309 +     */
   1.310 +    void populate_maltlab_array(mxLogical *mdata) const
   1.311 +    {
   1.312 +        cimg_forXYZV(*this, x, y, z, v)
   1.313 +        {
   1.314 +            mdata[((v*depth + z)*width+x)*height+y] = (mxLogical)((*this)(x, y, z, v)!=0);
   1.315 +        }
   1.316 +    }
   1.317 +
   1.318 +public:
   1.319 +    /******************************************
   1.320 +     * export a CImg image to a MATLAB array.
   1.321 +     **/
   1.322 +    mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS, bool squeeze = false) const
   1.323 +    {
   1.324 +        if (!isNumericalClassID(classID))
   1.325 +        {
   1.326 +#if cimg_debug>1
   1.327 +            cimg::warn("Invalid MATLAB Class Id Specified.");
   1.328 +#endif
   1.329 +            return NULL;
   1.330 +        }
   1.331 +
   1.332 +        mwSize dims[4];
   1.333 +        dims[0] = (mwSize)height;
   1.334 +        dims[1] = (mwSize)width;
   1.335 +        dims[2] = (mwSize)depth;
   1.336 +        dims[3] = (mwSize)dim;
   1.337 +
   1.338 +        if (squeeze && depth == 1)
   1.339 +        {
   1.340 +            dims[2] = (mwSize)dim;
   1.341 +            dims[3] = (mwSize)1;
   1.342 +        }
   1.343 +
   1.344 +        mxArray *matlabArray = mxCreateNumericArray((mwSize)4, dims, classID, mxREAL);
   1.345 +
   1.346 +        if (classID == mxLOGICAL_CLASS)
   1.347 +        {
   1.348 +            mxLogical *mdata = mxGetLogicals(matlabArray);
   1.349 +            populate_maltlab_array(mdata);
   1.350 +        }
   1.351 +        else
   1.352 +        {
   1.353 +            void *mdata = mxGetPr(matlabArray);
   1.354 +            switch (classID) {
   1.355 +            case mxDOUBLE_CLASS:
   1.356 +                populate_maltlab_array((real64_T *)mdata);
   1.357 +                break;
   1.358 +            case mxSINGLE_CLASS:
   1.359 +                populate_maltlab_array((real32_T *)mdata);
   1.360 +                break;
   1.361 +            case mxINT8_CLASS:
   1.362 +                populate_maltlab_array((int8_T *)mdata);
   1.363 +                break;
   1.364 +            case mxUINT8_CLASS:
   1.365 +                populate_maltlab_array((uint8_T *)mdata);
   1.366 +                break;
   1.367 +            case mxINT16_CLASS:
   1.368 +                populate_maltlab_array((int16_T *)mdata);
   1.369 +                break;
   1.370 +            case mxUINT16_CLASS:
   1.371 +                populate_maltlab_array((uint16_T *)mdata);
   1.372 +                break;
   1.373 +            case mxINT32_CLASS:
   1.374 +                populate_maltlab_array((int32_T *)mdata);
   1.375 +                break;
   1.376 +            case mxUINT32_CLASS:
   1.377 +                populate_maltlab_array((uint32_T *)mdata);
   1.378 +                break;
   1.379 +            case mxINT64_CLASS:
   1.380 +                populate_maltlab_array((int64_T *)mdata);
   1.381 +                break;
   1.382 +            case mxUINT64_CLASS:
   1.383 +                populate_maltlab_array((uint64_T *)mdata);
   1.384 +                break;
   1.385 +            }
   1.386 +        }
   1.387 +        return matlabArray;
   1.388 +    }
   1.389 +
   1.390 +// end of cimgmatlab.h