6

我一直在使用openCV进行一些块匹配,我注意到它的平方差之和与这样的直接for循环相比非常快:

int SSD = 0;
for(int i =0; i < arraySize; i++)
    SSD += (array1[i] - array2[i] )*(array1[i] - array2[i]);

如果我查看源代码以了解繁重的工作发生在哪里,OpenCV 的人们让他们的 for 循环在循环的每次迭代中一次执行 4 次平方差计算。进行块匹配的函数如下所示。

int64
icvCmpBlocksL2_8u_C1( const uchar * vec1, const uchar * vec2, int len )
{
int i, s = 0;
int64 sum = 0;

for( i = 0; i <= len - 4; i += 4 ) 
{   
    int v = vec1[i] - vec2[i];
    int e = v * v;

    v = vec1[i + 1] - vec2[i + 1]; 
    e += v * v;
    v = vec1[i + 2] - vec2[i + 2];
    e += v * v;
    v = vec1[i + 3] - vec2[i + 3];
    e += v * v;
    sum += e;
}

for( ; i < len; i++ )
{
    int v = vec1[i] - vec2[i];

    s += v * v;
}

return sum + s;
}

此计算适用于无符号 8 位整数。他们在此函数中对 32 位浮点数执行类似的计算:

double
icvCmpBlocksL2_32f_C1( const float *vec1, const float *vec2, int len )
{
double sum = 0;
int i;

for( i = 0; i <= len - 4; i += 4 )
{
    double v0 = vec1[i] - vec2[i];
    double v1 = vec1[i + 1] - vec2[i + 1];
    double v2 = vec1[i + 2] - vec2[i + 2];
    double v3 = vec1[i + 3] - vec2[i + 3];

    sum += v0 * v0 + v1 * v1 + v2 * v2 + v3 * v3;
}
for( ; i < len; i++ )
{
    double v = vec1[i] - vec2[i];

    sum += v * v;
}
return sum;
}

我想知道是否有人知道像这样将循环分成 4 个块是否可以加快代码速度?我应该补充一点,这段代码中没有发生多线程。

4

2 回答 2

4

我的猜测是,这只是展开循环len的一个简单实现——它在循环的每次传递中节省了 3 次加法和 3 次比较,例如,如果检查涉及缓存未命中,这可以节省很多。缺点是这种优化增加了代码复杂性(例如,如果长度不能被 4 整除,则在末尾额外的 for 循环以完成剩余 len % 4 个项目的循环),当然,这是一个依赖于架构的优化其改进幅度将因硬件/编译器/等而异...

尽管如此,与大多数优化相比,它很容易遵循,并且无论架构如何,都可能会导致某种性能提升,因此将其投入其中并希望获得最好的结果是低风险的。由于 OpenCV 是一个得到很好支持的代码块,我确信有人对这些代码块进行了检测,并发现它们非常值得——正如您自己所做的那样。

于 2012-04-14T17:51:28.260 回答
2

您的代码有一个明显的优化,即:

int SSD = 0;
for(int i = 0; i < arraySize; i++)
{
    int v = array1[i] - array2[i];
    SSD += v * v;
}
于 2012-04-14T18:07:01.443 回答