PTdecode/CImg-1.3.0/plugins/cimgmatlab.h

Wed, 05 Aug 2009 15:00:54 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 05 Aug 2009 15:00:54 +0100
changeset 12
96e1df9bd27c
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

small changes to hexdump code to stop a gcc warning on platforms where sizeof(int) != sizeof(int*) e.g. x86_64

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