在我的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);
答案 0 :(得分:1)
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。
我不相信原始代码中的内存管理也完全正确,但无论如何,只要缓冲区所有权的范围在锁定和解锁方法调用内,上述操作就会起作用。如果图像数据要比这个代码块寿命长,则必须复制缓冲区。
您也要小心像素格式 - 您需要确保Image/Bitmap
实例确实包含RGB8数据。 OpenCV的cv::Mat
有各种标志,因此您可以使用各种内存中的图像格式。但请注意,这些不与磁盘(通常是压缩)格式相同,例如PNG,TIFF等。
答案 1 :(得分:0)
是的,这是从字节数组创建Mat的一种方法。你必须要小心你的数组包含你的想法。
使用一些灰色阴影而不是原始阴影创建图像。
所以你在newImg中获得一张图片?原始数据的像素格式是什么?
也许你已经切换了红色和蓝色通道。以下行将交换频道:
cv::cvtColor(newImg,swappedImg,CV_RGB2BGR);
答案 2 :(得分:0)
以下是docs:http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-mat
的链接一般来说,你应该注意两件事:
我不熟悉C#,但在我看来,您在ProcessImage调用后立即发布数据。因此,如果ProcessImage是异步的或以某种方式缓存您的矩阵(即矩阵的生命周期比ProcessImage调用的更长),那么您应该关心内存管理。