Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Developing a new MEX function

Amro edited this page Oct 4, 2018 · 9 revisions

C++ Sources

Functions

All you need to do is to add your C++ source file in src/+cv/. If you want to add a MEX function called myfunc, create src/+cv/myfunc.cpp. The minimum contents of the myfunc.cpp would look like this:

#include "mexopencv.hpp"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Check number of arguments
    nargchk(nlhs<=1 && nrhs==1);

    // Convert mxArray to cv::Mat
    cv::Mat mat = MxArray(prhs[0]).toMat();

    // Do whatever you want

    // Convert cv::Mat back to mxArray
    plhs[0] = MxArray(mat);
}

This example simply copies an input to a cv::Mat object and then copies it again to the output. Notice how the MxArray class provided by mexopencv converts mxArray to cv::Mat object and back. Of course you would want to do something more with the object. Once you create a new source file, type mexopencv.make() in MATLAB to build your new function. The compiled MEX function will be located inside +cv/ and accessible through cv.myfunc within MATLAB.

The mexopencv.hpp header includes the class MxArray to manipulate mxArray objects. Mostly this class is used to convert between OpenCV data types and mxArray.

int i              = MxArray(prhs[0]).toInt();
double d           = MxArray(prhs[0]).toDouble();
float f            = MxArray(prhs[0]).toFloat();
bool b             = MxArray(prhs[0]).toBool();
std::string s      = MxArray(prhs[0]).toString();
cv::Mat mat        = MxArray(prhs[0]).toMat();   // For pixels
cv::MatND mat      = MxArray(prhs[0]).toMatND(); // For N-D array
cv::SparseMat sp   = MxArray(prhs[0]).toSparseMat(); // Only double to float
cv::Point pt       = MxArray(prhs[0]).toPoint();
cv::Size sz        = MxArray(prhs[0]).toSize();
cv::Rect rct       = MxArray(prhs[0]).toRect();
cv::Scalar sc      = MxArray(prhs[0]).toScalar();
cv::RotatedRect rr = MxArray(prhs[0]).toRotatedRect();

plhs[0] = MxArray(i);
plhs[0] = MxArray(d);
plhs[0] = MxArray(b);
plhs[0] = MxArray(s);
plhs[0] = MxArray(mat);
plhs[0] = MxArray(sp); // Only 2D float to double
plhs[0] = MxArray(pt);
plhs[0] = MxArray(sz);
plhs[0] = MxArray(rct);
plhs[0] = MxArray(sc);
plhs[0] = MxArray(rr);

There are also versions that handle STL vectors of such types. Check MxArray.hpp for the complete list of the conversion API. mexopencv.hpp also contains additional helper conversion functions.

Classes

If you rather want to develop a MATLAB class that internally calls a MEX function, make use of the +cv/private/ directory. Any function placed under private directory is only accessible from +cv/ directory.

So if you want to design a MATLAB class cv.MyClass that wraps the various behavior of a C++ class, define your MATLAB class at +cv/MyClass.m with a corresponding MEX function in src/+cv/private/MyClass_.cpp. Inside of +cv/MyClass.m, you can call MyClass_() without the cv namespace. In mexopencv, this is usually used to exposed C++ classes as MATLAB classes.

Check +cv/PCA.m and src/+cv/private/PCA_.cpp for a concrete example.

Unit Tests

You can optionally add a testing script for your new function. The testing convention in mexopencv is that testing scripts are all written as a static function in a MATLAB class. For example, test/unit_tests/TestFilter2D.m is a class that describes test cases for cv.filter2d function. Inside of the class, a couple of test cases are written as static functions whose name start with 'test'.

Testing is performed by test/UnitTest.m. It looks for unit testing classes inside test/unit_tests/, invokes all test cases, and reports the results. Place any resource files necessary for testing inside the test/ directory. An example of testing class is shown below:

classdef TestMyFunc
    methods (Static)
        function test_my_func
            src = imread(fullfile(mexopencv.root(),'test','img001.jpg'));
            ref = [1,2,3];                  % reference output
            dst = cv.myfunc(src);           % execute your function
            assert(isequal(dst, ref));      % check the output
        end

        function test_error_argnum
            try
                cv.myfunc('foo');           % myfunc should throw an error
                error('UnitTest:Fail', 'myfunc incorrectly returned');
            catch ME
                assert(strcmp(ME.identifier, 'mexopencv:error'));
            end
        end
    end
end

First add the test directory to the MATLAB path and invoke UnitTest to run all the test routines. You can also run make test from a Unix shell.

Documentation

You can create a MATLAB help documentation for a MEX function by having the same file with '.m' extension. For example, a help file for src/+cv/filter2D.cpp would be +cv/filter2D.m placed next to the compiled MEX function +cv/filter2D.mex*. The help file should only contain MATLAB comments. MATLAB will display the help text when you run help cv.filter2D. An example is shown below:

%MYFUNC  Brief description about my function
%
%     out = cv.myfunc(in)
%
% ## Input
% * __in__ input image.
%
% ## Output
% * __out__ output image.
%
% Detailed description of function continues...
%
% See also: cv.filter2D
%

The help file can also contain Markdown syntax in the comments, which is processed by MDoc when generating the HTML documentation.