Reputation: 1246
In OpenCV, is there a fast way to create a Mat
object where:
For example :
1 0 1 0 1 0
1 0 1 0 1 0
1 0 1 0 1 0
The pattern is always the same.
The size of Mat
can be big, and process by looping is really slow to generate this pattern.
Upvotes: 3
Views: 1356
Reputation: 41776
OpenCV repeat is there exactly for this.
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
int rows = 1000;
int cols = 1000;
vector<uchar> pattern = { 1, 0 }; // change with int, double, etc according to the type you want.
Mat m;
repeat(pattern, rows, cols/2, m);
return 0;
}
COMPARISON WITH OTHER METHODS
Just a small test to measure the performance of the proposed (so far) methods:
Time in milliseconds:
@Miki [repeat] : 0.442786
@RonaldoMessi [copyTo] : 7.26822
@Derman [merge] : 1.17588
The code I used for the test:
#include <opencv2\opencv.hpp>
#include <vector>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
int rows = 1000;
int cols = 1000;
{
// @Miki
double tic = (double)getTickCount();
vector<uchar> pattern = { 1, 0 };
Mat m1;
repeat(pattern, rows, cols / 2, m1);
double toc = ((double)getTickCount() - tic) * 1000 / getTickFrequency();
cout << "@Miki [repeat] \t\t: " << toc << endl;
}
{
// @RonaldoMessi
double tic = (double)getTickCount();
Mat m2(rows, cols, CV_8UC1);
Mat vZeros = Mat::zeros(rows, 1, CV_8UC1);
Mat vOnes = Mat::ones(rows, 1, CV_8UC1);
for (int i = 0; i < cols - 1; i += 2)
{
vOnes.col(0).copyTo(m2.col(i));
vZeros.col(0).copyTo(m2.col(i + 1));
}
double toc = ((double)getTickCount() - tic) * 1000 / getTickFrequency();
cout << "@RonaldoMessi [copyTo] \t: " << toc << endl;
}
{
// @Derman
// NOTE: corrected to give correct output
double tic = (double)getTickCount();
Mat myMat[2];
myMat[0] = cv::Mat::ones(rows, cols/2, CV_8UC1);
myMat[1] = cv::Mat::zeros(rows, cols/2, CV_8UC1);
Mat m3;
merge(myMat, 2, m3);
m3 = m3.reshape(1);
double toc = ((double)getTickCount() - tic) * 1000 / getTickFrequency();
cout << "@Derman [merge] \t: " << toc << endl;
}
getchar();
return 0;
}
Upvotes: 10
Reputation:
If two-channel matrix won't bother you, this could be your choice:
int rows = 5;
int cols = 5;
cv::Mat myMat[2];
myMat[0] = cv::Mat::ones(rows, cols, CV_32FC1);
myMat[1] = cv::Mat::zeros(rows, cols, CV_32FC1);
cv::Mat result;
cv::merge(myMat, 2, result);
And this is your result:
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0;
1, 0, 1, 0, 1, 0, 1, 0, 1, 0;
1, 0, 1, 0, 1, 0, 1, 0, 1, 0;
1, 0, 1, 0, 1, 0, 1, 0, 1, 0;
1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
Upvotes: 1
Reputation: 7929
You can create two column vectors vZeros and vOnes, then copy these columns to the matrix M:
int cols = A.cols;
int rows = A.rows;
Mat vZeros = Mat::zeros(rows , 1, CV_64F);
Mat vOnes = Mat::ones(rows , 1, CV_64F);
for(int i=0; i<cols-1; i+=2)
{
vOnes.col( 0 ).copyTo( M.col(i) );
vZeros.col( 0 ).copyTo( M.col(i+1) );
}
Upvotes: 1