Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opencv in memory Mat representation

Tags:

c++

opencv

I know that in memory opencv represents Mat objects as one big array. So if I have 3 channels mat of dimension 200x200 then In memory it will store this mat in an array of size 3x200x200. Or more generally any Mat in memory will be stored as channels*rows*cols. We can get such array as

double *array = (double)mat.data;

assuming that matrix is of type double

Now my question is what is the way to index this array for instance if I want to access element at channel ch, row r and col c is following is valid indexing

array[ch*rows*cols + c * rows + r]

or

array[ch*rows*cols + r * cols + c]

Regards Ahsan

like image 388
Ahsan Iqbal Avatar asked May 05 '16 01:05

Ahsan Iqbal


People also ask

How is an OpenCV image stored in memory?

OpenCV has been around since 2001. In those days the library was built around a C interface and to store the image in the memory they used a C structure called IplImage. This is the one you'll see in most of the older tutorials and educational materials.

What is use of mat class in OpenCV?

The Mat class of OpenCV library is used to store the values of an image. It represents an n-dimensional array and is used to store image data of grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms, etc.

What is Vec3b OpenCV?

Vec3b is the abbreviation for "vector with 3 byte entries" Here those byte entries are unsigned char values to represent values between 0 .. 255. Each byte typically represents the intensity of a single color channel, so on default, Vec3b is a single RGB (or better BGR) pixel.

What is CV_8U?

CV_8U is unsigned 8bit/pixel - ie a pixel can have values 0-255, this is the normal range for most image and video formats.


3 Answers

As you can see in the data layout reported on the documentation, you can access the values like:

for(int r=0; r<rows; ++r){
    for(int c=0; c<cols; ++c){
        for(int ch=0; ch<nchannels; ++ch){
            double val = array[(nchannels*mat.step*r) + (nchannels*c) + ch];
        }
    }
}
like image 140
Miki Avatar answered Oct 23 '22 01:10

Miki


You can get values in array like this:

double val = array+ (r*mat.step)+c*mat.channels()+ch;
like image 1
IvoLiu Avatar answered Oct 23 '22 00:10

IvoLiu


I found other answers a bit confusing: mat.step is the size of a row in bytes, not in (double) elements, and it does already take into consideration the number of channels. To access val you should use:

double* array = (double*) mat.data; // was (double) mat.data in the question
double value = array[ ((mat.step)/mat.elemSize1())*c+mat.channels()*r+ch]; // (mat.step)/mat.elemSize1() is the actual row length in (double) elements

You can verify this and other approaches comparing them with the .at<> operator as follows:

#include <iostream>
#include <opencv2/core.hpp>

using namespace cv;
using namespace std;

int main()
{
const int w0=5;
const int h=3;
const int w=4;
double data[w0*h*3];
for (int y=0; y<h; y++)
    for (int x=0; x<w0; x++)
        for (int ch=0; ch<3; ch++)
            data[3*(x+w0*y)+ch]=1000+100*(y)+10*(x)+ch;

Mat m0(h,w0,CV_64FC3, data);
Rect roi(0,0,w,h);
Mat mat=m0(roi);

int c=3, r=2, ch=1;
Vec3d v = mat.at<Vec3d>(r,c);
cout<<"the 3 channels at row="<<r<<", col="<<c<<": "<<v<<endl;
double* array= (double*) mat.data;
double expect = 1000+100*r+10*c+ch;
double value= array[ ((mat.step)/mat.elemSize1())*r+mat.channels()*c+ch];
cout<<"row="<<r<<", col="<<c<<", ch="<<ch<<": expect="<<expect<<", value="<<value<<endl;
return  0;
}
like image 1
Gianni Avatar answered Oct 23 '22 00:10

Gianni