我正在研究一个项目,该项目需要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#的正确方法。
我认为应该是:
通过多个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%正确。