gpt4 book ai didi

c# - OpenCV 从字节数组创建 Mat

转载 作者:可可西里 更新时间:2023-11-01 15:28:01 24 4
gpt4 key购买 nike

在我的 C++ dll 中,我从字节数组创建 Mat:

BYTE * ptrImageData;  //Image data is in this array passed to this function

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData);

创建的图像带有一些灰色阴影,而不是原始图像。

这是从字节数组创建 Mat 的正确方法吗?

请看代码

ptrImageData 从 C# 代码传递到 C++ dll。

传递图像数据的C#代码

System.Drawing.Image srcImage //Has the image
MemoryStream ms = new MemoryStream();
Marshal.FreeHGlobal(ptrImageData);
srcImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] imgArray = ms.ToArray();
ms.Dispose();


int size1 = Marshal.SizeOf(imgArray[0]) * imgArray.Length;
IntPtr ptrImageData = Marshal.AllocHGlobal(size1);
Marshal.Copy(imgArray, 0, ptrImageData, imgArray.Length);

//Calling C++ dll function
ProcessImage(ptrImageData, srcImage.Width, srcImage.Height);

Marshal.FreeHGlobal(ptrImageData);

最佳答案

C++ 代码看起来不错,因为它为提供的图像数据创建了一个矩阵包装,假设缓冲区是传统的 RGB8 格式。请注意,此构造函数不会复制缓冲区,因此缓冲区必须在此Mat 实例(或被复制)期间保持有效。

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData);

看来问题出在您的 C# 代码中。我不是 C# 开发人员,但我会尽力提供帮助。您正在创建一个内存流并使用 JPEG 编解码器将图像的压缩版本写入缓冲区,就好像它是一个文件一样。但这不是 cv::Mat 所期望的数据格式,因此您基本上会看到垃圾(压缩数据被解释为未压缩)。

给定一个 System.Image.Drawing.Image 实例,您可以直接创建一个包装器 Bitmap 对象(或者可以使用 as,因为这是一个简单的沮丧)。然后你可以只使用 Bitmap.LockBits()方法获取指向底层图像数据的指针。

Bitmap bmp = new Bitmap(sourceImage);

// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);

// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;

// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbBuffer = new byte[bytes];

// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbBuffer, 0, bytes);

// Do your OpenCV processing...
// ...

// Unlock the bits.
bmp.UnlockBits(bmpData);

然后您可以将 rgbBuffer 传递给 OpenCV。

我也不相信原始代码中的内存管理是完全正确的,但无论如何,只要缓冲区所有权的范围在 lock 和 unlock 方法调用范围内,上述内容就可以工作。如果图像数据的生命周期超过此代码块,则必须复制缓冲区。

也要小心您的像素格式 - 您需要确保 Image/Bitmap 实例确实包含 RGB8 数据。 OpenCV 的 cv::Mat 具有各种标志,因此您可以使用各种内存图像格式。但请注意,这些与磁盘上的(通常是压缩的)格式相同,例如 PNG、TIFF 等。

关于c# - OpenCV 从字节数组创建 Mat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13599395/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com