我正在实时处理视频帧。我一次循环一个像素,做一些数学运算,然后将像素设置为特定颜色(如果需要)。
简而言之,我的算法如下所示:
//videoFrame is IplImage, 8 bit, 4 channel
for(int i=0;i<videoFrame.width;i++){
for(int j=0;j<videoFrame.height;j++){
CvScalar pixel = cvGet2D(&videoFrame, i, j);
double red = pixel.val[0];
double green = pixel.val[1];
double blue = pixel.val[2];
//do some math
if (someCondition) {
cvSet2D(&videoFrame, i, j, white);
}
}
}
但是我发现调用cvGet2D(&videoFrame, i, j);
和cvSet2D(&videoFrame, i, j, white);
非常昂贵(慢)。是否有更快的方法可以访问每个像素的红/绿/蓝值?
谢谢!
答案 0 :(得分:2)
尝试使用指针直接访问数据,如下所示。
for(int i=0;i<videoFrame.width;i++){
for(int j=0;j<videoFrame.height;j++){
uchar B =((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 0];
uchar G =((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 1];
uchar R =((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 2];
//do some math
((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 0] = B;
((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 1] = G;
((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 2] = R;
}
}
答案 1 :(得分:2)
这里提供的答案
Etarion(用于新界面,使用Mat)和Andrew(用于IplImage,就像你的情况一样)比johnlinvc提供的示例更清晰,更快,因为它们消除了所有不必要的强制转换并按行顺序访问像素,最小化缓存未命中。
它们适用于一般情况,即使对于感兴趣的区域(子矩阵)也是如此。
答案 2 :(得分:1)
除了johnlinvc的答案之外,交换i
和j
的迭代可能是一个好主意,因此您可以连续访问图像元素,因为OpenCV以行主要顺序存储图像。
答案 3 :(得分:1)
由于运行时查找导致效率低下的一般方法是将该查找移动到编译时。
定义像素迭代器模板。在循环之前,甚至在帧生成之前,获得对应于帧图像的特征的像素迭代器。然后使用该迭代器进行像素访问。
大多数情况下,您可以使用纯顺序访问。确保实现迭代器,以便逻辑顺序访问对应于原始字节级别的顺序访问。这有助于(而不是当前代码与硬件的缓存策略不兼容)。