[英]Unity Plugin : Marshal C++ double* to double Array in C#
我正在努力使用Unity和使用C ++ Dll的插件系統。 基本上,我在C ++中有一個Dll,可在知道固有參數的情況下找到相機的外部參數。 創建.exe時,該功能運行平穩。
我想做的是通過C ++中的Dll在Unity中使用該函數來獲取存儲在一維雙數組中的外部參數。
我已經閱讀了很多有關在Dll中導出函數並在C#中導入它們的知識,但是我花了4天的時間,但沒有任何效果。
我總是得到相同的錯誤:運行時錯誤和Unity崩潰(我認為是內存訪問問題)。
這是C ++代碼
#include <opencv2\opencv.hpp>
#include <stdio.h>
#ifdef CALIBRATION_EXPORTS
#define CALIBRATION_API __declspec(dllexport)
#else
#define CALIBRATION_API __declspec(dllimport)
#endif
using namespace cv;
using namespace std;
class CALIBRATION_API calib
{
public:
calib();
virtual ~calib();
void calcBoardCornerPosititions(Size boardSize, double squareSize, vector<Point3f>& corners);
Mat Nextimage(VideoCapture camera);
void find_extrinsic(double* Mat_Ext, double mat_int[], double mat_dist[], int size_ext, int size_int, int size_dist);
private :
VideoCapture camera;
};
extern "C" CALIBRATION_API calib* CreateCalib()
{
return new calib();
}
extern "C" CALIBRATION_API void DisposeCalib( calib* pObject)
{
if (pObject != NULL)
{
delete pObject;
pObject = NULL;
}
}
void calib::find_extrinsic(double *Mat_Ext, double mat_int[], double mat_dist[], int size_ext, int size_int, int size_dist)
{
if (size_ext == 16 && size_int == 9 && size_dist == 5)
{
Size boardSize = Size(9, 6);
double squareSize = 245;
//Matrices de résultats param ext
Mat_<double> rvecs_ext(3, 3);
Mat_<double> tvecs_ext(3, 1);
vector<Point3f> objectPoints_ext;
int id = 0;
Mat_<double> cameraMatrix(3, 3);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cameraMatrix.data[i, j] = mat_int[id];
id++;
}
}
Mat_<double> distCoeffs(5, 1);
for (int i = 0; i < 5; i++)
{
distCoeffs.data[i, 1] = mat_dist[i];
}
Mat result = Nextimage(camera);
Size imageSize = result.size();
vector<Point2f> pointBuf;
bool found = findChessboardCorners(result, boardSize, pointBuf, CALIB_CB_FAST_CHECK + CALIB_CB_FILTER_QUADS);
if (found)
{
calcBoardCornerPosititions(boardSize, squareSize, objectPoints_ext);
solvePnP(objectPoints_ext, pointBuf, cameraMatrix, distCoeffs, rvecs_ext, tvecs_ext, false, CV_ITERATIVE);
Mat_Ext[0] = rvecs_ext.at<double>(0, 0);
Mat_Ext[1] = rvecs_ext.at<double>(0, 1);
Mat_Ext[2] = rvecs_ext.at<double>(0, 2);
Mat_Ext[3] = tvecs_ext.at<double>(0, 0);
Mat_Ext[4] = rvecs_ext.at<double>(1, 0);
Mat_Ext[5] = rvecs_ext.at<double>(1, 1);
Mat_Ext[6] = rvecs_ext.at<double>(1, 2);
Mat_Ext[7] = tvecs_ext.at<double>(0, 2);
Mat_Ext[8] = rvecs_ext.at<double>(2, 0);
Mat_Ext[9] = rvecs_ext.at<double>(2, 1);
Mat_Ext[10] = rvecs_ext.at<double>(2, 2);
Mat_Ext[11] = rvecs_ext.at<double>(0, 3);
Mat_Ext[12] = rvecs_ext.at<double>(3, 0);
Mat_Ext[13] = rvecs_ext.at<double>(3, 1);
Mat_Ext[14] = rvecs_ext.at<double>(3, 2);
Mat_Ext[15] = 1;
}
}
}
}
extern"C" CALIBRATION_API void Call_find_extrinsic(calib* pObject, double *Mat_Ext, double mat_int[], double mat_dist[], int size_ext, int size_int, int size_dist)
{
if (pObject != NULL)
{
pObject->find_extrinsic(Mat_Ext, mat_int, mat_dist,size_ext,size_int,size_dist);
}
}
以及相關的C#代碼:
[DllImport("Beta.dll")]
public static extern IntPtr CreateCalib();
[DllImport("Beta.dll")]
public static extern void DisposeCalib(IntPtr pCalibObject);
[DllImport("Beta.dll")]
public static extern void Call_find_extrinsic(IntPtr pCalibObject, double[] pMat_Ext, double[] mat_int, double[] mat_dist,
int size_ext, int size_int, int size_dist);
pCalibClass = CreateCalib();
double[]test_ext = new double[16];
Call_find_extrinsic(pCalibClass, test_ext,Intrinsic_mat,Dist_mat,test_ext.Length,Intrinsic_mat.Length,Dist_mat.Length);
我嘗試用find_extrinsic方法計算的值填充test_ext。
您能幫我解決這個問題嗎?
非常感謝!
C ++和C#函數的調用約定不匹配,__ cdecl是C和C ++程序的默認調用約定,而__stdcall是默認的(如果您未在[DllImport]屬性中明確指定)。 如果約定不匹配,則會由於堆棧損壞而導致崩潰。
有關詳細信息,請參考此內容。
因此,您應該在[DllImport]聲明中添加CallingConvention = CallingConvention.Cdecl
。
rvecs_ext不應該是3x3矩陣,而是3x1向量。 因此,當您訪問禁止的內存空間時,它會崩潰。
3x1向量是旋轉矩陣的對角線,其他元素視為空值。 為什么呢? 看看這個
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.