2017-01-17 7 views
0

私は現在、オクターブのエッジ検出器で作業しています。 JavaやPythonのような他のプログラミング言語から来ているので、私はforループを反復するのに慣れています。今オクターブでは、これは重大なパフォーマンスのヒットを引き起こし、私は自分のコードをベクトル化する方法を理解するのに少し難しいです。私は、次の2つのコード片を有する:サブマトリクス(およびサブベクトル)の演算をベクトル化できますか?

1)

function zc = ZeroCrossings(img, T=0.9257) 
    zc = zeros(size(img)); 

    # Iterate over central positions of all 3x3 submatrices 
    for y = 2:rows(img) - 1 
    for x = 2:columns(img) - 1 
     ndiff = 0; 

     # Check all necessary pairs of elements of the submatrix (W/E, N/S, NW/SE, NE/SW) 
     for d = [1, 0; 0, 1; 1, 1; 1, -1]' 
     p1 = img(y-d(2), x-d(1)); 
     p2 = img(y+d(2), x+d(1)); 
     if sign(p1) != sign(p2) && abs(p1 - p2) >= T 
      ndiff++; 
     end 
     end 

     # If at least two pairs fit the requirements, these coordinates are a zero crossing 
     if ndiff >= 2 
     zc(y, x) = 1; 
     end 
    end 
    end 
end 

2)

function g = LinkGaps(img, k=5) 
    g = zeros(size(img)); 

    for i = 1:rows(img) 
    g(i, :) = link(img(i, :), k); 
    end 
end 

function row = link(row, k) 
    # Find first 1 
    i = 1; 
    while i <= length(row) && row(i) == 0 
    i++; 
    end 

    # Iterate over gaps 
    while true 
    # Determine gap start 
    while i <= length(row) && row(i) == 1 
     i++; 
    end 
    start = i; 

    # Determine gap stop 
    while i <= length(row) && row(i) == 0 
     i++; 
    end 

    # If stop wasn't reached, exit loop 
    if i > length(row) 
     break 
    end 

    # If gap is short enough, fill it with 1s 
    if i - start <= k 
     row(start:i-1) = 1; 
    end 
    end 
end 

これらの機能の両方の第2のケースで部分行列(又は行と下位行を繰り返し処理する)、及び特に最初のプログラムは私のプログラムをかなり遅くしているようです。

  1. この関数は、ゼロ交差(その対応する3×3近傍特定の要件に合う画素)が見出された1Sと、画素(img)のマトリックスを受け取り、バイナリ(0/1)行列を返します。

    ループの外側2は、何とかベクトル化できるように見えます。私は体をそれ自身の関数に入れることができます(引数として必要な部分行列を取る)が、すべての部分行列でこの関数を呼び出す方法を理解できず、対応する(中心の)位置を戻り値に設定します。

    内側のforループもベクトル化できる場合のボーナスポイントです。

  2. この関数は、前の出力からバイナリ行列を取り込み、その行のギャップを埋めます(つまり、1に設定します)。ギャップは、長さ< = kの一連の0として定義され、両辺は1で境界付けられます。

    今や、少なくとも外側のループ(LinkGapsのもの)はベクトル化可能です。しかし、linkwhileループは再び単一の要素ではなくサブベクトルで動作するので、どのようにベクトル化するのかはわかりません。

+0

タスク1は、ゼロ交差を検出するように設計されたカーネルを使用して畳み込みを解くことができます。 – Suever

答えて

0

ない完全なソリューションが、ここであなたはどのループせずに最初の操作を行う可能性がどのような考え方である:

% W/E 
I1 = I(2:end-1,1:end-2); 
I2 = I(2:end-1,3:end ); 
C = (I1 .* I2 < 0) .* (abs(I1 - I2)>=T); 

% N/S 
I1 = I(1:end-2,2:end-1); 
I2 = I(3:end, 2:end-1); 
C = C + (I1 .* I2 < 0) .* (abs(I1 - I2)>=T); 

% proceed similarly with NW/SE and NE/SW 
% ... 

% zero-crossings where count is at least 2 
ZC = C>=2; 

アイデア:、適切にシフトされている2つのサブイメージを形成する記号の違いをチェック(生成物陰性)およびその差を閾値する。両方のテストは論理(0/1)の行列を返し、要素ごとの積は論理を行い、結果は両方のテストが成功した1の0/1行列です。これらの行列は、カウント(ndiff)を追跡するために追加することができます。

+0

私が予想していたよりも少し複雑ですが、優雅なソリューションです。ありがとうございました。 –

+0

2行目の行内を結ぶギャップは、同様に行シフト量をkまでインクリメントすることでベクトル化することができますが、実際には効率が悪くなる可能性があります。いずれにしても、1)はパフォーマンスの大幅な向上であり、現在は修正されています(プログラムの実行時間を約6倍改善しました)。 –

+0

2)私の提案は、すべての遷移(0→1または1> 0)を見つけるために 'idx = find(diff(row))'を行うことでした。行がバイナリの場合、これらは交互になります。したがって、最初のものが+ 1の破棄である場合。さて、 'gaps = diff(idx)'は、遷移の長さを含むベクトルです。毎秒1つはギャップです。したがって、満たすべきものは 'fill = gap(1:2:end)<= k;'であり、これを使ってidxのインデックスを見つけ、 'I'の対応する値を1に設定します。そんな感じ。 – Florian

関連する問題