weixin_39877581
weixin_39877581
2021-01-07 11:48

how to convert cv::Mat from C++ opencv to Mat for C# opencvsharp?

I want to Convert Mat object from  C++  opencv  to C# opencvsharp.but I don't how to do .

C++/opencv-------Mat------------>DLL------->C#/opencvsharp---------->Mat.

At first,I Wrote one DLL for C++ as following:

//C++ DLL -----unmanaged

TSO.h

c++
extern "C"
{
    __declspec(dllexport)  Mat WINAPI GetImage(char* filename);//The Mat object is C++ object from opencv
}

TSO.cpp

c++
__declspec(dllexport)  Mat WINAPI GetImage(char* filename)
{
    return imread(filename);
}

then I quote this dll in C# ,As the same time I quote opencvsharp

c#
[DllImport("TSO.dll", EntryPoint = "GetImage")]
 public extern static Mat GetImage(string filename);//Mat is from opencvsharp

finally ,I did like this

c#
Mat img=GetImage(@"D:\1.jpg");//C#object form opencvsharp
            pictureBoxIpl1.ImageIpl = img;//pictureBoxIpl1  is control of opencvsharp

but it doesn't work,So how to convert?

该提问来源于开源项目:shimat/opencvsharp

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

6条回答

  • weixin_39613291 weixin_39613291 3月前

    Your native function should return not Mat but Mat*. C++

    c++
    __declspec(dllexport) Mat* WINAPI GetImage(char* filename)
    {
        Mat m = imread(filename);
        return new Mat(m);
    }
    

    C#

    c#
    [DllImport("TSO.dll", EntryPoint = "GetImage")]
    public extern static IntPtr GetImage(string filename);
    
    c#
    IntPtr matPtr = GetImage("1.jpg");
    Mat mat = new Mat(matPtr);
    

    The OpenCV version referenced by both your native library and the OpenCvSharp library must be the same. I do not recommend this way, because it is often annoying with complicated and obscure errors.

    点赞 评论 复制链接分享
  • weixin_39877581 weixin_39877581 3月前

    think you for your help.I make it

    点赞 评论 复制链接分享
  • weixin_39801714 weixin_39801714 3月前

    it doesn't work 👎

    点赞 评论 复制链接分享
  • weixin_39581571 weixin_39581571 3月前

    Hi :) I am trying to find the way to pass a Mat and multiple Mats from C++ dll to C#. I agree with your opinion 'I do not recommend this way, because it is often annoying with complicated and obscure errors.'. I would like to know another way. Do you have an idea about this?

    点赞 评论 复制链接分享
  • weixin_39613291 weixin_39613291 3月前

    :thinking: If your Mat's Type is 8UC1 or 8UC3, encoding it into an image such as BMP or PNG is one way to do it. If it's any other type, then copying the pixel values might be a good way.

    c++
    __declspec(dllexport) std::vector<uchar>* __cdecl vector_uchar_new()
    {
        return std::vector<uchar>;
    }
    __declspec(dllexport) void __cdecl vector_uchar_delete(std::vector<uchar>* vec)
    {
        delete vec;
    }
    __declspec(dllexport) void __cdecl vector_uchar_getPointerAndLength(std::vector<uchar>* vec, uchar** ptr, int* length)
    {
        *ptr = &vec[0];
        *length = static_cast<int>(vec->size());
    }
    
    __declspec(dllexport) void __cdecl SomeFunction(char* filename, std::vector<uchar> *outVec)
    {
        cv::Mat m = cv::imread(filename);
        cv::imencode(m, ".png", *outVec);
    }
    </uchar></int></uchar></uchar></uchar></uchar>
    c#
    [DllImport("MyNative.dll", CallingConvention = CallingConvention.Cdecl)]
    public extern static IntPtr vector_uchar_new();
    [DllImport("MyNative.dll", CallingConvention = CallingConvention.Cdecl)]
    public extern static void vector_uchar_delete(IntPtr vec);
    [DllImport("MyNative.dll", CallingConvention = CallingConvention.Cdecl)]
    public extern static void vector_uchar_getPointerAndLength(IntPtr vec, out IntPtr ptr, out int length);
    
    [DllImport("MyNative.dll", CallingConvention = CallingConvention.Cdecl)]
    public extern static void SomeFunction(string fileName, IntPtr outVec);
    
    c#
    IntPtr vec = vector_uchar_new();
    try
    {
        SomeFunction("image.jpg", vec);
        vector_uchar_getPointerAndLength(vec, out IntPtr ptr, out int length);
    
        byte[] pngImageBytes = new byte[length];
        Marshal.Copy(ptr, pngImageBytes , 0, length);
    
        using var mat = OpenCvSharp.Mat.FromImageData(pngImageBytes);
    }
    finally
    {
        vector_uchar_delete(vec);
    }
    

    However, if you are using C++ in the first place, I would suggest that you don't use OpenCvSharp and write all image processing consistently in C++.

    点赞 评论 复制链接分享
  • weixin_39801714 weixin_39801714 3月前

    You can use just one function for passing Mat object between two languages.

    C++ Function

    cpp
    //for conversion from c++ to cs
    //this variable must be delete after using
    std::vector<uchar>* vec = new std::vector<uchar>;
    void convertMat2CS(cv::Mat income_mat, uchar** ptr, int* length)
    {
        cv::imencode(".png", income_mat, *vec);
        *ptr = &vec[0][0];
        *length = static_cast<int>(vec->size());
    }
    
    </int></uchar></uchar>

    C# Side

    cs
    
    [DllImport(dll)]
    public static extern void convertMat2CS(out IntPtr ptr, out int len);
    
    void Main(){
        convertMat2CS(out IntPtr ptr, out int length);
        byte[] pngImageBytes = new byte[length];    
        Marshal.Copy(ptr, pngImageBytes, 0, length);
        Mat mat = new Mat();
        CvInvoke.Imdecode(pngImageBytes, LoadImageType.AnyColor, mat);
        CvInvoke.Imshow("Test_" + showCount, mat);
        CvInvoke.WaitKey(1);
    
    }
    
    
    点赞 评论 复制链接分享

为你推荐