How to use the C++ Interface to Matlab 1 Rahul Nair

How to use the C++ Interface to Matlab
Rahul Nair
May 6, 2009
1
Before we start (Things worth knowing)
Matlab always employs Copy on demand. In assignments of the for a = b as well as
when arguments are passed to functions.Only references or pointers are passed. Only
if subsequently the assigned array is changed, matlab will copy the data.
This also applies to mex functions. Matlab does not copy the data but only
provides pointers to the memory, where the data is managed. Note that copy on
demand is not enforced while using mexFunctions. So it is (as of version 2008) quite
possible to manipulate data passed as function parameters in place. (Though most
probably not really recommended, as this is not default matlab behaviour)
To avoid copying large amount of data while using the C++ Interface, but still
having the comfort of using Classes and Objects, VIGRA provides View classes. These
are basically enhanced pointers to external memory providing methods that work on
it.
It would be advisible to have a look at the functions already written as much of
the following will most probably be easier to understand.
2
The Gateway function
The mexFunction(...) gateway is replaced by the vigraMexFunction(...) gateway. The
mexFunction still exists - but is in matlab.hxx. It only creates the InputArray and
OutputArray objects and subsequently calls vigraMexFunction(...)
Note: if for some reason you do not want to use a custom mexFunction it is
possible to override default behavior by #define CUSTOM MEX FUNCTION before
#include matlab.hxx
The two main classes needed for using the interface are vigra::matlab::InputArray
and vigra::matlab::OutputArray. These two classes take the plhs prhs and nlhs nrhs
parameters of the classical mexFunction and provide methods that simplify access of
data.
The job of the vigraMexFunction is to call the right template-instance of the
vigraMain<>(..) function. Typechecking of the inputs etc should be done here.
Note: vigra contains typedefs of kind UInt8 ... UInt64, Int8 ... Int64
Listing 1: The first parameter of the Function can be of type double or of type UInt8
1
2
3
4
5
6
7
8
void vigraMexFunction (
v i g r a : : matlab : : OutputArray outputs ,
v i g r a : : matlab : : I n p u t A r r a y i n p u t s )
{
switch ( i n p u t s . typeOf ( 0 ) )
// s w i t c h on t h e t y p e o f t h e f i r s t p a r a m e t e r
// c a l l s m x C l a s s I D t o g e t t h e a number c o r r e s p o n d i n g t o t h e t y p e
{
c a s e mxUINT8 CLASS :
1
9
10
11
12
13
14
15
v i g r a M a i n <U I n t 8 >( o u t p u t s , i n p u t s ) ;
break ;
c a s e mxDOUBLE CLASS :
v i g r a M a i n <d o u b l e >( o u t p u t s , i n p u t s ) ;
break ;
default :
mexErrMsgTxt ( ” Type o f i n p u t a t p o s i t i o n 0 n o t s u p p o r t e d ” ) ;
}
}
Listing 2: Using Macros - This only works if vigraMain takes only one template
parameter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void vigraMexFunction ( v i g r a : : matlab : : OutputArray outputs ,
v i g r a : : matlab : : I n p u t A r r a y i n p u t s )
{
s w i t c h ( i n p u t s . t y p e O f ( ” someOption ” ) )
// s w i t c h on t h e t y p e o f t h e f i e l d ” someOption ” o f t h e o p t i o n s
// s t r u c t .
// c a l l s m x C l a s s I D t o g e t t h e a number c o r r e s p o n d i n g t o t h e t y p e
{
ALLOW UINT 16 64
// s w i t c h c a s e s f o r i n t 1 6 t o i n t 6 4
ALLOW INT 8 32
// s w i t c h c a s e s f o r i n t 8 t o i n t 3 2
ALLOW FD
// a l l o w f l o a t and d o u b l e
default :
mexErrMsgTxt ( ” Type o f i n p u t a t p o s i t i o n 0 n o t s u p p o r t e d ” ) ;
}
}
3
The vigraMain function
The vigraMain(...) function contains the C++ code that actually has to be run.
First the View objects should look at the right data. Also space should be allocated
for the output arrays.
Listing 3: Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1.
/∗Make a View o f Type T ( t h e t e m p l a t e t y p e o f v i g r a M a i n ) and l e t i t l o o k a t t h e
f i r s t p a r a m e t e r s u p p l i e d . v r e q u i r e d ( ) i n d i c a t e s t h a t an mexErrMsgTxt ( ) i s t h r o w n
i f no ar g u m e n t i s s u p p l i e d a t p o s i t i o n 0 ( o r an empty a r r a y ) ∗/
B a s i c I m a g e V i e w<T>
in
=
i n p u t s . g e t I m a g e<T>(0 , v r e q u i r e d ( ) ) ;
2.
/∗ Second Argument i s S c a l a r and c o p i e d i n t o ” s c a l e ” v d e f a u l t ( 1 . 0 ) i n d i c a t e s t h a t
i f no ar g u m e n t i s s u p p l i e d t h e d e f a u l t v a l u e 1 . 0 i s u s e d . t h e l a s t two a r g u m e n t s
a r e t h e r a n g e c o n s t r a i n t s on s c a l e a mexErrMsgTxt i s t h r o w n i f t h e v a l u e i s o u t
o f bounds ∗/
double s c a l e
=
i n p u t s . g e t S c a l a r M i n M a x<d o u b l e >(1 , v d e f a u l t ( 1 . 0 ) , 0 . 0 , ” i n f ” ) ;
3.
// C r e a t e an Image o f t y p e d o u b l e a t o u t p u t p o s i t i o n 0 w i t h t h e s i z e o f i n
B a s i c I m a g e V i e w<d o u b l e> o u t =
o u t p u t s . c r e a t e I m a g e <d o u b l e >(0 , v r e q u i r e d ( ) , i n . w i d t h ( ) , i n . h e i g h t ( ) ) ;
4.
/∗Same t h i n g a s 2 . w i t h o u t c o n s t r a i n t s . v o p t i o n a l ( ) i n d i c a t e s t h a t t h i s v a r i a b l e
does not have a d e f a u l t v a l u e . v o p t i o n a l ( bool check ) s e t s check to t r u e i f the
v a r i a b l e h a s b e e n s e t , f a l s e o t h e r w i s e . ∗/
bool
hasBackground ;
T
backgroundValue =
i n p u t s . g e t S c a l a r <T>(” b a c k g r o u n d V a l u e ” , v o p t i o n a l ( h a s B a c k g r o u n d ) ) ;
5.
/∗ c r e a t e s a s c a l a r a t t h e s e c o n o u t p u t i f s e c o n d o u t p u t h a s b e e n a s k e d f o r
( v o p t i o n a l ( ) ) and c o p i e s m a x r e g i o n l a b e l i n t o i t ∗/
o u t p u t s . c r e a t e S c a l a r <i n t > ( 1 , v o p t i o n a l ( ) , m a x r e g i o n l a b e l ) ;
After space is allocated and the Views point to the right memory - the actual code
can be executed.
2
4
matlab::InputArray and matlab::OutputArray
These are wrapper classes for plhs nlhs, prhs nrhs respectively. InputArray checks
whether the last mxArray* in prhs is a matlab struct array - If yes it is an
options struct and loaded. What followes is a listing of public methods and attributes
Place posOrName denotes an object of type std::string or an int. If it is
std::string the options struct is searched for a field with name posOrNum. if it is
an then the argument at the given position is used.
ReqType is one of the objects described in the next section.
Note: If you are not using matlab::InputArray or matlab::OutputArray, still you
may use the non-member get and create functions which take a mxArray* as first
parameter. Note that these functions do not check for constraints or whether the
mxArray* is pointing to any memory. Look into matlab.hxx for further details.
Listing 4: matlab::InputArray
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
matlab : : C o n s t S t r u c t A r r a y o p t i o n s
/∗The o p t i o n s S t r u c t . See D o c u m e n t a t i o n o f C o n s t S t r u c t A r r a y f o r more
i n f o r m a t i o n . ∗/
mxArray ∗ & o p e r a t o r [ ] ( P l a c e posOrName )
/∗ A c c e s s r e f e r e n c e t o t h e mxArray ∗ a t c e r t a i n p l a c e . ∗/
size type size ()
/∗ r e t u r n s n r h s ∗/
b o o l i s V a l i d ( P l a c e posOrName )
/∗ r e t u r n s t r u e i f a Argument was s u p p l i e d a t p l a c e posOrNum . ∗/
b o o l i s E m p t y ( P l a c e posOrName )
/∗ r e t u r n t r u e i f A r r a y a t p l a c e posOrNum i s empty . ∗/
m x C l a s s I D t y p e O f ( p l a c e posOrName )
/∗ r e t u r n t y p e o f mxArray ∗ a t p l a c e posOrNum ; ∗/
t e m p l a t e <c l a s s P l a c e , c l a s s ReqType>
i n t getEnum ( P l a c e posOrName , ReqType r e q , s t d : : map<s t d : : s t r i n g , i n t > c o n s t & c o n v e r t e r )
/∗ g e t S t r i n g and c o n v e r t i n t o E n u m e r a t i o n t y p e
See Note a f t e r t h e l i s t i n g f o r u s a g e ∗/
t e m p l a t e <c l a s s T , c l a s s p l a c e , c l a s s ReqType>
T g e t S t r i n g ( p l a c e posOrName , ReqType r e q )
/∗ g e t S t r i n g a t p l a c e posOrName . ∗/
t e m p l a t e <c l a s s T , c l a s s p l a c e , c l a s s ReqType>
T g e t S c a l a r ( p l a c e posOrName , ReqType r e q )
/∗ g e t S c a l a r v a l u e a t p l a c e posOrName . ∗/
t e m p l a t e<c l a s s T , c l a s s p l a c e , c l a s s r e q C l a s s ,
c l a s s m i n C l a s s , c l a s s m a x C l as s>
T g e t S c a l a r M i n M a x ( p l a c e posOrName , r e q C l a s s r e q ,
m i n C l a s s min , m a x C l a s s max )
/∗ g e t S c a l a r v a l u e c o n s t r a i n e d by r a n g e d e f i n e d by m i n and max
m i n and max can a l s o be ” i n f ” ∗/
t e m p l a t e <c l a s s T , c l a s s p l a c e , c l a s s r e q C l a s s , c l a s s i t e r a t o r T y p e >
T g e t S c a l a r V a l s ( p l a c e posOrName , r e q C l a s s r e q ,
i t e r a t o r T y p e begin , i t e r a t o r T y p e end )
/∗ g e t S c a l a r v a l u e c o n s t r a i n e d by t h e v a l u e s i n t h e i t e r a t o r r a n g e
g i v e n by b e g i n and e n d ∗/
t e m p l a t e <c l a s s T , c l a s s p l a c e , c l a s s r e q C l a s s , c l a s s i t e r a t o r T y p e >
T g e t S c a l a r V a l s 2 D 3 D ( p l a c e posOrName , r e q C l a s s r e q ,
i t e r a t o r T y p e b e g i n 2 D , i t e r a t o r T y p e end2D ,
i t e r a t o r T y p e b e g i n 3 D , i t e r a t o r T y p e end3D ,
i n t dimVar )
/∗ g e t S c a l a r v a l u e c o n s t r a i n e d by r a n g e b e g i n 2 D , end2D i n c a s dimVar
i s 2 e l s e c o n s t r a i n e d by r a n g e b e g i n 3 D , end3D ∗/
t e m p l a t e <c l a s s p l a c e , c l a s s r e q C l a s s >
b o o l g e t B o o l ( p l a c e posOrName , r e q C l a s s r e q )
/∗ g e t l o g i c a l v a l u e . ∗/
t e m p l a t e <u n s i g n e d i n t N, c l a s s T , c l a s s p l a c e , c l a s s r e q C l a s s >
3
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
M u l t i A r r a y V i e w <N, T> g e t M u l t i A r r a y ( p l a c e posOrName , r e q C l a s s r e q )
/∗ g e t M u l t i A r r a y V i e w w i t h dim N and Type T∗/
template < c l a s s T, c l a s s place , c l a s s r e q C l a ss >
B a s i c I m a g e V i e w<T> g e t I m a g e ( p l a c e posOrName , r e q C l a s s r e q )
/∗ g e t B a s i c I m a g e V i e w w i t h Type T∗/
t e m p l a t e<c l a s s T , u n s i g n e d i n t s z e , c l a s s p l a c e , c l a s s r e q C l a s s >
T i n y V e c t o r V i e w< T , s z e > g e t T i n y V e c t o r ( p l a c e posOrName , r e q C l a s s r e q )
/∗ g e t T i n y V e c t o r V i e w o f Type T and s i z e s z e ∗/
t e m p l a t e< u n s i g n e d i n t s z e , c l a s s p l a c e , c l a s s r e q C l a s s >
T i n y V e c t o r V i e w<M u l t i A r r a y I n d e x , s z e > g e t S h a p e ( p l a c e posOrName , r e q C l a s s r e q )
/∗ g e t M u t l i a r r a y S h a p e s i z e s z e ∗/
t e m p l a t e< c l a s s p l a c e , c l a s s r e q C l a s s >
i n t g e t D i m O f I n p u t ( p l a c e posOrName , r e q C l a s s r e q )
/∗ g e t D i m e n s i o n o f I n p u t a t p l a c e posOrName ∗/
t e m p l a t e<c l a s s p l a c e , c l a s s r e q C l a s s >
C o n s t C e l l A r r a y g e t C e l l A r r a y ( i n t pos , r e q C l a s s r e q )
/∗ g e t a O b j e c t o f t y p e C o n s t C e l l A r r a y
NOTE : C e l l A r r a y may n o t be i n t h e s t r u c t ! ! ! ∗/
4.1
1
2
Using the getEnum method
VIGRA CREATE ENUM AND STD MAP4 ( MapName , C o r n e r , F o e r s t n e r , Rohr , B e a u d e t ) ;
int
method =
i n p u t s . getEnum ( 2 ,
v d e f a u l t ( C o r n e r ) , MapName ) ;
The first command is a macro. const int variables with names. Corner, Foerstner,
Rohr and Beaudet. Also it creates a std::map MapName that maps the corresponding
strings to the constants the method variable is then initialized with the getEnum
method.
Listing 5: matlab::OutputArray
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
mxArray ∗ & o p e r a t o r [ ] ( i n t p o s )
A c c e s s r e f e r e n c e t o t h e mxArray ∗ a t c e r t a i n p l a c e .
size type size ()
returns nlhs
bool i s V a l i d ( i n t pos )
r e t u r n s t r u e i f a Output was r e q u i r e d a t p o s i t i o n p o s .
bool isEmpty ( i n t pos )
r e t u r n t r u e i f A r r a y a t p l a c e posOrNum i s empty .
t e m p l a t e <u n s i g n e d i n t DIM , c l a s s T , c l a s s ReqType>
M u l t i A r r a y V i e w <DIM , T> c r e a t e M u l t i A r r a y ( i n t pos , ReqType r e q ,
c o n s t T i n y V e c t o r <i n t , DIM> & s h a p e )
/∗ c r e a t e M u l t i A r r a y V i e w o f d i m e n s i o n Dim and t y p e T and a l l o c a t e
enough s p a c e f o r s h a p e ∗/
t e m p l a t e <c l a s s T , c l a s s ReqType>
B a s i c I m a g e V i e w<T> c r e a t e I m a g e ( i n t pos , ReqType r e q ,
mwSize w i d t h , mwSize h e i g h t )
t e m p l a t e <c l a s s T , c l a s s ReqType>
B a s i c I m a g e V i e w<T> c r e a t e I m a g e (
i n t pos , ReqType r e q ,
typename M u l t i A r r a y S h a p e <2>:: t y p e c o n s t & s h a p e )
t e m p l a t e <c l a s s T , c l a s s ReqType>
T∗ c r e a t e S c a l a r ( i n t pos , ReqType r e q )
/∗ a l l o c a t e memory f o r a s c a l a r and r e t u r n p o i n t e r t o i t . ∗/
t e m p l a t e <c l a s s T , c l a s s ReqType>
v o i d c r e a t e S c a l a r ( i n t pos , ReqType r e q , T v a l )
/∗ a l l o c a t e memory f o r a s c a l a r and c o p y v a l i n t o
i t . ∗/
t e m p l a t e <c l a s s ReqType>
C o n s t C e l l A r r a y c r e a t e C e l l A r r a y ( i n t pos , ReqType r e q , mwSize s z e )
4
5
The Required/Optional/Default objects
The createType and getType functions always take an object of type Required,
DefaultImpl<T>, DefaultImplVoid or bool as second argument Use the factory
methods v_required(), v_default() and v_optional to create these objects:
Listing 6: Behavior of the get/set functions with the factory objects
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
v required ( void )
/∗ g e n e r a t e s an e r r o r m e s s a g e i f t h e ar g u m e n t was n o t s u p p l i e d . ∗/
v optional ()
/∗ d o e s n o t h i n g . I f a rg u m e n t was n o t s u p p l i e d d e f a u l t
c o n s t r u c t o r i s c a l l e d . ∗/
v o p t i o n a l ( bool f l a g )
/∗ same a s a b o v e . Only t h a t f l a g i s s e t i f a r gu m e n t was s u p p l i e d .
f l a g i s f a l s e o t h e r w i s e . ∗/
/∗ A d d i t i o n a l l y when i n u s e w i t h t h e g e t method : ∗/
v default ( defaultVal )
/∗ r e t u r n s d e f a u l t V a l i f no ar g u m e n t s u p p l i e d . ∗/
v d e f a u l t ( defaultVal2D , defaultVal3D , dimSwitch )
/∗ i f d i m S w i t c h == 2 u s e d e f a u l t V a l 2 D e l s e u s e d e f a u l t V a l 3 D ∗/
Note: If you need to know whether an Object was set even if you used
v_default(defaultval) Explicitly create the DefaultImpl<T> object (Only if using
the first method):
Listing 7: Finding out whether a default object was set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// c r e a t e a d e f a u l t M u l t i A r r a y
M u l t i A r r a y <3, T> i n ( SomeShape ) ;
// C r e a t e d e f a u l t I m p l o b j e c t
D e f a u l t I m p l <typename M u l t i A r r a y V i e w <3,T> >
d e f a u l t M u l t i A r r a y V i e w ( M u l t i A r r a y V i e w <3,T>( i n ) ) ;
M u l t i A r r a y V i e w <3,T> Arg =
i n p u t s . g e t M u l t i A r r a y <3,T>(0 , v d e f a u l t ( d e f a u l t M u l t i A r r a y V i e w ) ) ;
// f i r s t way o f c h e c k i n g w h e t h e r Argument was s u p p l i e d :
i f ( d e f a u l t M u l t i A r r a y V i e w . g a r b a g e == t r u e )
s t d : : c o u t << ” i t h a s b e e n s e t ” ;
/∗ s e c o n d way o f c h e c k i n g w h e t h e r Argument was s u p p l i e d − o n l y w o r k s w i t h t h e
View c l a s s e s , n o t w i t h s c a l a r s : ∗/
i f ( i n . d a t a ( ) == Arg . d a t a ( ) )
s t d : : c o u t << ” i t h a s n o t b e e n s e t ” ;
6
Build and Test scripts
Use buildVigraExtensions and testVigraExtensions to build all mex files and to
test the matlab.hxx interface.
Note: The test script calls buildVigraExtensions to create the test mex files
located in the test subdirectory
7
other classes
The ConstStructArray object is used to store the options. It should not be necessary
to manipulate the ConstStructArray directly.
Listing 8: ConstStructArray (Options) ConstStructArray(mxArray* matPointer)
/*Constructor.*/ operator[
1
2
/∗ a c c e s s mxArray ∗ w h i c h i s
f i e l d N a m e . ∗/
stored in the StructArray with
5
3
4
5
6
isValid ()
/∗ i s t r u e i f C o n s t S t r u c t A r r a y p o i n t s t o a v a l i d m a t P o i n t e r ∗/
i s V a l i d ( std : : s t r i n g )
/∗ t r u e i f f i e l d w i t h name s p e c i f i e d i n s t r i n g e x i s t s ∗/
This is just some experimental code but quite handy if you have make and handle
sparse arrays. Basically just a wrapper class to a stl::map;
Listing 9: Sparse array
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
t e m p l a t e<c l a s s T>
class SparseArray
private :
s t d : : map<T i n y V e c t o r <i n t ,2 > , T , ShapeCmp> d a t a ;
i n t width , l e n g t h ;
public :
SparseArray ( i n t i = 1 , i n t j = 1)
// c a l l s a s s i g n ;
void a s s i g n ( i n t i = 1 , i n t j = 1)
/∗ s e t i n t r i n s i c s i z e o f t h e S p a r s e A r r a y − o n l y n e e d e d when u s i n g map
To MxArray . ∗/
T& o p e r a t o r ( ) ( i n t i , i n t j ){
c o n s t T g e t ( i n t i , i n t j ){
// g e t and s e t e l e m e n t ;
// Any b e t t e r i d e a ? i would l i k e t o u n i f y t h e g e t and o p e r a t o r ( )
// f u n c t i o n s .
// Problem i s t h a t
operator () always passes a r e f e r e n c e or c r e a t e s
// one .
v o i d mapToMxArray ( mxArray ∗ & i n )
// C r e a t e s a s p a r s e mxArray and c o p i e s d a t a i n t o
6
it .