2

我在 MATLAB 中有一个长时间运行的函数,我试图通过添加缓存来加速它并最终显着降低了我的性能。我的代码基本上是在边缘检测图像中搜索连续的“水平”线,原始代码如下所示:

function lineLength = getLineLength(img, startRow, startCol)
    [nRows, nCols] = size(img);
    lineLength = 0;
    if startRow < 1 || startRow > nRows
        return;
    end

    for curCol = startCol:nCols
        if img(curCol)
            lineLength = lineLength + 1;
            continue;
        elseif lineLength > 0
            lengths = zeros(2,1);
            lengths(1) = getLineLength(img, startRow - 1, curCol);
            lengths(2) = getLineLength(img, startRow + 1, curCol);
            increment = max(lengths);
            lineLength = lineLength + increment;
        end
        break; %// At this point the end of the current line has been reached
    end
end function

由于这个函数的性能不是我想要的,我想我会从任何一点添加长度缓存,如下所示:

function lineLength = getLineLength(img, startRow, startCol)
persistent pointCache; 
    if startRow == 0 && startCol == 0
        pointCache = zeros(size(img, 1), size(img, 2), 2);
    end
    [nRows, nCols] = size(img);
    lineLength = 0;
    if startRow < 1 || startRow > nRows
        return;
    end

    for curCol = startCol:nCols
        if pointCache(startRow, curCol, 2)
            lineLength = lineLength + pointCache(startRow, curCol, 1);
            break;
        end
        if img(curCol)
            lineLength = lineLength + 1;
            continue;
        elseif lineLength > 0
            lengths = zeros(2,1);
            lengths(1) = getLineLength(img, startRow - 1, curCol);
            lengths(2) = getLineLength(img, startRow + 1, curCol);
            increment = max(lengths);
            lineLength = lineLength + increment;
        end
        break; %// At this point the end of the current line has been reached
    end
    pointCache(startRow, startCol, 1) = lineLength;
    pointCache(startRow, startCol, 2) = 1;
end function

令我惊讶的是,实现这种缓存实际上使我的性能更差,而不是更好。我最好的猜测是global变量给我带来了麻烦,或者它使用了额外的内存,但我没有足够的 MATLAB 经验知道。

已编辑...

正如 Gautam 正确指出的那样,原始代码中存在一个忽略递归结果的错误。这就是实际代码的作用。我确信这很明显,但 MATLAB 不是我的母语,所以如果有更 MATLAB 的方式来做到这一点,我会喜欢这些建议。

4

4 回答 4

3

我很确定全局不是问题,但就风格而言,您应该使用 a persistent,它在调用之间保持它的值,但对于函数来说是本地的。

每当您遇到性能问题时,请配置文件。调用profile on,然后调用你的函数,然后调用profile report。它会指出你真正的性能问题。直觉很少有利于分析问题,尤其是在 matlab 中。您可以阅读帮助,但它非常不言自明。

于 2008-12-15T15:11:21.627 回答
2

It's not clear to me what the function does. In particular, why do you recursively call getLineLength and then effectively throw away the results (you only test if increment is greater than zero)?

My guess for why pointCache doesn't help: your function probably doesn't call itself repeatedly with the same paramters (startRow, startCol). Have you tried to log how many times getLineLength is called for a particular startRow and startCol?

Whatever your algorithm is, using recursion to iterate over a image is completely unsuited to MATLAB's strengths. If you want high performance:

  1. Set up your algorithm to use iteration instead of recursion, and
  2. Figure out how to vectorize the iterated parts.

Some tips on vectorizing:

  • Use built-in functions like sum, cumsum, diff, bsxfun, and accumarray to operate directly over the image matrix.
  • Complicated double-iteration computations on images can sometimes be reexpressed as matrix multiplications.
于 2008-12-16T17:01:30.873 回答
0

我的猜测是您正在缓存代码的错误部分。elseif 部分的递归似乎是真正的瓶颈。整个算法对我来说看起来有点奇怪,也许你最好尝试这样的事情(虽然我不确定这是否是你想要的):

for every pixel p in img
  if (pixel p set)
    linelength = 1
    p2 = p
    while (pixel p2 set) and (p2 in same column as p)
      p++ // don't check lines twice
      p2++
      linelength++
    endwhile
  endif
于 2008-12-15T13:42:33.287 回答
0

据我所知,您正在尝试查找每列的非零元素的数量,尽管代码似乎并没有完全实现这一点。会像以下工作:

lineLengths = max(cumsum(img~=0, 1), 1)

如果您尝试从图像中提取 blob,请考虑使用 BWLABEL 函数。

我赞同 Gautam 所说的在 Matlab 中通常运行良好的内容。

于 2008-12-18T04:09:05.503 回答