Tue, 18 Mar 2014 01:27:15 +0000
Update PTdecode to handle output from other Ptouch drivers
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