简体   繁体   English

Unity插件:元帅C ++ double *将C#中的数组翻倍

[英]Unity Plugin : Marshal C++ double* to double Array in C#

I'm struggling with Unity and the plugin system using a C++ Dll. 我正在努力使用Unity和使用C ++ Dll的插件系统。 Basically I have a Dll in C++ that find the extrinsic parameters of camera knowing the intrinsic parameters. 基本上,我在C ++中有一个Dll,可在知道固有参数的情况下找到相机的外部参数。 The function runs smoothly when I create a .exe. 创建.exe时,该功能运行平稳。

What i'm trying to do is using that function in Unity via a Dll in C++ to get the extrinsic parameters stored in a 1D double Array. 我想做的是通过C ++中的Dll在Unity中使用该函数来获取存储在一维双数组中的外部参数。

I've read a lot about exporting functions in Dll and Importing them in C#, but I've spend 4 days of work and nothing works. 我已经阅读了很多有关在Dll中导出函数并在C#中导入它们的知识,但是我花了4天的时间,但没有任何效果。

I always get the same error : Runtime Error and Unity crashes (Memory access problem I think). 我总是得到相同的错误:运行时错误和Unity崩溃(我认为是内存访问问题)。

Here is the C++ code 这是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);
}
}

And the revelant C# code: 以及相关的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);

I try to fill the test_ext with the value calculated by the find_extrinsic method. 我尝试用find_extrinsic方法计算的值填充test_ext。

Could you plz help me to solve that. 您能帮我解决这个问题吗?

Thanks a Lot! 非常感谢!

The calling conventions of the C++ and C# functions are not matched, __cdecl is the default calling convention for C and C++ programs, while __stdcall is the default if you don't specify it explicitly in the [DllImport] attribute. C ++和C#函数的调用约定不匹配,__ cdecl是C和C ++程序的默认调用约定,而__stdcall是默认的(如果您未在[DllImport]属性中明确指定)。 If the conventions are not matched, it leads to crash because of stack damage. 如果约定不匹配,则会由于堆栈损坏而导致崩溃。

Please refer this for details. 有关详细信息,请参考内容。

So you should add CallingConvention = CallingConvention.Cdecl in the [DllImport] declaration. 因此,您应该在[DllImport]声明中添加CallingConvention = CallingConvention.Cdecl

rvecs_ext is not supposed to be a 3x3 matrix, instead it is a 3x1 vector. rvecs_ext不应该是3x3矩阵,而是3x1向量。 hence it crashes as you are accessing forbidden memory space. 因此,当您访问禁止的内存空间时,它会崩溃。

The 3x1 vector is the diagonal of the rotation matrix, other elements are considered as null. 3x1向量是旋转矩阵的对角线,其他元素视为空值。 why ? 为什么呢? take a look at this 看看这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM