Matlab and C ++ mixed programming (dependent on OpenCV), and Matlab OpenCV
Matlab and C ++ hybrid programming is actually to compile C ++ code into executable files and function interfaces that Matlab supports calling through Matlab's Mex tool. In this way, you can use the functions that have been compiled in Matlab, even though this function is written in C ++. Communication without borders is achieved, and there is no one who is unified, and there is only one and only one who is arrogant. On the other hand, take the C ++ director to make up for your shortcomings. Matlab is good at matrix operations, but its efficiency in cyclic operations is less efficient than that in C ++, such as the creation of a Hilbert matrix. Therefore, you can use C ++ to complete computation with large loops.
I. Beginner
When using MATLAB to compile C/C ++ code, we need to modify the C/C ++ code and add the function interfaces supported by Matlab. In this way, Matlab can call it. Then compile it using the Mex tool of Matlab. The following is an example to illustrate these two steps.
Suppose we have a very simple C ++ code that implements the addition of two double numbers:
Mexico Add. cpp
1 #include <iostream>2 using namespace std;3 4 double add(double x, double y)5 {6 return x + y;7 }
1. modify the code file
1) Add the header file mex. h.
Add the header file at the beginning of the c ++ file:
# Include "mex. h"
2) Add the interface function ()
The definition of Mexico function is as follows:
Void mexFunction (int nlhs, mxArray * plhs [], int nrhs, const mxArray * prhs [])
{
}
First, this function does not return values. It does not return the computation result of c ++ code to Matlab through the return value, but by assigning values to the plhs parameter. For example, in Matlab, calling this add function is generally like this:
> A = 0.5; B = 0.8;
> C = add (a, B );
Then, how does one pass the input parameters a and B to the add function of c ++, and then return the calculation result to c? All of these coarse-performing activities are implemented through four parameters of the mexFunction:
Nlhs: the number of left hand size parameters, that is, the number of variables on the left of the Matlab CALL statement, is actually the number of return variables that need to be returned to Matlab. For example, above c = add (a, B); there is only one return parameter c, so nlhs is 1;
Plhs: It feels like pointer of left hand size parameters, that is, the pointer to the parameter returned by the function. But it is a pointer array. In other words, it is an array, each element is a pointer, and each Pointer Points to a response parameter with a data type of mxArray. For example, the above c = add (a, B); only one return parameter c, so the array has only one pointer, and the result indicated by plhs [0] is assigned to c.
Nrhs: number of right hand size parameters, that is, the number of variables on the right of the Matlab CALL statement. For example, above c = add (a, B), it passes two parameters a and B to the c ++ code, so nrhs is 2;
Prhs: This is pointer of right hand size parameters, similar to plhs, because there are two independent variables on the right hand side, that is, the array has two pointers, and prhs [0] points to, prhs [1] points to B. Note that prhs is a const pointer array, that is, it cannot be changed to the content.
Because the most basic unit of Matlab is array, no matter what type it is, such as doublearray, cell array, struct array ...... So a, B, and c are all arrays, and B = 1.1 is a double array of 1x1. In C language, the array of Matlab is represented by the mxArray type. Therefore, it is not difficult to understand why plhs and prhs both point to the mxArray type pointer array (see [1]).
So how can I write the function body of the mexFunction? How can we use this interface function to associate Matlab parameters with the corresponding parameters in c ++ code? First, we will display all the code.
The last mexAdd. cpp is as follows:
Mexico Add. cpp
1 #include "opencv2/opencv.hpp" 2 #include "mex.h" 3 4 double add(double x, double y) 5 { 6 return x + y; 7 } 8 9 10 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])11 {12 double *a;13 double b, c;14 plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);15 a = mxGetPr(plhs[0]);16 b = *(mxGetPr(prhs[0]));17 c = *(mxGetPr(prhs[1]));18 *a = add(b, c);19 }
What does the content of Mexico function mean? We know that if the function is called in Matlab as follows:
> Output = add (0.5, 0.8 );
When no specific calculation is involved, the output value is unknown and is not assigned a value. Therefore, in a specific program, we create a real double matrix of 1x1 (using the mxCreateDoubleMatrix function, which returns a pointer to the newly created mxArray), and then let plhs [0] point to it. Next, let Pointer a point to the first element of mxArray pointed to by plhs [0] (using the mxGetPr function, return the pointer to the first element of mxArray ). Similarly, we extract the elements (0.5 and 0.8) pointed to by prhs [0] And prhs [1] to B and c. Therefore, we can pass B and c as independent variables to the add function to obtain the elements in the mxArray to which the pointer a points. Because a is an element pointing to the mxArray pointed to by plhs [0], the mxArray pointed to by plhs [0] is assigned to output in the final output, the output is the calculated result.
In fact, the Mexican function is not so simple. We need to test the number and type of user input independent variables to ensure that the input is correct. For example, in the add function example, the user input char array is an error.
As mentioned above, the MEX file implements an interface to return the computation results in C language to Matlab as appropriate. When we have a large program written in C, we don't have to rewrite it in Matlab, but write only one interface to make it into a MEX file. In addition, some computing bottlenecks (such as loops) in the Matlab program can be achieved through the MEX file in C language to increase the computing speed (see [1]).
2. Compile the modified c ++ File
After the file is modified, We need to compile it to generate executable files supported by Matlab. Here, we need the Mex tool that comes with Matlab. But in the compiler, We need to configure this tool to tell it what compiler you want to use to compile our c/c ++ code. Run in Matlab:
> Mex-setup
You can select a default compiler. For example, here I want to select the ACM that comes with Matlab or Microsoft Visual C ++ 2010 that I installed on my computer. Generally, the latter is selected. You can compile the configuration. Compilation also has the following situations:
> Mex XXX. cpp
> Mex X1.cpp X2.cpp X3.cpp % multiple cpp files with dependencies. The generated database name is X1.
> Mex-O X1.cpp % uppercase O option to optimize Compilation
> Mex-largeArrayDims X1.cpp % specifies the API used to process large-capacity Arrays for 64-bit systems. Because the interfaces between Matlab and C ++ are based on 32-bit systems, this makes it impossible for people to take advantage of the speed advantage of C and C ++ when processing large data volumes. However, for 64-bit systems, system resources are generally more adequate than 32-bit systems, so you can specify this interface to make it easier for large-capacity data processing.
There are also some compilation options, like gcc. For example,-I specifies the directory to be included,-L specifies the directory of the library to be connected, and-l specifies the library to be linked.
It's easy for our program. In the MATLAB command window, enter the following command: mexmadd. cpp to compile successfully. After compilation is successful, a file with the same name will appear in the same folder, but with the suffix of mexw32 (32-bit system) or mexw64 (64-bit system), such as mexAdd. mexw32. Then, you can directly call it in Matlab to calculate it:
> Ans = Mexico add (0.5, 0.8 );
Ii. Advanced
The above is for processing scalar values, that is, numbers a, B, or c. In this section, let it process two-dimensional arrays, that is, images. In order to verify, We are dumb to do the following:
> [GrayImage] =RGB2Gray('imageFile.jpeg ');
That is, an image file name is passed to the c ++ code. Then the c ++ Code reads the image, converts it to a grayscale image, and then returns it to Matlab. The image reading and grayscale conversion operations in the c ++ code are implemented by calling the library function of OpenCV. Are you stupid? Because Matlab already has functions that implement the same function. Yes, that's right. However, we have no intention to explain the transfer process of two-dimensional arrays. However, if we want to calculate the optical flows of two images, Matlab may really need the help of OpenCV.
In addition, because the cpp file is linked to the OpenCV library, I wrote a make. m file. Its function is similar to Makefile. In fact, it implements the compilation rules for mex to compile this project. For details, refer to the following code and then you will know what you have done in it.
The first is the RGB2Gray. cpp Code:
1 #include "opencv2/opencv.hpp" 2 #include "mex.h" 3 4 using namespace cv; 5 6 /******************************************************* 7 Usage: [imageMatrix] = RGB2Gray('imageFile.jpeg'); 8 Input: 9 a image file10 OutPut: 11 a matrix of image which can be read by Matlab12 13 **********************************************************/14 15 16 void exit_with_help()17 {18 mexPrintf(19 "Usage: [imageMatrix] = DenseTrack('imageFile.jpg');\n"20 );21 }22 23 static void fake_answer(mxArray *plhs[])24 {25 plhs[0] = mxCreateDoubleMatrix(0, 0, mxREAL);26 }27 28 void RGB2Gray(char *filename, mxArray *plhs[])29 {30 // read the image31 Mat image = imread(filename);32 if(image.empty()) {33 mexPrintf("can't open input file %s\n", filename);34 fake_answer(plhs);35 return;36 }37 38 // convert it to gray format39 Mat gray;40 if (image.channels() == 3)41 cvtColor(image, gray, CV_RGB2GRAY);42 else43 image.copyTo(gray);44 45 // convert the result to Matlab-supported format for returning46 int rows = gray.rows;47 int cols = gray.cols;48 plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);49 double *imgMat;50 imgMat = mxGetPr(plhs[0]);51 for (int i = 0; i < rows; i++)52 for (int j = 0; j < cols; j++)53 *(imgMat + i + j * rows) = (double)gray.at<uchar>(i, j);54 55 return;56 }57 58 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])59 {60 if(nrhs == 1)61 {62 char filename[256];63 mxGetString(prhs[0], filename, mxGetN(prhs[0]) + 1);64 if(filename == NULL)65 {66 mexPrintf("Error: filename is NULL\n");67 exit_with_help();68 return;69 }70 71 RGB2Gray(filename, plhs);72 }73 else74 {75 exit_with_help();76 fake_answer(plhs);77 return;78 }79 }
Compared with the above, there are several more things in it. The first step is to test the input parameters to see if there are errors in the parameters passed in by Matlab, and some exception handling is included. The second is help information. The third is the main implementation function. Only the reading image and grayscale conversion of OpenCV will not be mentioned here, that is, the call of two functions. The key point is to pass an image, that is, a two-dimensional array, to the parameter of the mexFunction and let it return to the Matlab. In fact, we only need to be clear:
Plhs [0] = mxCreateDoubleMatrix (2, 3, mxREAL );
The pointer plhs [0] of the matrix created by this function is stored in column mode. Assume that imgMat is its pointer. * (imgMat + 1) is the matrix element [1, 0]. * (imgMat + 2) is the matrix element [0, 1]. * (imgMat + 4) is the matrix element [0, 2]. The above Code assigns the pixel value in the gray image to the corresponding position of the plhs [0] parameter (in fact, it may be possible to directly copy the memory, but because it is a pointer operation, it involves the destruction of the local variable gray, so we simply use the stupid but stable method to implement it ).
Well, the following is the make. m file. You need to obtain whether your computer's system version is 32 or 64-bit to select the compilation option. Then add the related configurations of OpenCV. If you want to use it, change it to the related directory of your OpenCV. Then a list of files to be compiled is provided. Finally, analyze the list and add the compilation option to compile all the files in the list using mex.
1 %// This make.m is for MATLAB 2 %// Function: compile c++ files which rely on OpenCV for Matlab using mex 3 4 %% Please modify your path of OpenCV 5 %% If your have any question, please contact Zou Xiaoyi 6 7 % Notice: first use "mex -setup" to choose your c/c++ compiler 8 clear all; 9 10 %-------------------------------------------------------------------11 %% get the architecture of this computer12 is_64bit = strcmp(computer,'MACI64') || strcmp(computer,'GLNXA64') || strcmp(computer,'PCWIN64');13 14 15 %-------------------------------------------------------------------16 %% the configuration of compiler17 % You need to modify this configuration according to your own path of OpenCV18 % Notice: if your system is 64bit, your OpenCV must be 64bit!19 out_dir='./';20 CPPFLAGS = ' -O -DNDEBUG -I.\ -ID:\OpenCV_64\include'; % your OpenCV "include" path21 LDFLAGS = ' -LD:\OpenCV_64\lib'; % your OpenCV "lib" path22 LIBS = ' -lopencv_core240 -lopencv_highgui240 -lopencv_video240 -lopencv_imgproc240';23 if is_64bit24 CPPFLAGS = [CPPFLAGS ' -largeArrayDims'];25 end26 %% add your files here!27 compile_files = { 28 % the list of your code files which need to be compiled29 'RGB2Gray.cpp'30 };31 32 33 %-------------------------------------------------------------------34 %% compiling...35 for k = 1 : length(compile_files)36 str = compile_files{k};37 fprintf('compilation of: %s\n', str);38 str = [str ' -outdir ' out_dir CPPFLAGS LDFLAGS LIBS];39 args = regexp(str, '\s+', 'split');40 mex(args{:});41 end42 43 fprintf('Congratulations, compilation successful!!!\n');
Iii. Usage and results
1. Compile
Run make. m directly in Matlab. You can generate RGB2Gray. mexw64. Then run in Matlab:
> Img = RGB2Gray ('d: \ test.jpg ');
> Imshow (uint8 (img ));
The conversion result is displayed,
Note:The above Matlab instructions are all in the directory where your cpp file is located.
Iv. References
[1] how to write the mexFunction
[2] matlab uses mex to compile cpp files
[3] matlab and C ++ Mixed Programming