如何从c ++ dll正确传递多个cv :: Mat到opencvsharp Mat c#?

问题描述 投票:0回答:1

我正在研究一个项目,该项目需要dll文件才能使用c#编写的另一个程序使用(我对C ++ / C#的用法不是很熟悉)。对于完成我的工作的最后一步,我在将“多个” cv :: Mat从dll传递到C#时遇到了问题。

我在Internet上找到了一些有关C#的示例,这些示例使用OpenCvSharp从dll接收cv :: Mat,并且它在我的代码中工作得很好,这很简单]:

//original.hpp
extern "C" LIB_API cv::Mat* inference(unsigned char* img_pointer, long data_len);


//original.cpp
LIB_API cv::Mat* inference(unsigned char* img_pointer, long data_len)
{
    cv::Mat A;
    ..... // process that update A
    return new cv::Mat(A);
}

//original.cs
[DllImport(@"D:\Coco\Code\C_plus_plus\cpp_dll\x64\Release\cpp_dll.dll")]
private static extern IntPtr inference(byte[] img, long data_len);

static void Main()
{
    Intptr res = inference(X, Y);
    Mat A1 = new Mat(res);
    Cv2.ImShow("test1", A1);
    Cv2.WaitKey(2000);
}

由于成功运行,我计划使用相同的语法,并通过带有函数的参数传递结果,以便我可以根据需要返回多个cv :: Mat,但是此代码不起作用...] >

//rv1.hpp
extern "C" LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat* res);

//rv1.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat *res)
{
    cv::Mat A;
    ..... // process that update A
    res = new cv::Mat(A);
}

//rv1.cs
[DllImport(@"D:\Coco\Code\C_plus_plus\cpp_dll\x64\Release\cpp_dll.dll")]
private static extern void inference(byte[] img, long data_len, out IntPtr res);

static void Main()
{
    Intptr res;
    inference(X, Y, out res);
    Mat A1 = new Mat(res);
    Cv2.ImShow("test1", A1);
    Cv2.WaitKey(2000);
}

我以为是因为我对cv :: Mat *的分配错误,所以它没有得到正确的地址,所以我修改了rv1.cpp的部分,但该代码也不起作用...

// rv1_1.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat *res)
{
    cv::Mat A;
    ..... // process that update A
    res = &A;
}

(错误为System.AccessViolationException:尝试读取或写入受保护的内存

)] >>

然后我想出了另一种方法,将函数的参数传递给cv :: Mat *向量

,而代码类似于:
//rv2.hpp
extern "C" LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat ***data_1, long* len);

// rv2.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat ***data_1, long* len)
{
    std::vector<cv::Mat*> vec_mat;
    cv::Mat A;
    cv::Mat B;
    ..... // process that update A, B
    vec_mat.push_back(new cv::Mat(A));
    vec_mat.push_back(new cv::Mat(B));

    *len = vec_mat.size();
    auto size = (*len) * sizeof(cv::Mat*);
    *data_1 = static_cast<cv::Mat**>(CoTaskMemAlloc(size));
    memcpy(*data_1, vec_mat.data(), size);
}

//rv2.cs
[DllImport(@"D:\Coco\Code\C_plus_plus\cpp_dll\x64\Release\cpp_dll.dll")]
private static extern void inference(byte[] img, long data_len, out IntPtr[] data, out int len);

static void Main()
{
    IntPtr[] sss1;
    int itemsCount;
    inference(image_byte_array, ms.Length, out sss1, out itemsCount);
    for (int i = 0; i < itemsCount; i++) // index out of range (the length of ss1 is "1")
    {
       Mat A3 = new Mat(sss1[i]);
       Cv2.ImShow("test3", A3);
       Cv2.WaitKey(2000);
    }
}

事实是,我希望返回的向量中应该有2个项目,但事实证明只有一个项目。

