Reputation: 34017
I'd like to assign each pixel of a mat matA
to some value according to values of matB
, my code is a nested for-loop:
clock_t begint=clock();
for(size_t i=0; i<depthImg.rows; i++){
for(size_t j=0; j<depthImg.cols; j++){
datatype px=depthImg.at<datatype>(i, j);
if(px==0)
depthImg.at<datatype>(i, j)=lastDepthImg.at<datatype>(i, j);
}
}
cout<<"~~~~~~~~time: "<<clock()-begint<<endl;
and it costs about 40~70ms for a mat of size 640*480.
I could do this easily in python numpy using fancy indexing:
In [18]: b=np.vstack((np.ones(3), np.arange(3)))
In [19]: b
Out[19]:
array([[ 1., 1., 1.],
[ 0., 1., 2.]])
In [22]: a=np.vstack((np.arange(3), np.zeros(3)))
In [23]: a=np.tile(a, (320, 160))
In [24]: a.shape
Out[24]: (640, 480)
In [25]: b=np.tile(b, (320, 160))
In [26]: %timeit a[a==0]=b[a==0]
100 loops, best of 3: 2.81 ms per loop
and this is much faster than my hand writing for-loop.
So is there such operation in opencv c++ api?
Upvotes: 4
Views: 836
Reputation: 11329
I am unable to replicate your timing results on my machine Your C++ code runs in under 1ms on my machine. However, whenever you have slow iteration, at<>()
should be immediately suspect. OpenCV has a tutorial on iterating through images, which I recommend.
However, for the operation you describe, there is a better way. Mat::copyTo()
allows masked operations:
lastDepthImg.copyTo(depthImg, depthImg == 0);
This is both faster (about 2x as fast) and far more readable than your nested-loop solution. In addition, it may benefit from hardware optimizations like SSE.
Upvotes: 4
Reputation: 67427
In your C++ code, at every pixel you are making a function call, and passing in two indices which are getting converted into a flat index doing something like i*depthImageCols + j
.
My C++ skills are mostly lacking, but using this as a template, I guess you could try something like, which should get rid of most of that overhead:
MatIterator_<datatype> it1 = depthImg.begin<datatype>(),
it1_end = depthImg.end<datatype>();
MatConstIterator_<datatype> it2 = lastDepthImg.begin<datatype>();
for(; it1 != it1_end; ++it1, ++it2) {
if (*it1 == 0) {
*it1 = *it2;
}
}
Upvotes: 1