diff --git a/OpenCV_API.m b/OpenCV_API.m new file mode 100644 index 0000000..148e405 --- /dev/null +++ b/OpenCV_API.m @@ -0,0 +1,76 @@ +%================================================================ +% This class abstracts the API to an external OpenCV library. +% It implements static methods for updating the build information +% at compile time and build time. + +classdef OpenCV_API < coder.ExternalDependency + %#codegen + + methods (Static) + + function bName = getDescriptiveName(~) + bName = 'OpenCV_API'; + end + + function tf = isSupportedContext(buildContext) + myTarget = {'mex','rtw'};% 验证代码生成目标为mex或者dll,lib,exe + if buildContext.isCodeGenTarget(myTarget) + tf = true; + else + error('OpenCV_API only supported for mex, lib, exe, dll'); + end + + % hw = buildContext.getHardwareImplementation(); + + end + + function updateBuildInfo(buildInfo, buildContext) + % 输入buildInfo请参考:RTW.BuildInfo + % 输入buildContext请参考:coder.BuildConfig class + % + % Get file extensions for the current platform + % [~, linkLibExt, execLibExt, ~] = buildContext.getStdLibInfo(); + + % Code to run on Linux platform + includeFilePath = fullfile("E:\opencv4_4_0\opencv\MinGW64_v8_OpenCV4_4_Contrib_install\include"); + buildInfo.addIncludePaths(includeFilePath); + + % Link files + libPath = fullfile("E:\opencv4_4_0\opencv\MinGW64_v8_OpenCV4_4_Contrib_install\x64\mingw\lib"); + linkFiles = "libopencv_world440.dll.a"; + linkPath = libPath; + linkPriority = ""; + linkPrecompiled = true; + linkLinkOnly = true; + group = ''; + buildInfo.addLinkObjects(linkFiles, linkPath, ... + linkPriority, linkPrecompiled, linkLinkOnly, group); + + % include and source path +% buildInfo.addIncludePaths("./"); +% buildInfo.addSourcePaths("./"); + end + + %API for library function 'imread' + function outImg = imread(imagePath) + arguments + imagePath (1,1) string + end + + outImg = coder.nullcopy(zeros(480,640,3,"uint8")); + if coder.target('MATLAB') + % running in MATLAB, use built-in addition + outImg = imread_opencv_mex(imagePath); + else + % Add the required include statements to the generated function code + coder.cinclude('opencvAPI.h'); + % include external C++ functions + coder.updateBuildInfo('addSourceFiles', "opencvAPI.cpp"); + + % 调用OpenCV C++代码包装器 + imgPath = [char(imagePath),0]; + coder.ceval('imreadOpenCV', coder.rref(imgPath),coder.wref(outImg)); + end + end + end +end \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..85e8a92 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# MATLAB MEX file For C/C++ code generation + +![logo](images/logo.PNG) + +## OverView + +In order to call external C/C++ library functions, it is generally recommended to use the [mex](https://ww2.mathworks.cn/help/matlab/ref/mex.html) built-in function to compile the source code into a mex executable file, but the disadvantage is that it is not easy to generate C/C++ code in turn if there are other matlab code mixed in. This example is just to show how to use [codegen](https://ww2.mathworks.cn/help/coder/ref/codegen.html) two-way through this process, not limited to the example itself, is a general method, another advantage is not limited to the code generation of various restrictions, fully integrated with C/C++ programming. + +## Requirements + +- MATLAB +- Matlab Coder toolbox +- [Supported and Compatible Compilers](https://ww2.mathworks.cn/en/support/requirements/supported-compilers.html) +- Your External C/C++ Library(This example uses OpenCV as an example) + +## How to setup + +### 1.Configuring the compiler + +In the command window,configure your complier. + +```matlab +mex -setup C++ +``` + +### 2.Source Code Preparation + +Prepare your C/C++ code and MATLAB entry-point function.Prepare the implementation of the `updateBuildInfo(buildInfo, buildContext)` member function, rewritten according to the path of the external library. (header files and library files). + +### 3.Generate or Compile + +Generate or compile the files you want with the `codegen` command. +For example: + +```matlab +imagePath = "./test_480x640x3.jpg"; +input1 = coder.typeof(imagePath); +input1.StringLength=inf; +codegen -config:mex imread_opencv -args {input1} -lang:c++ -report +``` diff --git a/images/logo.PNG b/images/logo.PNG new file mode 100644 index 0000000..5415968 Binary files /dev/null and b/images/logo.PNG differ diff --git a/imread_opencv.m b/imread_opencv.m new file mode 100644 index 0000000..21ba8a7 --- /dev/null +++ b/imread_opencv.m @@ -0,0 +1,37 @@ +function outImg = imread_opencv(imagePath)%#codegen +% Brief: Write a function imreadOpencv that calls the external library function. +% Details: +% Read a uint8 image of size 480*640 +% +% Syntax: +% outImg = imread_opencv(imagePath) +% +% Inputs: +% imagePath - [1,1] size,[string] type,image path +% +% Outputs: +% outImg - [480,640] size,[uint8] type,Description +% +% codegen command: +% imagePath = "./test_480x640_uint8.jpg"; +% input1 = coder.typeof(imagePath); +% input1.StringLength=inf; +% +% codegen -config:mex imread_opencv -args {input1} -lang:c++ -report +% +% Usage Example: +% imagePath = "./test_480x640_uint8.jpg"; +% result = imread_opencv(imagePath); +% +% +% Example: +% None +% +% See also: None + + +arguments + imagePath (1,1) string +end +outImg = OpenCV_API.imread(imagePath); +end \ No newline at end of file diff --git a/opencvAPI.cpp b/opencvAPI.cpp new file mode 100644 index 0000000..81a2d67 --- /dev/null +++ b/opencvAPI.cpp @@ -0,0 +1,29 @@ +#include "opencvAPI.h" + +// 对应OpenCV的cv::Mat转MATLAB uint8类型或logical图像 +void convertCVToMatrix(cv::Mat &srcImg, int rows, int cols, int channels, unsigned char dst[]) { + CV_Assert(srcImg.type() == CV_8UC1 || srcImg.type() == CV_8UC3); + size_t elems = rows * cols; + if (channels == 3) { + cv::Mat channels[3]; + cv::split(srcImg.t(), channels); + + memcpy(dst, channels[2].data, elems * sizeof(unsigned char)); //copy channel[2] to the red channel + memcpy(dst + elems, channels[1].data, elems * sizeof(unsigned char)); // green + memcpy(dst + 2 * elems, channels[0].data, elems * sizeof(unsigned char)); // blue + } else { + srcImg = srcImg.t(); + memcpy(dst, srcImg.data, elems * sizeof(unsigned char)); + } +} + + +void imreadOpenCV(const char *imagePath, unsigned char outImg[]) { + std::string imgPath(imagePath); + cv::Mat srcImg = cv::imread(imgPath, cv::IMREAD_COLOR); + if (srcImg.empty()) { + std::runtime_error("read image is empty!"); + } + + convertCVToMatrix(srcImg, srcImg.rows, srcImg.cols, srcImg.channels(), outImg); +} diff --git a/opencvAPI.h b/opencvAPI.h new file mode 100644 index 0000000..0560cdc --- /dev/null +++ b/opencvAPI.h @@ -0,0 +1,22 @@ + +#ifndef _OPENCVAPI_ALLPLATFORM_ +#define _OPENCVAPI_ALLPLATFORM_ + +// base +#include +#include +#include +#include + +// OpenCV +#include +#include +#include + + +// "marshalling" +void convertCVToMatrix(cv::Mat &srcImg, int rows, int cols, int channels, unsigned char dst[]); + +void imreadOpenCV(const char *imagePath, unsigned char outImg[]); + +#endif \ No newline at end of file diff --git a/test_480x640x3.jpg b/test_480x640x3.jpg new file mode 100644 index 0000000..57eeac3 Binary files /dev/null and b/test_480x640x3.jpg differ