((当我循环遍历IntPtr []时,它只会得到1个项目,然后停止,并出现诸如“索引超出范围”之类的错误)

我知道我的代码中必须有一些语法错误

,但我不知道它们在哪里以及如何纠正它们...

(而且似乎有些使用指针的非常基本的语法问题...

]

由于上述方法仍然可以获取向量的“第一”项,因此我目前可以通过这种方式传递“多个” cv :: Mat *:

((实际上是愚蠢的,不适合这样的代码...)

//rv3.hpp
extern "C" LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*** data_1, cv::Mat ***data_2);

// rv3.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat ***data_1, cv::Mat ***data_2)
{
    std::vector<cv::Mat*> vec_mat1;
    std::vector<cv::Mat*> vec_mat2;

    cv::Mat A;
    cv::Mat B;
    ..... // process that update A, B
    vec_mat1.push_back(new cv::Mat(A));
    vec_mat2.push_back(new cv::Mat(B));

    auto size = (*len) * sizeof(cv::Mat*);
    *data_1 = static_cast<cv::Mat**>(CoTaskMemAlloc(size));
    *data_2 = static_cast<cv::Mat**>(CoTaskMemAlloc(size));
    memcpy(*data_1, vec_mat1.data(), size);
    memcpy(*data_2, vec_mat2.data(), size);

}

//rv3.cs
[DllImport(@"D:\Coco\Code\C_plus_plus\cpp_dll\x64\Release\cpp_dll.dll")]
private static extern void inference(byte[] img, long data_len, out IntPtr[] data_1, out IntPtr[] data_2);

static void Main()
{
    IntPtr[] sss1, sss2;
    int itemsCount;
    inference(image_byte_array, ms.Length, out sss1, out sss2);

    Mat A3 = new Mat(sss1[0]);
    Cv2.ImShow("test3", A3);
    Cv2.WaitKey(2000);

    Mat A4 = new Mat(sss2[0]);
    Cv2.ImShow("test4", A4);
    Cv2.WaitKey(2000);
}

如上所述,我认为这不是将多个cv :: Mat *从dll传递到C#的正确方法。

我认为应该是:

  1. 通过多个cv :: Mat *

带有函数的参数
  • 通过其中有多个cv :: Mat *的向量具有函数的参数

    [每个中没有多个cv :: Mat *的多个向量

  • 但是我真的不知道如何正确修改代码,因此,任何建议或帮助都非常感谢...

    (感谢您阅读我凌乱的问题描述!)>

    我正在研究一个项目,该项目需要dll文件才能使用c#编写的另一个程序使用(我对C ++ / C#的用法不是很熟悉)。对于完成工作的最后一步,我有一个...

    由于您已经返回了指向cv::Mat的指针,因此也可以使其成为动态数组。

    LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size)
    {
        img_count = 10;
        mat_type_size = sizeof(cv::Mat);
        res = new cv::Mat[img_count]
    
        for (int i = 0; i < img_count; i++)
        {
            // process each mat 
            cv::Mat& A = res[0];
        }
    }
    

    请注意

    • cv::Mat*& res现在是对指针的引用。仅将指针传递不起作用,因为您只是将指针重新分配给了新地址。
  • [int& img_count也是参考,因此您可以将分配给C#的实际图像数返回。
  • int& mat_type_size仅表示cv::Mat对象的字节数。这对于正确地递增C#IntPtr指向数组中的下一个图像是必要的。

    在您的C#代码中,您应该能够像这样导入它(我对编组的知识是有限的:]

  • [DllImport(@"D:\Coco\Code\C_plus_plus\cpp_dll\x64\Release\cpp_dll.dll")]
    private static extern void inference(byte[] img, long data_len, ref IntPtr images, ref int img_count, ref int mat_type_size);
    

    并像这样使用它:

    static void Main()
    {
        IntPtr imgPtrs;
        int imgCount, matTypeSize;
        inference(image_byte_array, ms.Length, ref imgPtrs, ref imgCount, ref matTypeSize);
    
        List<Mat> images;
    
        for (int i = 0; i < imgCount; i++)    
            images.Add(new Mat(IntPtr.Add(imgPtrs, i * matTypeSize)));    
    
        // ...
    }
    

    我对C#有点生疏,对编组不太熟悉,因此代码可能不是100%正确。

    c# c++ opencv dll opencvsharp
    1个回答
    0
    投票

    由于您已经返回了指向cv::Mat的指针,因此也可以使其成为动态数组。

    LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size)
    {
        img_count = 10;
        mat_type_size = sizeof(cv::Mat);
        res = new cv::Mat[img_count]
    
        for (int i = 0; i < img_count; i++)
        {
            // process each mat 
            cv::Mat& A = res[0];
        }
    }
    
    © www.soinside.com 2019 - 2024. All rights reserved.