Writing MEX-files that use DIPlib
Contents
A MEX-file is a compiled C, C++ or Fortran function (C++ if it uses DIPlib) that can be called from MATLAB as if it were a normal MATLAB function. It must take MATLAB data as input and produce MATLAB data as output. To call a DIPlib function from the MEX-file, the MATLAB data must be converted to the right C++ types. This chapter describes the functionality we wrote for this purpose.
It is assumed that the reader is familiar with basic MEX-files (see the MATLAB MEX-file documentation if not) and basic DIPlib (see the documentation if not). We exclusively use the C API.
The DIPlib–MATLAB interface
The header file dip_matlab_interface.h contains a series of functions that can be used to convert MATLAB types to DIPlib types and vice versa. These functions make it very easy to write a MATLAB interface to DIPlib functions (and this is its main purpose), but could be used for other purposes too.
All its functionality is in the dml
namespace.
Output images
The main trick that it can do is prepare a dip::Image
object that, when forged
by a DIPlib function, will have MATLAB allocate the memory for the pixels,
such that no copy needs to be made when this image is returned to MATLAB. For
this, create an object of type dml::MatlabInterface
. Its dml::MatlabInterface::NewImage
function creates a raw image that can be forged (or passed as output image to
any DIPlib function). The dml::GetArray
function
can then be used to obtain a pointer to the mxArray
containing a dip_image
object with the same pixel data. Note that the dml::MatlabInterface
object
needs to exist throughout this process, as it owns the data until dml::GetArray
extracts it.
This is a skeleton MEX-file that outputs such an image:
#include <dip_matlab_interface.h> // Always include this, it includes diplib.h and mex.h void mexFunction( int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[] ) { try { // Create an output image dml::MatlabInterface mi; dip::Image out = mi.NewImage(); // Forge it out.ReForge( { 256, 256 }, 1, dip::DT_UINT8 ); out.Fill( 0 ); // Usually you'd do something more exciting here! // Retrieve the MATLAB array for the output image (it's a dip_image object) plhs[ 0 ] = dml::GetArray( out ); } DML_CATCH }
The documentation to dml::MatlabInterface
gives more details about how to use
the images created in this way.
Input images
The function dml::GetImage
takes an mxArray
pointer, checks it for validity,
and returns a dip::Image
object that shares data with the mxArray
(except in
exceptional circumstances: complex-valued numeric arrays must be copied because
their storage is different in MATLAB and DIPlib; complex-valued dip_image
objects are not copied).
For example, one can add the following line to the mexFunction
above:
dip::Image const in = ( nrhs > 0 ) ? dml::GetImage( prhs[ 0 ] ) : dip::Image();
This line calls dml::GetImage
only if prhs[0]
actually exists. If not, it
creates a raw image object. You should always check nrhs
before reading any of
the prhs
elements. Likewise, you should always check nlhs
before assigning
to any of the plhs
elements except the first one (plhs
always has at least
one element, even if nlhs == 0
).
Converting other types
There exist similar Get...
functions for just about every DIPlib type, for example
dml::GetFloat
, dml::GetFloatArray
or dml::GetFloatCoordinateArray
. See
the documentation to the dml
namespace for a complete list. These
take an mxArray
pointer as input, validate it, and output a value of the appropriate
type. If the validation fails, an exception is thrown.
There exist also a series of dml::GetArray
functions that do the reverse process:
they take a value of any type typically returned by a DIPlib function, and
convert it to an mxArray
, returning its pointer. Note that MATLAB always takes
care of freeing any mxArray
objects created by the MEX-file, there is no need
to do any manual memory management.
These data conversion functions all copy the data (only images are passed without copy, other data is typically not large enough to matter).
For more complex examples of MEX-files, see
examples/external_interfaces/matlab_mex_example.cpp
,
as well as the DIPimage MEX-files in
dipimage/private/
and
dipimage/@dip_image/private
.
Compiling a MEX-file
To compile a MEX-file like the one shown in the previous section, save it for example
as myfunction.cpp
, and use the dipmex
function in MATLAB:
dipmex myfunction.cpp
This function simply calls the mex
function, adding arguments to allow the compiler
to find the DIPlib header files and to link in the DIPlib library. Because this
is C++, it is important that the same compiler (and often also the same version) be
used to build the MEX-file as was used to build the DIPlib library. We recommend
that you build the library yourself. mex -setup C++
should be used to configure
MATLAB’s mex
command to use the right compiler.
The result of the dipmex
command above is a MEX-file called myfunction
. You can
call it like any other MATLAB function:
img = myfunction; % it has no input arguments
If your MEX-file needs more source files and/or libraries, simply add them to the
dipmex
command. You can also add other arguments for mex
here:
dipmex myfunction.cpp other_source.cpp /home/me/mylibs/libstuff.a -I/home/me/mylibs/
The MEX-file will always have as name the name of the first source file in the list,
unless an -output mexname
argument is given.