如何优化C ++代码的以下片段 - 卷中的零交叉
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何优化C ++代码的以下片段 - 卷中的零交叉相关的知识,希望对你有一定的参考价值。
我正在努力优化以下代码片段。正在为320x320x320体积中的每个体素调用该函数,其中每个体素是16位灰度值。体积存储为一系列平面(横截面),并且每个平面是连续的1D阵列,因此例如当前体素下方的体素的位置变为currentPosition + pixelsPerRow,并且其左侧的位置变为currentPosition-1。
该函数检查体积中的零交叉以及当前和相邻体素的绝对值是否高于特定阈值。这是Marr-Hildreth边缘探测器的必要部分。
currentPosition是当前体素,relativePosition也可以是当前体素(在这种情况下,在同一平面内围绕它的8个方向检查零交叉)或者它可以是直接在其上方或正下方的体素。这样,对于每个体素,执行27次检查,其覆盖3D中的所有可能方向。
也许可以重新排列函数,使其执行速度更快。我已经尝试以这样的方式安排检查顺序,即分支预测有更好的机会启动,但也许可以加快它的速度。目前,它需要50%的大型应用程序处理时间,因此需要进行一些优化。
bool zeroCrossing(int16_t* currentPosition, int16_t* relativePosition, int pixelsPerRow, int threshold)
{
return *currentPosition * *(relativePosition - pixelsPerRow - 1) < 0 && abs(*currentPosition + *(relativePosition - pixelsPerRow - 1)) > threshold
|| *currentPosition * *(relativePosition - pixelsPerRow) < 0 && abs(*currentPosition + *(relativePosition - pixelsPerRow)) > threshold
|| *currentPosition * *(relativePosition - pixelsPerRow + 1) < 0 && abs(*currentPosition + *(relativePosition - pixelsPerRow + 1)) > threshold
|| *currentPosition * *(relativePosition - 1) < 0 && abs(*currentPosition + *(relativePosition - 1)) > threshold
|| *currentPosition * *(relativePosition) < 0 && abs(*currentPosition + *(relativePosition)) > threshold
|| *currentPosition * *(relativePosition + 1) < 0 && abs(*currentPosition + *(relativePosition + 1)) > threshold
|| *currentPosition * *(relativePosition + pixelsPerRow - 1) < 0 && abs(*currentPosition + *(relativePosition + pixelsPerRow - 1)) > threshold
|| *currentPosition * *(relativePosition + pixelsPerRow) < 0 && abs(*currentPosition + *(relativePosition + pixelsPerRow)) > threshold
|| *currentPosition * *(relativePosition + pixelsPerRow + 1) < 0 && abs(*currentPosition + *(relativePosition + pixelsPerRow + 1)) > threshold;
}
我的直觉是,这段代码非常适合并行化。使用AVX(2),或将其卸载到GPU。这将超出C ++的范畴,但这对于程序的核心功能来说是合理的。
我假设您已经使用线程来并行化操作,因为这非常简单。请注意,使用AVX,您仍然需要线程;每个CPU核心都有自己的AVX单元。
如果存在过零点,则将在两个相邻像素之间发生。在卷中运行时,您只需要检查每对邻居一次。如果将函数应用于每个像素,则会检查每对像素两次。 (我也使用术语像素作为3D图像的元素,我不喜欢voxel这个词很多)。
此外,您还可以检查共享边或顶点的像素对,只需要检查共享面的像素。如果下图中像素a
和d
之间存在零交叉,则a
和b
之间或a
和c
之间必须有一个。
a b
c d
因此,对于每个像素,您只需要检查三个邻居,而不是27.这会将执行时间减少到1/9。
然而,这并没有完全解释你的幅度检查,a
和d
之间的差异可能大于其他两个邻居之间的差异。但是,我不认为这很重要。
在这方面,你的幅度检查是错误的:如果a
和b
符号不同并且都非常大(一个重要的零交叉),那么abs(a + b)
可能是0,你不会计算它。你可能想要与众不同!
以上是关于如何优化C ++代码的以下片段 - 卷中的零交叉的主要内容,如果未能解决你的问题,请参考以下文章