Convert Mat to Array/Vector in OpenCV
If the memory of the Mat mat
is continuous (all its data is continuous), you can directly get its data to a 1D array:
std::vector<uchar> array(mat.rows*mat.cols*mat.channels());
if (mat.isContinuous())
array = mat.data;
Otherwise, you have to get its data row by row, e.g. to a 2D array:
uchar **array = new uchar*[mat.rows];
for (int i=0; i<mat.rows; ++i)
array[i] = new uchar[mat.cols*mat.channels()];
for (int i=0; i<mat.rows; ++i)
array[i] = mat.ptr<uchar>(i);
UPDATE: It will be easier if you're using std::vector
, where you can do like this:
std::vector<uchar> array;
if (mat.isContinuous()) {
// array.assign(mat.datastart, mat.dataend); // <- has problems for sub-matrix like mat = big_mat.row(i)
array.assign(mat.data, mat.data + mat.total()*mat.channels());
} else {
for (int i = 0; i < mat.rows; ++i) {
array.insert(array.end(), mat.ptr<uchar>(i), mat.ptr<uchar>(i)+mat.cols*mat.channels());
}
}
p.s.: For cv::Mat
s of other types, like CV_32F
, you should do like this:
std::vector<float> array;
if (mat.isContinuous()) {
// array.assign((float*)mat.datastart, (float*)mat.dataend); // <- has problems for sub-matrix like mat = big_mat.row(i)
array.assign((float*)mat.data, (float*)mat.data + mat.total()*mat.channels());
} else {
for (int i = 0; i < mat.rows; ++i) {
array.insert(array.end(), mat.ptr<float>(i), mat.ptr<float>(i)+mat.cols*mat.channels());
}
}
UPDATE2: For OpenCV Mat data continuity, it can be summarized as follows:
- Matrices created by
imread()
,clone()
, or a constructor will always be continuous. - The only time a matrix will not be continuous is when it borrows data (except the data borrowed is continuous in the big matrix, e.g. 1. single row; 2. multiple rows with full original width) from an existing matrix (i.e. created out of an ROI of a big mat).
Please check out this code snippet for demonstration.
OpenCV convert Mat Object to array in C++
This will copy the image pixels into a vector. If you need a C like array just use &pixels[0]
.
std::vector<cv::Vec3b> pixels;
cv::MatIterator_<Vec3b> it, end;
for(it = imgHSV .begin<Vec3b>(), end = imgHSV.end<Vec3b>(); it != end; ++it)
{
pixels.push_back(*it);
}
This is a more efficient way to fill the pixels vector:
std::vector<cv::Vec3b> pixels(imgHSV.rows * imgHSV.cols);
cv::Mat m(imgHSV.rows, imgHSV.cols, CV_8UC3, &pixels[0]);
imgHSV.copyTo(m);
How to convert a OpenCV 2D matrix into a 1D array in C++?
Try looping through the matrix using pointer arithmetic. First, we create a random BGR
matrix of size 9
, to test the procedure. The data type stored in the mat
are BGR
pixels represented as cv::Scalar
s:
//Create random test mat:
cv::Mat3b randomMat(3,3);
cv::randu( randomMat, cv::Scalar(0,0,0), cv::Scalar(256,256,256) );
cv::Mat testMat = randomMat;
//Get mat total elements:
int matElements = testMat.cols * testMat.rows;
//Prepare output array:
cv::Scalar matArray[ matElements ];
This is the test matrix:
The raw values will be stored in the matArray
container. Loop through the matrix using pointer arithmetic and store each pixel in the array:
//Loop trhough the mat, insert into array:
cv::MatIterator_<cv::Vec3b> it, end;
int i = 0;
for ( it = testMat.begin<cv::Vec3b>(), end = testMat.end<cv::Vec3b>(); it != end; ++it ) {
//get current bgr pixels:
uchar &r = (*it)[2];
uchar &g = (*it)[1];
uchar &b = (*it)[0];
//Store them into array, as a cv::Scalar:
matArray[i] = cv::Scalar(b,g,r);
i++;
}
We can check the data stored in the array like this:
for ( int i = 0; i < matElements; i++ ){
std::cout<<"i: "<<i<<" - "<<matArray[i]<<std::endl;
}
This yields:
i: 0 - [246, 156, 192, 0]
i: 1 - [7, 165, 166, 0]
i: 2 - [2, 179, 231, 0]
i: 3 - [212, 171, 230, 0]
i: 4 - [93, 138, 123, 0]
i: 5 - [80, 105, 242, 0]
i: 6 - [231, 239, 174, 0]
i: 7 - [174, 176, 191, 0]
i: 8 - [134, 25, 124, 0]
Converting a row of cv::Mat to std::vector
Data in OpenCV matrices is laid out in row-major order, so that each row is guaranteed to be contiguous. That means that you can interpret the data in a row as a plain C array. The following example comes directly from the documentation:
// compute sum of positive matrix elements
// (assuming that M is double-precision matrix)
double sum=0;
for(int i = 0; i < M.rows; i++)
{
const double* Mi = M.ptr<double>(i);
for(int j = 0; j < M.cols; j++)
sum += std::max(Mi[j], 0.);
}
Therefore the most efficient way is to pass the plain pointer to std::vector
:
// Pointer to the i-th row
const double* p = mat.ptr<double>(i);
// Copy data to a vector. Note that (p + mat.cols) points to the
// end of the row.
std::vector<double> vec(p, p + mat.cols);
This is certainly faster than using the iterators returned by begin()
and end()
, since those involve extra computation to support gaps between rows.
incorrect size of vector when converting Mat to Vector
You have 4 times the expected number of elements in your vector because your matrix is of type CV_32FC1
. If you look at the type of m.datastart
and m.dataend
you will see that they are uchar*
and not float*
as you expect.
To correct this, change v.assign(m.datastart, m.dataend);
to v.assign((float*)m.datastart, (float*)m.dataend);
. And you will need to pass a vector of float instead of a vector<uchar>
.
Of course, your conversion function will only work for float type matrices. you could add some tests to detect the type of the matrix inside the function.
To answer your follow up question, it appears that you have the inverse problem. You are passing a CV_8U
type matrix to a function that expects a CV_32F
type one. Use your old conversion function for 8-bit matrices and use the fix I suggested for 32-bit floating-values matrices. You can also add a test inside the conversion function to automatically choose the right conversion. I also advise you to read a bit on OpenCV Mat class to understand better what type of data is in your matrices.
Related Topics
How to Read the Results of a System() Call in C++
How Can My C/C++ Application Determine If the Root User Is Executing the Command
Single Process Maximum Possible Memory in X64 Linux
Lightweight Memory Leak Debugging on Linux
How to Increase Thread Priority in Pthreads
Iterating Over a Struct in C++
Altering Dll Search Path for Static Linked Dll
How to Compare Multiple Strings Inside an If Statement
When Do We Have to Use Copy Constructors
When G++ Static Link Pthread, Cause Segmentation Fault, Why
Is Passing a C++ Object into Its Own Constructor Legal
How Is the Size of a C++ Class Determined
May I Take the Address of the One-Past-The-End Element of an Array
C++ Auto Keyword. Why Is It Magic
Extract Year/Month/Day etc. from Std::Chrono::Time_Point in C++
Why Isn't 'Int Pow(Int Base, Int Exponent)' in the Standard C++ Libraries