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 は私の母国語ではないので、これを行うための MATLABy の方法が他にあれば、提案をお待ちしています。

4

4 に答える 4

3

グローバルは問題ではないと確信していますが、スタイルの問題として、persistent呼び出しから呼び出しまで値を維持するが、関数に対してローカルである a を使用する必要があります。

パフォーマンスの問題が発生したときはいつでもプロファイルを作成してください。を呼び出しprofile on、次に関数を呼び出し、次にprofile report. 実際のパフォーマンスの問題を指摘します。特に matlab では、問題のプロファイリングに直観が役立つことはめったにありません。ヘルプを読むことができますが、それはかなり自明です。

于 2008-12-15T15:11:21.627 に答える
2

関数が何をするのか私にはわかりません。特に、なぜgetLineLengthを再帰的に呼び出してから、結果を効果的に破棄するのですか(増分がゼロより大きいかどうかのみをテストします)。

pointCacheが役に立たない理由についての私の推測:あなたの関数はおそらく同じパラメーター(startRow、startCol)でそれ自体を繰り返し呼び出さないでしょう。特定のstartRowおよびstartColに対してgetLineLengthが呼び出された回数をログに記録しようとしましたか?

アルゴリズムが何であれ、再帰を使用して画像を反復処理することは、MATLABの長所にはまったく適していません。高性能が必要な場合:

  1. 再帰の代わりに反復を使用するようにアルゴリズムを設定し、
  2. 繰り返される部分をベクトル化する方法を理解します。

ベクトル化に関するいくつかのヒント:

  • sum、、、、などの組み込み関数を使用してcumsum、画像マトリックスを直接操作します。diffbsxfunaccumarray
  • 画像に対する複雑な二重反復計算は、行列の乗算として再表現される場合があります。
于 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)

画像からブロブを抽出しようとしている場合は、BWLABEL 関数の使用を検討してください。

私は、Matlab で一般的にうまく機能するものについて Gautam が述べていることに同意します。

于 2008-12-18T04:09:05.503 に答える