Я работаю над проектом, который требует использования файла dll для другой программы, написанной на c # (я не очень знаком с использованием C ++ / C #). Для самого последнего шага, чтобы завершить мою работу, у меня есть проблема с передачей «множественного» cv :: Mat из dll в C #.
В Интернете я нашел несколько примеров о C #, использующих OpenCvSharp для полученияcv :: Mat из dll, и в моем коде это работает хорошо (это упрощено):
//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 #.
По моему мнению, он должен выглядеть следующим образом:
pass множественное cv :: Mat * с параметрами функции
pass авектор кратного cv :: Mat * в нем с параметрами функции
( Не несколько векторов только одного cv :: Mat * в каждом )
Но я действительно не знаю, как правильно пересмотреть код, поэтому любые советы или помощь действительно приветствуются ...
(Заранее благодарен за то, что дочитал моё грязное описание вопроса! )