C++调用Mtalab接口

发布于:2024-12-07 ⋅ 阅读:(120) ⋅ 点赞:(0)

C++调用Mtalab接口

实现步骤:

1、创建项目,配置环境,加载对应的库和头文件;
     环境搭建可以参考文档:https://blog.csdn.net/m0_63694181/article/details/139148961
2、创建一个类,去初始化库文件;
3、调用matlab接口;

1、接口调用实现

1.1、算法接口

#ifndef Test_h
#define Test_h 1

#if defined(__cplusplus) && !defined(mclmcrrt_h) && defined(__linux__)
#  pragma implementation "mclmcrrt.h"
#endif
#include "mclmcrrt.h"
#include "mclcppclass.h"
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library. 
 */
#ifndef LIB_test_C_API
#define LIB_test_C_API/* No special import/export declaration */
#endif

/* GENERAL LIBRARY FUNCTIONS -- START */

extern LIB_test_C_API
bool MW_CALL_CONV TestInitializeWithHandlers(
       mclOutputHandlerFcn error_handler, 
       mclOutputHandlerFcn print_handler);

extern LIB_test_C_API
bool MW_CALL_CONV TestInitialize(void);

extern LIB_test_C_API
void MW_CALL_CONV TestTerminate(void);

extern LIB_test_C_API
void MW_CALL_CONV TestPrintStackTrace(void);

/* GENERAL LIBRARY FUNCTIONS -- END */

/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */

extern LIB_test_C_API
bool MW_CALL_CONV mlxTest_info_API(int nlhs, mxArray *plhs[], int nrhs, mxArray 
                                         *prhs[]);

/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */

#ifdef __cplusplus
}
#endif

/* C++ INTERFACE -- WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */

#ifdef __cplusplus

/* On Windows, use __declspec to control the exported API */
#if defined(_MSC_VER) || defined(__MINGW64__)

#ifdef EXPORTING_test
#define PUBLIC_test_CPP_API __declspec(dllexport)
#else
#define PUBLIC_test_CPP_API __declspec(dllimport)
#endif

#define LIB_test_CPP_API PUBLIC_test_CPP_API

#else

#if !defined(LIB_test_CPP_API )
#if defined(LIB_test_C_API)
#define LIB_test_CPP_API LIB_test_C_API
#else
#define LIB_test_CPP_API /* empty! */ 
#endif
#endif

#endif

extern LIB_test_CPP_API void MW_CALL_CONV test_info_API(int nargout, mwArray& signal, mwArray& width, mwArray& height, mwArray& dx, mwArray& dy, const mwArray& img, const mwArray& arr, const mwArray& num);

/* C++ INTERFACE -- WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */
#endif

#endif

1.2、接口初始化

创建一个类初始化算法接口

//load_calib.h
#ifndef LOADCALIB_H
#define LOADCALIB_H

#pragma once
#include "atlstr.h"
#include <mclcppclass.h>

typedef  bool(__cdecl* faculaInitialize)(void);//__stdcall

typedef  void(__cdecl* mlxCalc_test_info_API)(int nlhs, mxArray *plhs[], int nrhs, mxArray* prhs[]);


/// <summary>
//nlhs为整数类型,是用户执行name所包含的命令时期望输出的参数的个数,系统规定nlhs不超过50。
//plhs(*)为包含命令name输出参数内存地址的整数类型的数组,其中数组元素plhs(nlhs)包含了name第nlhs个输出参数的内存地址。
//nrhs为整数类型,是用户期望执行的命令name的输入元素的个数,nrhs不超过50。
//prhs(*)为包含命令name输入参数内存地址的整数类型的数组,其中数组元素prhs(nrhs)包含了name第nrhs个输入参数的内存地址。

class LoadCalib
{
public:
	LoadCalib();
	~LoadCalib();
	
private:
	HMODULE m_hDll;
	CString m_strLastErr;  //存放错误信息

public:
	bool Load(CString DLLFileName);//加载DLL,DLLFileName:DLL文件的全路径,ex.D:\SimpleMath.dll

	CString GetLastError(); //返回报错信息
	faculaInitialize _faculaInitialize;
	mlxCalc_test_info_API _calc_test_info_API;
};
#endif // LOADDLL_H
#include "load_calib.h"
LoadCalib::LoadCalib()
{
	_faculaInitialize = NULL;
	_calc_test_info_API = NULL;
	m_hDll = NULL;
	m_strLastErr = "";
}

LoadCalib::~LoadCalib()
{
	if (m_hDll) { FreeLibrary(m_hDll); m_hDll = NULL; }
}

