0xS*_*ina 0 c c++ algorithm opencv image-processing
我正在处理视频中的帧并实时显示(实时).算法很快,但我想知道是否有任何我可以做的优化会使它更加无缝.我不知道我的算法中的哪些函数占用了大部分时间,我的猜测是sqrt()函数,因为它显然有一些查找,但我不确定.
这是我的算法:
IplImage *videoFrame = cvCreateImage(cvSize(bufferWidth, bufferHeight), IPL_DEPTH_8U, 4);
videoFrame->imageData = (char*)bufferBaseAddress;
int channels = videoFrame->nChannels;
int widthStep = videoFrame->widthStep;
int width = videoFrame->width;
int height = videoFrame->height;
for(int i=0;i<height;i++){
uchar *col = ((uchar *)(videoFrame->imageData + i*widthStep));
for(int j=0;j<width;j++){
double pRed = col[j*channels + 0];
double pGreen = col[j*channels + 1];
double pBlue = col[j*channels + 2];
double dRed = green.val[0] - pRed;
double dGreen = green.val[1] - pGreen;
double dBlue = green.val[2] - pBlue;
double sDRed = dRed * dRed;
double sDGreen = dGreen * dGreen;
double sDBlue = dBlue * dBlue;
double sum = sDRed + sDGreen + sDBlue;
double euc = sqrt(sum);
//NSLog(@"%f %f %f", pRed, pGreen, pBlue);
if (euc < threshold) {
col[j*channels + 0] = white.val[0];
col[j*channels + 1] = white.val[1];
col[j*channels + 2] = white.val[2];
}
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
UPDATE 好的,所以这样做是循环遍历图像中的每个像素,并计算像素颜色和绿色之间的欧几里德距离.所以,总的来说这是一个绿屏算法.
我做了一些基准测试,没有使用这个算法的fps是30.0fps.使用此算法,它降至约8fps.但是,大部分for drop来自于col[j*channels + 0];如果算法没有做任何其他事情并使用访问阵列选择,它下降到大约10fps.
更新2 确定这很有趣,我从双循环内部的东西中删除了随机行,看看是什么原因导致更大的开销,这就是我发现的:在堆栈上创建变量会导致FPS大幅下降.考虑这个例子:
for(int i=0;i<height;i++){
uchar *col = ((uchar *)(data + i*widthStep));
for(int j=0;j<width;j++){
double pRed = col[j*channels + 0];
double pGreen = col[j*channels + 1];
double pBlue = col[j*channels + 2];
}
}
Run Code Online (Sandbox Code Playgroud)
这使fps降至11-ish.
另一方面,现在这个:
for(int i=0;i<height;i++){
uchar *col = ((uchar *)(data + i*widthStep));
for(int j=0;j<width;j++){
col[j*channels + 0];
col[j*channels + 1];
col[j*channels + 2];
}
}
Run Code Online (Sandbox Code Playgroud)
根本不会掉落FPS!FPS保持在30.0.我想我应该更新这个,让你们知道这是什么真正的瓶颈,让变量不是他堆叠.我想知道我是否内联所有可能获得的纯30.0fps.
Nvm ...可能甚至没有评估未分配给var的表达式.
sqrt 是一个单调递增的函数,你似乎只在阈值测试中使用它.
由于单调性,sqrt(sum) < threshold相当于sum < threshold * threshold(假设阈值为正).
没有更昂贵的平方根,编译器会在循环外移动乘法.
下一步,您可以j * channels从内部循环中删除昂贵的乘法.编译器应该足够聪明,只能执行一次并使用结果三次,但它仍然是计算其余部分所依赖的乘法,因此会损坏流水线.
请记住,乘法与重复加法相同吗?通常做更多的操作更昂贵,但在这种情况下,由于循环,你已经有了重复部分.所以使用:
for(int j=0;j<width;j++){
double pRed = col[0];
double pGreen = col[1];
double pBlue = col[2];
double dRed = green.val[0] - pRed;
double dGreen = green.val[1] - pGreen;
double dBlue = green.val[2] - pBlue;
double sDRed = dRed * dRed;
double sDGreen = dGreen * dGreen;
double sDBlue = dBlue * dBlue;
double sum = sDRed + sDGreen + sDBlue;
//NSLog(@"%f %f %f", pRed, pGreen, pBlue);
if (sum < threshold * threshold) {
col[0] = white.val[0];
col[1] = white.val[1];
col[2] = white.val[2];
}
col += channels;
}
Run Code Online (Sandbox Code Playgroud)
接下来,您uchar和之间的转换成本很高double.阈值测试不需要这些:
int j = width;
do {
int_fast16_t const pRed = col[0];
int_fast16_t const pGreen = col[1];
int_fast16_t const pBlue = col[2];
int_fast32_t const dRed = green.val[0] - pRed;
int_fast32_t const dGreen = green.val[1] - pGreen;
int_fast32_t const dBlue = green.val[2] - pBlue;
int_fast32_t const sDRed = dRed * dRed;
int_fast32_t const sDGreen = dGreen * dGreen;
int_fast32_t const sDBlue = dBlue * dBlue;
int_fast32_t const sum = sDRed + sDGreen + sDBlue;
//NSLog(@"%f %f %f", pRed, pGreen, pBlue);
if (sum < threshold * threshold) {
col[0] = white.val[0];
col[1] = white.val[1];
col[2] = white.val[2];
}
col += channels;
} while (--j);
Run Code Online (Sandbox Code Playgroud)