0

I'm struggling with Unity and the plugin system using a C++ Dll. Basically I have a Dll in C++ that find the extrinsic parameters of camera knowing the intrinsic parameters. The function runs smoothly when I create a .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.

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.

I always get the same error : Runtime Error and Unity crashes (Memory access problem I think).

Here is the C++ code

#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:

[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.

Could you plz help me to solve that.

Thanks a Lot!

2 Answers 2

1

rvecs_ext is not supposed to be a 3x3 matrix, instead it is a 3x1 vector. 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. why ? take a look at this

Sign up to request clarification or add additional context in comments.

1 Comment

In fact, you were right... I didn't pay attention to that detail, I was focusing on the C++/C# thing...
0

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. 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.