日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

Matlab与C/C++混合编程 (基于Opencv库)

發布時間:2024/4/18 c/c++ 65 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Matlab与C/C++混合编程 (基于Opencv库) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前用過基于VS2018 與MATLAB2018a 混合編程(C++特性)(見https://blog.csdn.net/wwwoowww/article/details/83013801),奈何后來matlab版本換成了2016a,混合編程的方式不一樣了,自己嘗試了幾天,終于搞定了。

目錄

版本選擇

matlab與c++的混合編程有兩個方法:

利用mex的方法

創建C++動態庫


版本選擇

版本: Win10 ,VS2015, Matlab2016a

注意:Matlab2016支持的VS版本有兼容問題,matlab具體支持哪些VS版本請見matlab的安裝文件夾路徑:C:\Program Files\MATLAB\R2016a\bin\win64\mexopts 中包含了哪些編譯器。如下圖所示,我的文件夾中包含了vs2015,說明該版本的matlab支持vs2015的編譯器。

若想要支持的vs版本文件夾中沒有,需要自己去下載對應版本的文件。詳細的內容請見或自己找找吧,我是放棄了:https://blog.csdn.net/cztqwan/article/details/78902530

?

matlab與c++的混合編程有兩個方法:

mex 和調用C++動態庫

?

利用mex的方法

若是不在c/c++中使用其他第三方庫,可以使用簡單的編譯方法。

  • ?matlab中使用mex -setup 命令,選擇c++ 的編譯器 (第一次可以使用mex setup -v?,先查找所有的已安裝并且支持的編譯器)
    • 創建test.cpp 文件, 文件輸出 傳入的第一個參數和參數的個數

    matlab官方文檔,對于mexFunction的解釋:https://ww2.mathworks.cn/help/matlab/apiref/mexfunction.html

    簡單來說,mexFunction是matlab調用C/C++的入口,類似main函數,

    nlhs 輸出的個數, plhs matlab的array類型,是輸出參數的地址

    nrhs 輸入數組的個數, prhs matlab的array類型,包含了輸入參數地址

  • #include "mex.h" //matlab的頭文件 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {if(nrhs < 1){mexPrintf("Use example: test(12)");return;}//如果prhs的類型是double,打印一下語句。類似的函數有mxIsInt等等//if(mxIsDouble(prhs[0]))// mexPrintf("Type of input arg is double\n");double *data = mxGetPr(prhs[0]); // 獲取傳入值的地址,不管傳入的類型是什么,該方法的獲得的都必須為double*int mrows, ncols;mrows = mxGetM(prhs[0]); //獲取行的大小ncols = mxGetN(prhs[0]); //獲取列的大小mexPrintf("value:%f,rows:%d, cols: %d\n",*data, mrows, ncols);}
    • matlab中使用命令 mex **.cpp。編譯成功后使用文件名調用

    • 若要使用第三方庫,需要創建make.m文件(但是我自己按網上的嘗試,沒有鏈接成功,放棄了)
    %// This make.m is for MATLAB %// Function: compile c++ files which rely on OpenCV for Matlab using mex %// Author : zouxy %// Date : 2014-03-05 %// HomePage : http://blog.csdn.net/zouxy09 %// Email : zouxy09@qq.com%% Please modify your path of OpenCV %% If your have any question, please contact Zou Xiaoyi% Notice: first use "mex -setup" to choose your c/c++ compiler clear all; %------------------------------------------------------------------- %% get the architecture of this computer is_64bit = strcmp(computer,'MACI64') || strcmp(computer,'GLNXA64') || strcmp(computer,'PCWIN64'); %-------------------------------------------------------------------%% the configuration of compiler % You need to modify this configuration according to your own path of OpenCV % Notice: if your system is 64bit, your OpenCV must be 64bit!out_dir='./'; CPPFLAGS = ' -O -I.\ -ID:\OpenCV\build2015\install\include'; % your OpenCV "include" path LDFLAGS = ' -LD:\OpenCV\build2015\install\x64\vc14\lib'; % your OpenCV "lib" path LIBS = ' -lopencv_world346d'; if is_64bit CPPFLAGS = [CPPFLAGS ' -largeArrayDims']; end%% add your files here! compile_files = { % the list of your code files which need to be compiled 'RGB2Gray.cpp' };%------------------------------------------------------------------- %% compiling... for k = 1 : length(compile_files) str = compile_files{k}; fprintf('compilation of: %s\n', str); str = [str ' -outdir ' out_dir CPPFLAGS LDFLAGS LIBS]; args = regexp(str, '\s+', 'split'); mex(args{:}); end fprintf('Congratulations, compilation successful!!!\n');

    ?

    創建C++動態庫

    上面我們使用了matlab中的vs2015編譯器,鑒于我之前的混合編程經驗(C++,vs2018,matlab2019,見https://blog.csdn.net/wwwoowww/article/details/83013801),我在嘗試使用mex鏈接第三方庫不成功后,想在vs中生成dll文件,再改后綴為.mexw64 。開干

    1. 新建Win32 控制臺應用程序

    2. 配置項目的屬性

    需要配置的地方有四點:

    2.1.注意選擇平臺為x64(因為我自己編譯的opencv版本是64位的)

    2.2.常規 -》 配置類型改為 .dll

    2.3.VC++目錄-》 2.3.1包含目錄:添加opencv的include, 添加matlab安裝目錄下的/extern/include目錄

    ? ? ? ? ? ? ? ? ? ? ? ? 2.3.2 庫目錄:添加opencv的 x64\vc14\lib(這是我自己編譯的基于vs2015的opencv庫), 添加matlab安裝目錄下的\extern\lib\win64\microsoft目錄

    2.4.連接器-》輸入-》 附件依賴項 中 添加:

    ? ? ? ? ? opencv_world346d.lib (我在opencv編譯的時候選擇了生成world庫,該庫將opencv所有的功能集合成一個文件。所以不用想一些博客中要包含n多個opencv_****.dll )
    ? ? ? ? ? ? ? ? ? ? ? ?libmat.lib ? (以下都是matlab的庫文件)
    ? ? ? ? ? ? ? ? ? ? ? ?libmx.lib
    ? ? ? ? ? ? ? ? ? ? ? ?libmex.lib
    ? ? ? ? ? ? ? ? ? ? ? ?libeng.lib

    3 創建 ***.def 文件?

    文件內容:

    LIBRARY detect_mark.DLLEXPORTSmexFunction


    ?

    4 創建源文件

    功能:matlab傳入一個圖像矩陣,c++識別圖像是否有aruco mark,并返回mark的id,和中心位置

    提醒下, opencv的aruco頭文件很可能找不到,因為該庫在opencv_contrib包中,需要自己在編譯opencv的時候加上這個額外的包

    具體的詳情見:https://blog.csdn.net/ezhchai/article/details/80557936

    #include "stdafx.h" #include "opencv2/opencv.hpp" #include "opencv2/aruco.hpp" #include <iostream> #include "mex.h" using namespace std; using namespace cv;void exit_with_help() {mexPrintf("Usage: [id, x, y] = detect_mark(img_data);\n"); }/**檢查圖像中的mark,并返回mark的id和中心點坐標 */ void detect_marks(cv::Mat& image, vector<Vec3d>&center) {Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();Ptr<aruco::Dictionary> dictionary =aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(1));vector< int > ids;vector< vector< Point2f > > corners, rejected;vector< Vec3d > rvecs, tvecs;// detect markers and estimate pose/*markerCorners 是檢測出的圖像的角的列表。對于每個marker,將返回按照原始順序排列的四個角(從左上角順時針開始)。因此,第一個點是左上角的角,緊接著右上角、右下角和左下角。markerIds 是在markerCorners檢測出的所有maker的id列表.注意返回的markerCorners和markerIds 向量具有相同的大小。*/aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);//獲取中心點坐標for (int i = 0; i < ids.size(); i++) {double x = (corners[i][0].x + corners[i][2].x) / 2;double y = (corners[i][0].y + corners[i][2].y) / 2;center.push_back(Vec3d(ids[i], x, y));//cout << "id: " << ids[i] << " ;center: " << x << "," << y << endl;}return ; }static void fake_answer(mxArray *plhs[]){plhs[0] = mxCreateDoubleMatrix(0, 0, mxREAL); }void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {if (nrhs == 1){//獲取傳入數據的指針,類型只能為double*double *data = mxGetPr(prhs[0]);//將傳入的圖像數據類型強轉為uint8_t來解釋,因為我們傳入的是圖像矩陣,圖像在matlab中是uint8類型uint8_t *i_data = (uint8_t*) data;int mrows, ncols;mrows = mxGetM(prhs[0]); //行數,,matlab按照uint8來計算的個數ncols = mxGetN(prhs[0]); //列數mexPrintf("m = %d, n = %d", mrows, ncols);/**創建Opencv格式下的圖像數據matlab和opencv的圖像格式不一樣。matlab是三個通道(RGB)分成了三張圖片的保存,每一張圖片的數據類型都是uint8。所以需要轉換。但是如果是一個通道的灰度圖,不需要轉換opencv是三個通道同時保存,只有一張圖片,每個圖片的值為(BGR)[uint8,uint8,uint8]matlab和opencv的圖像通道排列方式不一樣,MATLAB中RGB,OPENCV BGR*///獲取灰度圖,只采了matlab圖像中的R通道數據Mat img_gray = Mat(mrows, ncols / 3, CV_8UC1);for (int i = 0; i<mrows; i++) {for (int j = 0; j < ncols/3; j++) {*(img_gray.data + img_gray.step[0] * i + img_gray.step[1] * j) = (uchar)i_data[j*mrows + i];}}/**// 獲取彩色圖Mat img_col = Mat(mrows, ncols / 3, CV_8UC3);for (int i = 0; i<mrows; i++) {for (int j = 0; j < ncols; j++) {//改變通道,matlab和opencv的圖像通道排列方式不一樣,MATLAB中RGB,OPENCV BGR,寫的真難看,不忍直視。。。。int chan = j / (ncols / 3);int n;if (chan == 0)n = 2;else if (chan == 2)n = 0;else n = 1;*(img_col.data + img_col.step[0] * i + img_col.step[1] * (j % (ncols / 3)) + img_col.elemSize1()* n) = (uchar)i_data[j*mrows + i];}}*/vector<Vec3d> center;detect_marks(img_gray, center);if (center.size() == 0) {plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);double *resultMat = mxGetPr(plhs[0]);*resultMat = -1;return;}int rows = center.size();int cols = 3;//創建返回給matlab的數據plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);//獲取指針double *resultMat = mxGetPr(plhs[0]);//賦值for (int i = 0; i < rows; i++)for (int j = 0; j < cols; j++)*(resultMat + i + j * rows) = (double)center.at(i)[j];//imwrite("out_file_color.png", img_col);}else{exit_with_help();fake_answer(plhs);return;} }

    說明下Matlab的圖像存儲方式:

    matlab文檔:https://ww2.mathworks.cn/help/matlab/matlab_external/matlab-data.html

    原圖是500*312*3的彩色圖(不可否認,我媳婦兒很漂亮)

    matlab讀入上圖并傳入到C/C++圖像的格式是1500*312*1的二維矩陣,排列方式如下,從左到右分別是R、G、B通道的值。

    ?

    5. 生成.dll文件

    最后使用 控制界面 生成-》生成解決方案

    把生成的.dll 文件后綴改為 .mexw64?

    使用matlab調用就可以了

    ?

    附 我的結果:

    傳入圖像:

    總結

    以上是生活随笔為你收集整理的Matlab与C/C++混合编程 (基于Opencv库)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。