简体   繁体   English

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

[英]Problem with getting OpenCV image data to C#

So I'm fairly new to C++, and I tried to use it to read images using the OpenCV library.所以我对 C++ 还很陌生,我尝试使用 OpenCV 库来读取图像。 My idea was to put the C++ code in a DLL and then get the decoded image by calling the DLL from a C# script (I need the image in C#). My idea was to put the C++ code in a DLL and then get the decoded image by calling the DLL from a C# script (I need the image in C#).

I looked arround a bit on what would be the best way to send the bytes to C#, and saw that most people were using a char* to store bytes.我仔细研究了将字节发送到 C# 的最佳方式,发现大多数人都使用char*来存储字节。 That could then be returned by a C++ function and stored as a C# string like so:然后可以由 C++ function 返回并存储为 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;
}

and then in C#:然后在 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);
}

And this even worked, but now I had to get the raw data from the Mat to a char* .这甚至奏效了,但现在我必须将原始数据从Mat获取到char* I was quite sure I had to use the Mat.data field, but that contained a unsinged char* .我很确定我必须使用Mat.data字段,但它包含一个unsinged char* There were several ways in which I tried this conversion:我尝试了这种转换的几种方法:

  • Using a simple cast (like (char*)my_mat.data )使用简单的演员表(如(char*)my_mat.data
  • Using reinterpret_cast (like reinterpret_cast<char*>(my_mat.data) ), which some people said would be better for C++使用 reinterpret_cast (如reinterpret_cast<char*>(my_mat.data) ),有人说这对于 C++ 会更好
  • Using memcpy like:使用 memcpy 像:
int size = my_mat.total() * my_mat.elemSize();
char* bytes = new char[size];
memcpy(bytes, my_mat.data, size);

So here's my problem: When I used my_mat.total() * my_mat.elemSize() on a full-hd image, it returned 6220804 , what makes sense to me (because 1920 * 1080 = 2073600 , so the image has 2.073.600 pixels, and 2073600 * 3 = 6220804 , the image has 3 color channels, and so it takes a total of 6.220.804 bytes to store it).所以这是我的问题:当我在全高清图像上使用my_mat.total() * my_mat.elemSize()时,它返回6220804 ,这对我来说很有意义(因为1920 * 1080 = 2073600 ,所以图像有 2.073.600像素,并且2073600 * 3 = 6220804 ,图像有 3 个颜色通道,因此总共需要 6.220.804 字节来存储它)。

However, after the conversion to a char* , with every one of the three methods above, strlen(the_converted_bytes) was something completely different with every image I tried, ranging from about 2.000 all the way up to about 11.000.000.但是,在转换为char*之后,对于上述三种方法中的每一种, strlen(the_converted_bytes)与我尝试的每张图像都完全不同,范围从大约 2.000 一直到大约 11.000.000。 bytes.Length in C# returned the same value though, so I don't think the error is in the C++-char* to C#-bytes process. bytes.Length中的 bytes.Length 返回相同的值,但我认为错误不在 C++-char* 到 C#-bytes 的过程中。 I tried different charsets in both the DllImport and the Encoding.GetBytes anyway, but that didn't seem to help.无论如何,我在DllImportEncoding.GetBytes中都尝试了不同的字符集,但这似乎没有帮助。

So I think there is something wrong with my understanding of char and unsigned char or with pointers.所以我认为我对charunsigned char或指针的理解有问题。 Or both.或两者。 Anyway, it really seems to me that it should be possible to convert the data of a C++ Mat to a C# byte[] .无论如何,在我看来,应该可以将 C++ Mat的数据转换为 C# byte[] Isn't it possible to convert between a unsinged char* and a char* as easily as I thought, or have I overlooked something completely different (maybe there's something wrong with my use of my_mat.data )?是不是可以像我想象的那样轻松地在unsinged char*char*之间进行转换,或者我忽略了一些完全不同的东西(也许我对my_mat.data的使用有问题)?

I would apreciate any help我会感谢任何帮助

Ok, nevermind, turns out it actually makes more sense to just return the unsigned char* from the C++ function and then convert it in C#.好吧,没关系,事实证明只从 C++ function 返回unsigned char*然后将其转换为 C# 实际上更有意义。 If anyone else has problems with this, here 's the thread I found this answer on (Thanks to Louis.fr ).如果其他人对此有疑问, 是我在上面找到这个答案的线程(感谢Louis.fr )。

Here are the methods I ended up using:以下是我最终使用的方法:

In C++:在 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;
}

and in C# ( using System and using System.Runtime.InteropServices ):并在 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);
}

Glad it was this simple after all.很高兴毕竟这么简单。 Louis.fr also wrote that you could just pass a pointer, but as far as I understand using these pointers in C# would require unsave code (compiling with /unsave or something like that). Louis.fr还写道,您可以只传递一个指针,但据我了解,在 C# 中使用这些指针需要取消保存代码(使用/unsave或类似的东西编译)。 So I think I'm going to stick with this method, as long as I don't stumble into further problems with it in the future.所以我想我会坚持使用这种方法,只要我将来不会遇到更多问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM