我怎样才能让它更快?(C/C++)OpenCV

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的表达式.

Ben*_*igt 7

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)