OpenCV掩膜操作,C++中的逐元素赋值
我想给一个叫 matA
的图像中的每个像素赋值,这个值是根据另一个图像 matB
的值来决定的。我写的代码是一个嵌套的for循环:
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;
这样做大约需要40到70毫秒,处理的图像大小是640*480。
在Python的numpy库中,我可以用一种更简单的方法来实现这个功能,叫做花式索引:
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
这样做的速度比我手动写的for循环快得多。
那么在opencv的C++接口中,有没有类似的操作呢?
2 个回答
1
在你的C++代码中,每处理一个像素,你都在调用一个函数,并传入两个索引,这两个索引会被转换成一个平面索引,像这样 i*depthImageCols + j
。
我的C++技能不太好,但参考这个,我想你可以尝试一些方法,这样可以减少大部分的开销:
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;
}
}
4
我在我的电脑上无法复现你的时间结果。你的C++代码在我这儿运行不到1毫秒。不过,每当你遇到慢的循环时,at<>()
这个函数就应该引起注意。OpenCV有一个关于如何遍历图像的教程,我推荐你去看看。
不过,对于你描述的操作,有更好的方法。Mat::copyTo()
可以进行带掩码的操作:
lastDepthImg.copyTo(depthImg, depthImg == 0);
这种方法不仅更快(大约快2倍),而且比你用嵌套循环的方案更容易理解。此外,它还可能利用一些硬件优化,比如SSE。