2016-09-07 230 views
3

当我试图从文件读取图像时,加载后Mat.Data数组一直为空。但是当我在调试过程中查看Mat对象时,有一个字节数组,其中包含来自图像的所有数据。EmguCV - Mat.Data数组在加载图像后始终为空

Mat image1 = CvInvoke.Imread("minion.bmp", Emgu.CV.CvEnum.LoadImageType.AnyDepth); 

你知道为什么吗?

回答

0

我认识到这个问题是超级老,但我碰到同样的问题,我怀疑答案在于Emgu wiki。具体做法是:

访问像素从垫

不同于图像<,>类,其中存储器是预分配的和固定的,垫的存储器可以自动打开CV函数调用重新分配。我们不能>预先分配托管内存,并假定在Mat对象的整个生命周期中都使用相同的内存。因此,Mat类不包含像Image <>类的Data>属性,其中可以通过托管数组访问像素。要访问Mat的数据,有几种可能的选择。 简单的方法和安全的方式,花费额外的内存副本

第一个选项是使用Mat.ToImage函数将Mat复制到图像<,>对象。例如

Image<Bgr, Byte> img = mat.ToImage<Bgr, Byte>();

像素数据然后可以使用Image <,>。数据属性来访问。

您也可以将垫子转换为矩阵<>对象。假设垫包含8位数据,

Matrix<Byte> matrix = new Matrix<Byte>(mat.Rows, mat.Cols, mat.NumberOfChannels); 
mat.CopyTo(matrix); 

请注意,应具有匹配型的垫对象创建矩阵<>。如果Mat包含32位浮点值,则应使用Matrix替换上述代码中的Matrix。然后可以使用Matrix <> .Data属性访问像素数据。 无需内存拷贝的最快方式。要小心!

第二个选项有点棘手,但会提供最佳性能。这通常会要求您在创建Mat对象之前了解其大小。因此,您可以分配托管数据阵列,并通过强制它使用固定托管内存来创建Mat对象。例如

//load your 3 channel bgr image here 
Mat m1 = ...; 

//3 channel bgr image data, if it is single channel, the size should be m1.Width * m1.Height 

byte[] data = new byte[m1.Width * m1.Height * 3];` 
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);` 
using (Mat m2 = new Mat(m1.Size, DepthType.Cv8U, 3, handle.AddrOfPinnedObject(), m1.Width * 3))` 
    CvInvoke.BitwiseNot(m1, m2);` 
handle.Free(); 

此时数据数组包含倒置图像的像素数据。请注意,如果Mat m2分配的大小错误,data []数组将包含全0,并且不会抛出异常。所以在执行上述操作时要非常小心。

TL; DR:您无法以您希望的方式使用数据对象(至少从版本3.2开始)。您必须将其复制到允许使用Data对象的另一个对象。