Reputation: 22245
I want to be able to send any OpenCV variables to Matlab in order to plot graphs and calculate statistics in a confortable way.
I know I have to use Matlab Engine, but there is little help on the web about how to make it accessible from any part of the code, or about functions to convert from CV::Mat to Matlab arrays, or how to deal with column-major and row-major in this specific case.
I think an step by step procedure OpenCV-to-Matlab would be very interesting since OpenCV is becoming really popular and Matlab helps a lot for debugging.
Upvotes: 3
Views: 1353
Reputation: 22245
Step by Step Sending data from OpenCV to Matlab
1.- Including and linking libraries
The neccesary headers for working with Matlab Engine are "engine.h" and "mex.h". The include path will be something like this:
c:\Program Files (x86\MATLAB\R2010a\extern\include)
In additional dependencies you should add: libeng.lib, libmex.lib and libmx.lib.
The easiest way to set up the project is by using CMake, as you just need to write the lines
find_package( Matlab REQUIRED )
INCLUDE_DIRECTORIES( ${MATLAB_INCLUDE_DIR})
CMake will set the paths for you and link the needed libraries. By using environment variables you make the project user-independent. That's the reason why I always use CMake.
2.- Singleton template for an unique instance of Matlab Engine.
A really comfortable way to call Matlab Engine from any part of the code is creating a Singleton template. You could create a "matlabSingleton.h", for example, and write something like this.
#include "engine.h";
#include "mex.h";
class MatlabWrapper
{
private:
static MatlabWrapper *_theInstance; ///< Private instance of the class
MatlabWrapper(){} ///< Private Constructor
static Engine *eng;
public:
static MatlabWrapper *getInstance() ///< Get Instance public method
{
if(!_theInstance) _theInstance = new MatlabWrapper(); // If NULL, create it
return _theInstance;
}
public:
static void openEngine();
void initializeVariable(const string vName) const;
// ... other functions ...
};
Then in "matlabSingleton.cpp" you should write
#include "matlabSingleton.h"
MatlabWrapper *MatlabWrapper::_theInstance = NULL; ///< Initialize instance as NULL
Engine *MatlabWrapper::eng=NULL;
void MatlabWrapper::openEngine()
{
if (!(eng = engOpen(NULL)))
{
cerr << "Can't start MATLAB engine" << endl;
exit(-1);
}
}
void MatlabWrapper::initializeVariable(const string vName) const
{
string command = vName + "=0";
engEvalString(eng, command.c_str());
}
3.- Using Matlab engine from your main code.
There are many ways to do this but I usually define a function initializeMatlab()
where I initialize the variables (Matlab variables) I will later use. You don't need to create the class MatlabWrapper because the first time you call getInstance() it will be created. Next times you call getInstance it will just be returned. That's what singletone is for.
void initializeMatlab(){
MatlabWrapper::getInstance()->initializeVariable("whatever1"); //class is created
MatlabWrapper::getInstance()->initializeVariable("whatever2"); //instance of the class returned
}
4.- Sending an OpenCV Matrix to Matlab
At this is where I foun more difficulties. This a simple function just to send a matrix to matlab for debugging step by step. It is overwritten each time.
void MatlabWrapper::cvLoadMatrixToMatlab(const Mat& m, const string name)
{
int rows=m.rows;
int cols=m.cols;
string text;
mxArray *T=mxCreateDoubleMatrix(cols, rows, mxREAL);
double *buffer=(double*)mxGetPr(T);
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
buffer[i*(cols)+j]= (double)m.at<float>(i,j);
}
}
engPutVariable(eng, name.c_str(), T);
text = name + "=" + name + "'"; // Column major to row major
engEvalString(eng, text.c_str());
mxDestroyArray(T);
}
Upvotes: 4