Reputation: 6497
What is the fastest way to convert a C++ array into an 2D opencv Mat object?
Brute force method would be to loop over all entries of the 2D mat and fill them with values of the array.
Is there a better / faster way to do that?
Could I somehow just give pointer of the array to the 2D matrix?
(I'm using opencv 2.4.8)
Upvotes: 15
Views: 50466
Reputation: 11420
Yes there is, in the documentation of cv::Mat
you can see how it can be achieved.
Specifically in this line
C++: Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
This means that you can do something like
double x[100][100];
cv::Mat A(100, 100, CV_64F, x);
This will not copy the data to it. You have to also remember that OpenCV data is row major, which means that it has all the columns of one rows and then the next row and so on. So your array has to match this style for it to work.
About how fast it is, the documentation also talks about it:
data – Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it.
It will work quite fast, but it is the same array, if you modified it outside of the cv::Mat
, it will be modified in the cv::Mat
, and if it is destroyed at any point, the data
member of cv::Mat
will point to a non-existant place.
UPDATE:
I forgot to also say, that you can create the cv::Mat
and do std::memcpy
. This way it will copy the data, which may be slower, but the data will be owned by the cv::Mat
object and destroyed upon with the cv::Mat
destroyer.
double x[100][100];
cv::Mat A(100,100,CV_64F);
std::memcpy(A.data, x, 100*100*sizeof(double));
Upvotes: 36
Reputation: 15121
#include <opencv2/opencv.hpp>
int main()
{
// First row contains 3 white pixels
// Second row contains 3 black pixels
uchar temp[2][3] = {{255, 255, 255}, {0, 0, 0}};
cv::Mat mat = cv::Mat(2, 3, CV_8UC1);
// The first element of temp decays to int* data.
// It means that mat.data tracks temp.
mat.data = temp[0];
// Change the upper left pixel to black from temp,
// the change affects mat.
temp[0][0] = uchar(0);
cv::namedWindow("title", cv::WINDOW_NORMAL);
cv::imshow("title", mat);
cv::waitKey();
return 0;
}
Upvotes: 1