Warm tip: This article is reproduced from serverfault.com, please click

c++-将OpenCV图像数据获取到C#时出现问题

(c++ - Problem with getting OpenCV image data to C#)

发布于 2020-12-02 19:45:49

因此,我对C ++还是相当陌生,我尝试使用它通过OpenCV库读取图像。我的想法是将C ++代码放入DLL,然后通过从C#脚本调用DLL来获取解码的图像(我需要C#中的图像)。

我仔细研究了将字节发送到C#的最佳方法,发现大多数人都使用achar*来存储字节。然后可以由C ++函数返回并存储为C#,string如下所示:

char* GetSomeBytes()
{
    // Got this method of allocating memory from the internet, sadly can't remember from were
    // (I get memory errors if I pass my_bytes directly)

    size_t stSize = strlen(my_bytes) + sizeof(char);
    char* pszReturn = NULL;

    pszReturn = (char*)::CoTaskMemAlloc(stSize);
    strcpy_s(pszReturn, stSize, my_bytes);
    return pszReturn;
}

然后在C#中:

[DllImport(path_to_my_dll, EntryPoint = "GetSomeBytes", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern string GetSomeBytes();

static void Main(string[] args)
{
    string raw_bytes = GetSomeBytes();

    byte[] bytes = Encoding.ASCII.GetBytes(raw);
}

甚至还可以,但是现在我不得不将原始数据从Mat传送到char*我非常确定我必须使用该Mat.data字段,但是其中包含一个unsinged char*我尝试了几种转换方式:

  • 使用简单的类型转换(如(char*)my_mat.data
  • 使用reinterpret_cast(如reinterpret_cast<char*>(my_mat.data)),有人说这对于C ++会更好
  • 使用memcpy像:
int size = my_mat.total() * my_mat.elemSize();
char* bytes = new char[size];
memcpy(bytes, my_mat.data, size);

所以这是我的问题:当我my_mat.total() * my_mat.elemSize()在全高清图像上使用时,它返回了6220804,这对我来说很有意义(因为1920 * 1080 = 2073600,所以该图像具有2.073.600像素,并且2073600 * 3 = 6220804,该图像具有3个颜色通道,因此总共需要6.220.804字节来存储它)。

但是,在char*使用上述三种方法中的每一种转换为a之后strlen(the_converted_bytes)我尝试的每张图像都完全不同,从大约2.000一直到大约11.000.000。bytes.Length虽然在C#中返回了相同的值,所以我认为错误不在C ++-char *到C#字节的过程中。我想在两种不同的字符集DllImportEncoding.GetBytes反正,但似乎并没有帮助。

所以我觉得有什么不对我的理解charunsigned char或指针。或两者。无论如何,在我看来,实际上似乎应该可以将C ++的数据转换Mat为C#byte[]难道无法像我想unsinged char*char*那样在a和a之间轻松转换,还是我忽略了完全不同的东西(也许我使用时有问题my_mat.data)?

我会很感激

Questioner
Wanja
Viewed
1
Wanja 2020-12-04 01:45:12

好的,没关系,事实证明,unsigned char*仅从C ++函数返回,然后将其转换为C#实际上更有意义如果其他人对此有疑问,请在这里找到我在(谢谢Louis.fr上找到此答案的线程

这是我最终使用的方法:

在C ++中:

unsigned char* GetUnsignedBytes(char* image, int* bytes_count)
{
    Mat img = imread(image);

    int size = img.total() * img.elemSize();
    unsigned char* raw_bytes = new unsigned char[size];

    memcpy(raw_bytes, img.data, size * sizeof(std::byte));
    
    *bytes_count = size;
    return raw_bytes;
}

并在C#(using Systemusing System.Runtime.InteropServices)中:

[DllImport(path_to_my_dll)]
public static extern IntPtr GetUnsignedBytes(string image, out int bytes_count);

static void Main(string[] args)
{
    IntPtr ptr = GetUnsignedBytes(some_image, out int bytes_count);

    byte[] bytes = new byte[bytes_count];
    Marshal.Copy(ptr, bytes, 0, bytes_count);
}

很高兴这就是这么简单。Louis.fr还写道,你可以只传递一个指针,但据我了解,在C#中使用这些指针将需要未保存的代码(使用/unsave或类似的代码进行编译)。因此,我认为我会坚持使用这种方法,只要我将来不会偶然遇到进一步的问题。