bool LoadCalib::Load(CString DLLFileName)
{
	if (m_hDll) { FreeLibrary(m_hDll); m_hDll = NULL; }
	//加载动态库
	m_hDll = LoadLibraryEx(DLLFileName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
	if (NULL == m_hDll)
	{
		m_strLastErr = "Load DLL Failed: " + DLLFileName;
		return FALSE;
	}

	_faculaInitialize = (faculaInitialize)GetProcAddress(m_hDll, "faculaInitialize");
	if (_faculaInitialize == NULL)
	{
		m_strLastErr = "Can not find[_faculaInitialize]";
		goto EXIT;
	}
	//加载函数接口
	_calc_test_info_API = (mlxCalc_test_info_API)GetProcAddress(m_hDll, "mlxCalc_test_info_API");
	if (_calc_test_info_API == NULL)
	{
		m_strLastErr = "Can not find[_calc_test_info_API]";
		goto EXIT;
	}

	return TRUE;

EXIT:
	if (m_hDll) { FreeLibrary(m_hDll); m_hDll = NULL; }
	return FALSE;
}

CString LoadCalib::GetLastError()
{
	return m_strLastErr;
}

1.3、接口调用

核心代码:在于调用算法接口,如何给其接口传参,以及内存释放的问题

//hdl_calib.h
#pragma once
#include<iostream>
#include<fstream>

#include"load_calib.h"
#include"engine.h" //引擎例程的函数原型
#include"mat.h" //mat 例程的函数原型
#include"matrix.h"  //矩阵访问例程的mxArray结构体和函数原型的定义

#include "opencv2\opencv.hpp"

using namespace std;
using namespace cv;

typedef struct ImgInfo_st
{
	double numw;  //光韵的宽和高
	double numh;
	double dx;
	double dy; //显示光韵中心坐标,相对图像中心而言
	int32_t signal;  //判断函数是否调用成功,1-成功,0-失败
}ImgInfo;

class CHdlCalib
{
public:
	//CHdlCalib(MemManager *memMng);
	CHdlCalib();
	~CHdlCalib();
public:
	bool loadDllMethod(const std::string & dll_path);  //初始化库文件
	void readFile();  //从文件中读取图像数据
	bool calibFocalInfo(uchar *data, uint32_t imgWidth, uint32_t imgHeight); //调用算法接

private:
	std::string m_dll_path = (QCoreApplication::applicationDirPath() + "/test.dll").toUtf8().constData();  //库在项目中的路径

	LoadCalib::Dll_load_Type curr_dlltype;
	LoadCalib currCalibDll;
	bool m_isLoadDll = false;

	ImgInfo m_imgInfo;
};
//hdl_calib.cpp
CHdlCalib::CHdlCalib(){
	loadDllMethod(m_dll_path);
}

CHdlCalib::~CHdlCalib(){}

bool CHdlCalib::loadDllMethod(const std::string & dll_path){
	try{
		if (currCalibDll.Load(dll_path.c_str())){
			///初始化Matla
			if (currCalibDll._faculaInitialize()){
				//dblog_debug(CalibAlgoProcessor, "Matlab init succeed");
				//printf("Matlab init succeed \n");
				m_isLoadDll = true;
				return true;
			}
		}
		m_isLoadDll = false;
		return false;
	}
	catch (...){
		m_isLoadDll = false;
		return false;
	}
}

void CHdlCalib::readFile()
{
	const char* fileName = "E:\\data.dat";  //数据类型为uchar,RGB888
	// 打开二进制文件
	std::ifstream inputFile(fileName, std::ios::binary);
	if (!inputFile) {
		std::cerr << "无法打开文件: " << fileName << std::endl;
		return 1;
	}

	// 获取文件大小
	inputFile.seekg(0, std::ios::end);
	std::streamsize fileSize = inputFile.tellg();
	inputFile.seekg(0, std::ios::beg);

	// 分配足够的内存来存储数据
	m_data = new unsigned char[fileSize];
	inputFile.read(reinterpret_cast<char*>(m_data), fileSize);

	calibFocalInfo(m_data, 1280, 720);//该数据类型为RGB888
}

bool CHdlCalib::calibFocalInfo(uchar *data, uint32_t imgWidth,uint32_t imgHeight)
{
	try{
		if (!m_isLoadDll)  //判断库是否初始化成功
		{
			cout << "matlab init failed!" << endl;
			return false;
		}

     //调用opencv,将数据从CV_8UC3转换为CV_8UC1,将rgb888三通道数据转换为一通道数据
		cv::Mat imgCV_8UC3(imgHeight, imgWidth, CV_8UC3, data);
		cv::Mat imgCV_8UC1;
		cv::cvtColor(imgCV_8UC3, imgCV_8UC1, cv::COLOR_BGR2GRAY);

		//1-0、传入第一个参数,图像数据,二维数组
		mwSize dims[] = { static_cast<mwSize>(imgWidth), static_cast<mwSize>(imgHeight) }; //创建一个mwSize类型的数组,初始化数组大小
		mxArray *mxData = mxCreateNumericArray(2, dims, mxUINT8_CLASS, mxREAL);  //创建一个 mxArray 类型的多维数组对象,存储二维数据数据
		// 获取mxData中存储uchar数据的指针,mxGetUint8s(mxData)
		// 将数据从 sourceData 拷贝到 mxData
		uint8_t* mxDataPtr = static_cast<uint8_t*>(mxGetUint8s(mxData));
		//std::memcpy(mxDataPtr, (uchar*)n_mem->getAddr(), n_mem->m_size);
		std::memcpy(mxDataPtr, imgCV_8UC1.data, imgWidth*imgHeight);
     
     //将读取到的数据保存为png格式,验证读取到的数据和原数据效果是否一致;
     // 使用OpenCV将数据转换为Mat对象,以便显示图像
		/*cv::Mat img(imgCV_8UC1.rows, imgCV_8UC1.cols, CV_8UC1, mxDataPtr);
		cv::imshow("1",image);
		cv::imwrite("1.png", img);
		cv::waitKey(0);
		cv::destroyAllWindows(); */

		// 将mxData数据写入文件保存下来,就用uint8_t格式写入,验证数据是否和原数据一致,保存后用nopade++,二进制格式打开
		/*{
			std::ofstream outFile("output_data.bin", std::ios::binary);
			if (!outFile) {
				std::cerr << "无法打开文件用于写入数据!" << std::endl;
				return false;
			}

			// 计算要写入文件的总字节数,根据mxData的维度信息
			size_t totalBytes = height * width;

			// 将mxData中的数据逐个字节写入文件
			for (size_t i = 0; i < totalBytes; ++i) {
				outFile.put(mxDataPtr[i]);
			}
			outFile.close();
			std::cout << "数据已成功写入文件 output_data.bin!" << std::endl;
		}*/

		//2-0、出入一个一维数组,数组元素有两个,元素类型为double
		double ArrInfo[2];
		ArrInfo[1] = 12.11;
		ArrInfo[0] = 23.1212;
		//2-1、创建内存空间
		mxArray *mxArrNum= mxCreateNumericMatrix(1, 2, mxDOUBLE_CLASS, mxREAL);
		//2-2、创建内存空间 将C++数据复制到MATLAB变量中
		std::memcpy(mxGetDoubles(mxArrNum), ArrInfo, 2 * sizeof(double));

		 获取mxArrNum中存储的double类型数据的指针
		//uint32_t* mxDataPtr2 = mxGetUint32s(mxArrNum);
		 输出mxArrNum中的数据
		//std::cout << "从mxArrNum中获取的数据:" << std::endl;
		//std::cout << "第一个值:" << mxDataPtr2[0] << std::endl;
		//std::cout << "第二个值:" << mxDataPtr2[1] << std::endl;

		//3-0、传入一个double类型的数据值,mm
		double val=12.1123;
		mxArray *mxVal = mxCreateDoubleScalar(val);
		// 打印输出mxVal 的值
		//double value = mxGetScalar(mxVal);
		//std::cout << "pixelTomrad : " << value << std::endl;

		//输入值
		mxArray *mw_MemSet[3]= { mxData,mxArrNum,mxVal};

    //接口输出值,第一个为int类型,其他为double类型,没有找到float处理方法,所以一致采用double
		mxArray* mw_MemRes[5];
		mwSize dims0[1]= {1};  //创建int类型的一维数组,元素个数为1
		mxArray *mxNumInt0 = mxCreateNumericArray(1, dims0, mxINT32_CLASS, mxREAL);  //创建指定值的n维逻辑
		mwSize dims1[1] = {1}; //创建double类型的一维数组,元素个数为1
		mxArray *mxNumInt1 = mxCreateNumericArray(1, dims1, mxDOUBLE_CLASS, mxREAL);
		mwSize dims2[1] = {1};
		mxArray *mxNumInt2 = mxCreateNumericArray(1, dims2, mxDOUBLE_CLASS, mxREAL);
		mwSize dims3[1] = {1};
		mxArray *mxNumInt3 = mxCreateNumericArray(1, dims3, mxDOUBLE_CLASS, mxREAL);
		mwSize dims4[1] = {1};
		mxArray *mxNumInt4= mxCreateNumericArray(1, dims4, mxDOUBLE_CLASS, mxREAL);

    //调用接口,mw_MemRes为接收返回参数,mw_MemSet为传入参数
		currCalibDll._calc_test_info_API(5, mw_MemRes, 3, mw_MemSet);

		m_imgInfo.signal  = static_cast<int32_t>(mxGetScalar(mw_MemRes[0]));
		for (int i = 1; i < 5; i++) {
			if (mw_MemRes[i] != nullptr && mxGetNumberOfElements(mw_MemRes[i]) == 1) {
				switch (i)
				{
				case 1:
					m_imgInfo.numw = mxGetScalar(mw_MemRes[i]);
					break;
				case 2:
					m_imgInfo.numh = mxGetScalar(mw_MemRes[i]);
					break;
				case 3:
					m_imgInfo.dx = mxGetScalar(mw_MemRes[i]);
					break;
				case 4:
					m_imgInfo.dy = mxGetScalar(mw_MemRes[i]);
					break;
				default:
					break;
				}
			}
		}

		//释放发的数据内存
		mxDestroyArray(mxData);
		mxDestroyArray(mxArrNum);
		mxDestroyArray(mxVal);

		// 释放内存,因为我们创建了mxArray,需要释放它们以避免内存泄漏
		for (int i = 0; i < 5; i++) {
			mxDestroyArray(mw_MemRes[i]);
			mw_MemRes[i] = nullptr;
		}
		return true;
	}
	catch (...){}
}