Пошаговое руководство по простой отправке переменных OpenCV C++ в Matlab
Я хочу иметь возможность отправлять любые переменные OpenCV в Matlab, чтобы строить графики и рассчитывать статистику удобным способом.
Я знаю, что должен использовать Matlab Engine, но в Интернете мало информации о том, как сделать его доступным из любой части кода, или о функциях, конвертирующих из массивов CV::Mat в Matlab, или о том, как работать со столбцами. -майор и мажор в этом конкретном случае.
Я думаю, что пошаговая процедура OpenCV-to-Matlab была бы очень интересной, поскольку OpenCV становится действительно популярным, а Matlab очень помогает для отладки.
1 ответ
Пошаговая отправка данных из OpenCV в Matlab
1.- Включение и связывание библиотек
Необходимые заголовки для работы с Matlab Engine - это "engine.h" и "mex.h". Путь включения будет примерно таким:
c: \ Program Files (x86 \ MATLAB \ R2010a \ extern \ include)
В дополнительные зависимости вы должны добавить: libeng.lib, libmex.lib и libmx.lib.
Самый простой способ настроить проект - использовать CMake, так как вам просто нужно написать строки
find_package(требуется Matlab)
INCLUDE_DIRECTORIES ($ {MATLAB_INCLUDE_DIR})
CMake установит пути для вас и свяжет необходимые библиотеки. Используя переменные окружения, вы делаете проект независимым от пользователя. Вот почему я всегда использую CMake.
2.- Шаблон Singleton для уникального экземпляра Matlab Engine.
Действительно удобный способ вызова Matlab Engine из любой части кода - это создание шаблона Singleton. Например, вы можете создать "matlabSingleton.h" и написать что-то вроде этого.
#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 ...
};
Тогда в "matlabSingleton.cpp" вы должны написать
#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.- Использование движка Matlab из вашего основного кода.
Есть много способов сделать это, но я обычно определяю функцию initializeMatlab()
где я инициализирую переменные (переменные Matlab), я буду позже использовать. Вам не нужно создавать класс MatlabWrapper, потому что при первом вызове getInstance() он будет создан. В следующий раз, когда вы вызовете getInstance, он будет просто возвращен. Вот для чего синглетон.
void initializeMatlab(){
MatlabWrapper::getInstance()->initializeVariable("whatever1"); //class is created
MatlabWrapper::getInstance()->initializeVariable("whatever2"); //instance of the class returned
}
4.- Отправка матрицы OpenCV в Matlab
На этом я и столкнулся с большими трудностями. Это простая функция просто для отправки матрицы в Matlab для пошаговой отладки. Он перезаписывается каждый раз.
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);
}