如何优化C 代码的以下片段 - 卷中的零交叉点

How to optimize the following fragment of C++ code - zero crossings in a volume

本文关键字:片段 交叉点 优化 代码 何优化      更新时间:2023-10-16

我正在努力优化以下代码片段。在320x320x320体积中的每个体素中都调用该函数,其中每个体素是16位灰度值。该音量存储为一系列平面(横截面),每个平面是连续的1D阵列,因此,例如,电流素下方的体素的位置变为CurrentPosition PixelSperrow,其左侧位置为CurrentPosition -1。1。<<<<<<

函数检查体积中的零交叉口以及电流和相邻体素的绝对值是否高于某些阈值。这是Marr-Hildreth边缘检测器的必要部分。

电流置位是电流体素,相对位置也可以是电流体素(在这种情况下,在同一平面以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)。

另外,您检查了共享边缘或顶点的像素对,您只需要检查那些共享脸的像素即可。如果以下图中的像素ad之间的交叉零,则ab之间或ac之间必须存在一个。

a   b
c   d

因此,对于每个像素,您只需要检查三个邻居,而不是27。

但是,这并不能完全解释您的幅度检查,ad之间的差异可能大于其他两个邻居中的任何一个。但是,我认为这并不重要。

在该注意事项上,您的幅度检查是错误的:如果 ab的符号不同并且都非常大(重要的零交叉),则abs(a + b)可能为0,而您不会计算它。您可能想取得差异!