a b/Thoracic Organs Segmentation code/OpticalFlow3D/cimgmatlab.h
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
 ***************************************************************************/
65
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
73
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
82
83
/*********************************************************
84
 * begin of included methods                             *
85
 * They are just added as member functions / constructor *
86
 * for the CImg<T> class.                                *
87
 *********************************************************/
88
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
    }
114
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);
132
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
    }
167
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
    }
192
193
public:
194
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
            }
243
244
            data = new T[size()];
245
            makeImageFromMatlabData(matlabArray, classID);
246
        }
247
    }
248
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
            }
282
283
            delete [] data;
284
            data = new T[size()];
285
286
            makeImageFromMatlabData(matlabArray, classID);
287
        }
288
    }
289
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
    }
303
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
    }
314
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
        }
328
329
        mwSize dims[4];
330
        dims[0] = (mwSize)height;
331
        dims[1] = (mwSize)width;
332
        dims[2] = (mwSize)depth;
333
        dims[3] = (mwSize)dim;
334
335
        if (squeeze && depth == 1)
336
        {
337
            dims[2] = (mwSize)dim;
338
            dims[3] = (mwSize)1;
339
        }
340
341
        mxArray *matlabArray = mxCreateNumericArray((mwSize)4, dims, classID, mxREAL);
342
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
    }
386
387
// end of cimgmatlab.h