EmguCV - Mat.Data array is always null after image loading - opencv

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?

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.

Related

OpenCV: accessing pixel intensity values of type 8UC4

Anyone knows which method is needed to be invoked to access the RGB value of a picture of the type 8UC4 (8 bits per component, 4 channels (color channels + alpha)
You may use mat.at(i, j), to access the pixel located at i row and j column, But at() must be used with data type of Mat, which is passed as a template type. OpenCV won't throw any error if you use wrong data type, instead it would return some garbage, so you need to take care of that thing, single channel matrix pixels can be accessed as mat.at<uchar>(i, j), mat.at<float>(i, j).
For multi-channel matrices, you need to use cv::Vec3b, cv::Vec3f, cv::Vec4b, etc.
In your case, since it is a 4-channel uchar matrix, its pixel values can be accessed as:
cv::Vec4b pixVal = mat.at<cv::Vec4b>(0, 0);

iOS Loading 16bit Single Channel Image

I have a 16bit grayscale image. I have tried both .png and .tif. .tif works somewhat. I have the following code:
CGDataProviderRef l_Img_Data_Provider = CGDataProviderCreateWithFilename( [m_Name cStringUsingEncoding:NSASCIIStringEncoding] );
CGImageRef l_CGImageRef = CGImageCreate( m_Width, m_Height, 16, 16, m_Width * 2,
CGColorSpaceCreateDeviceGray(), kCGBitmapByteOrder16Big, l_Img_Data_Provider, NULL, false, kCGRenderingIntentDefault );
test_Image = [[UIImage alloc] initWithCGImage:l_CGImageRef];
[_test_Image_View setImage:test_Image];
This results in the following image:
faulty gradient
As you can see, there seems to be an issue at the beginning of the image ( could it be trying to use the byte data from the header? ), and the image is offset by about a fifth ( a little harder to see, look at the left and the right, there is a faint line about a fifth away from the right.
My goal is to convert this to a metal texture and use it from there. Also having issues there. Seem like a byte order issue but maybe we can come back to that.
dave
CGDataProvider doesn't know about the format of the data that it stores. It is just meant for handling generic data:
"The CGDataProvider header file declares a data type that supplies
Quartz functions with data. Data provider objects abstract the
data-access task and eliminate the need for applications to manage
data through a raw memory buffer."
CGDataProvider
Because CGDataProvider is generic you must provide the format of the image data using the CGImageCreate parameters. PNGs and JPGs have their own CGImageCreateWith.. functions for handling encoded data.
The CGImage parameters in your example correctly describe a 16 bit grayscale raw byte format but nothing about TIF encoding so I would guess you are correct in guessing that the corrupted pixels you are see are from the file headers.
There may be other ways to load a 16 bit grayscale image on iOS, but to use that method (or the very similar Metal method) you would need to parse the image bytes from the TIF file and pass that into the function, or create another way to store and parse the image data.

Efficient matrix copying in OpenCV

I have no idea for how to implement matrix implementation efficiently in OpenCV.
I have binary Mat nz(150,600) with 0 and 1 elements.
I have Mat mk(150,600) with double values.
I like to implement as in Matlab as
sk = mk(nz);
That command copy mk to sk only for those element of mk element at the location where nz has 1. Then make sk into a row matrix.
How can I implement it in OpenCV efficiently for speed and memory?
You should take a look at Mat::copyTo and Mat::clone.
copyTo will make an copy with optional mask where its non-zero elements indicate which matrix elements need to be copied.
mk.copyTo(sk, nz);
And if you really want a row matrix then call sk.reshape() as member sansuiso already suggested. This method ...
creates alternative matrix header for the same data, with different
number of channels and/or different number of rows.
bkausbk gave the best answer. However, a second way around:
A=bitwise_and(nz,mk);
If you access A, you can copy the non-zero into a std::vector. If you want your output to be a cv::Mat instance then you have to allocate the memory first:
S=countNonZero(A); //size of the final output matrix
Now, fast element access is an actual topic of itself. Google it. Or have a look at opencv/modules/core/src/stat.cpp where countNonZero() is implemented to get some ideas.
There are two steps involved in your task.
First, you convert to double the input matrix:
cv::Mat binaryMat; // source matrix, filled somewhere
cv::Mat doubleMat; // target matrix (with doubles)
binaryMat.convertTo(doubleMat, CV64F); // Perform the conversion
Then, reshape the result as a row matrix:
doubleMat = cv::reshape(doubleMat, 1, 1);
// Alternatively:
cv::Mat doubleRow = cv::reshape(doubleMat, 1, 1);
The cv::reshape operation is efficient in the sense that the data is not copied, only the structure header changes.
This function returns a new reference to a matrix (by creating a new header), thus you should not forget to assign its result.

What is the best way to use the OpenCV library in conjunction with the Armadillo library?

I am building an image processing application using OpenCV. I am also using the Armadillo library because it has some very neat matrix related functions. The thing is though, in order to use Armadillo functions on cv::Mat I need frequent conversions from cv::Mat to arma::Mat .
To accomplish this I convert the cv::Mat to an arma::Mat using a function like this
arma::Mat cvMat2armaMat(cv::Mat M)
{
copy cv::Mat data to a arma::Mat
return arma::Mat
}
Is there a more efficient way of doing this?
To avoid or reduce copying, you can access the memory used by Armadillo matrices via the .memptr() member function. For example:
mat X(5,6);
double* mem = X.memptr();
Be careful when using the above, as you're not allowed to free the memory yourself (Armadillo will still manage the memory).
Alternatively, you can construct an Armadillo matrix directly from existing memory. For example:
double* data = new double[4*5];
// ... fill data ...
mat X(data, 4, 5, false); // 'false' indicates that no copying is to be done; see docs
In this case you will be responsible for manually managing the memory.
Also bear in mind that Armadillo stores and accesses matrices in column-major order, ie. column 0 is first stored, then column 1, column 2, etc. This is the same as used by MATLAB, LAPACK and BLAS.

Storing a Cv::Mat's data in a std::vector

I want to copy the data from a cv::Mat to an std::vector. I could obviously go through the entire Mat and copy each value one by one, but I was hoping that there might be an easier way using copyTo, clone, or some sort of pointer manipulation.
Does anyone have any insight on this problem?
Thanks
Assuming your Mat is CV_8UC1, you can do following.
cv::Mat mat(nrows,ncols,CV_8UC1);
...
std::vector<unsigned char> vec;
vec.assign(mat.data,mat.data+nrows*ncols);
For multiple channel image with different pixel type, I think you will be able to easily generalize the code above.
Here is what worked for myself. I had Mat matVec2f of size Nx1, type Vec2f, and a vector of size N. The following code copies the Mat's data to the vector. I believe this should work equally well for data types other than Vec2f.
int N = 10;
vector<Point2f> vec(N);
matVec2f.copyTo(Mat(vec, false));

Resources