5

When I am trying to read image from file, then after load Mat.Data array is alway null. But when I am looking into Mat object during debug there is byte array in which are all data from image.

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

Do you have any idea why?

eridanix
  • 818
  • 1
  • 8
  • 27

1 Answers1

0

I recognize this question is super old, but I hit the same issue and I suspect the answer lies in the Emgu wiki. Specifically:

Accessing the pixels from Mat

Unlike the Image<,> class, where memory are pre-allocated and fixed, the memory of Mat can be automatically re-allocated by Open CV function calls. We cannot > pre-allocate managed memory and assume the same memory are used through the life time of the Mat object. As a result, Mat class do not contains a Data > property like the Image<,> class, where the pixels can be access through a managed array. To access the data of the Mat, there are a few possible choices. The easy way and safe way that cost an additional memory copy

The first option is to copy the Mat to an Image<,> object using the Mat.ToImage function. e.g.

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

The pixel data can then be accessed using the Image<,>.Data property.

You can also convert the Mat to an Matrix<> object. Assuming the Mat contains 8-bit data,

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

Note that you should create Matrix<> with a matching type to the Mat object. If the Mat contains 32-bit floating point value, you should replace Matrix in the above code with Matrix. The pixel data can then be accessed using the Matrix<>.Data property. The fastest way with no memory copy required. Be caution!!!

The second option is a little bit tricky, but will provide the best performance. This will usually require you to know the size of the Mat object before it is created. So you can allocate managed data array, and create the Mat object by forcing it to use the pinned managed memory. e.g.

//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();

At this point the data array contains the pixel data of the inverted image. Note that if the Mat m2 was allocated with the wrong size, data[] array will contains all 0s, and no exception will be thrown. So be really careful when performing the above operations.

TL;DR: You can't use the Data object in the way you're hoping to (as of version 3.2 at least). You must copy it to another object which allows use of the Data object.

Randomh3r0
  • 103
  • 2
  • 6