2

findContours()この画像を適応的にしきい値処理して、OpenCVを使用して外側の境界線を見つけたいと思います。私が適応しきい値を使用するのは通常の理由です。大津の方法を使用しても、グローバルなしきい値処理では、画像の異なる部分間の明るさの違いを適切に補正できません。

ここに画像の説明を入力

残念ながら、アダプティブ スレッシュホールドは、太いグリッド線との交点の一部で破損を引き起こします。これは、交点のピクセルの場合、太いグリッド線が周囲の領域の大部分を占めているため、ローカルしきい値が交点のピクセルの (適度に暗い) 値よりも高くなるためです。驚くべきことに、この効果は、しきい値ウィンドウが大きい場合でもある程度保持されます。

ここに画像の説明を入力

もちろん、これにより、これらのタイプの画像で輪郭を見つけるのに適応しきい値が役に立たなくなります。ただし、接続されたエッジを考え出す点では、Canny などの他のアルゴリズムよりも全体的にはるかに優れています。

画像内のすべての 1 ピクセルおよび 2 ピクセルのギャップを手動で埋めることにより、適応しきい値処理後にエッジを再接続することができました (実際には、実行時間を節約するために縮小された画像でしきい値処理を行います。上記のフルではギャップが大きくなります) -サイズ画像)。私が使用した OpenCV コードは次のとおりです (Android バインディング用に記述)。0 は黒、-1 は白です。

private void fillGaps(Mat image) {

    int size = image.rows() * image.cols();
    byte[] src = new byte[size], dst = new byte[size];
    image.get(0, 0, src);

    int c = image.cols();
    int start = 2 * c + 2;
    int end = size - start;
    for (int i = start; i < end; i++) {
        if (src[i+1] == -1 && src[i-1] == -1 || src[i+c] == -1 && src[i-c] ==-1){
            // 1-pixel gap
            dst[i] = -1;
        } else if (src[i+1] == 0 && src[i+2  ] == -1 && src[i-1] == -1) {
            // 2-pixel horizontal gap
            dst[i] = -1; dst[i+1] = -1;
        } else if (src[i+c] == 0 && src[i+2*c] == -1 && src[i-c] == -1) { 
            // 2-pixel vertical gap
            dst[i] = -1; dst[i+c] = -1;
        }
    }

    image.put(0, 0, dst);
}

ギャップを埋める前後の縮小画像を次に示します。

ここに画像の説明を入力 ここに画像の説明を入力

これはここではかなりうまく機能しますが、大雑把な手法であり、すべてのギャップを埋めるわけではなく、グリッドを近くの他の輪郭と結合することもあります。

適応しきい値の後で切断された輪郭を回避する信頼できる方法は何ですか?

4

2 に答える 2

2

採用している適応しきい値アプローチは問題ありませんが、次のステップとして、侵食、膨張、開放、閉鎖などの形態学的操作を行う必要があります。特定のケースでは、クローズ操作が適しています。
Open-CV 組み込みメソッド cvDilate および cvErode もあります。構造化要素の形状はあまり重要ではありませんが、サイズを小さく保ちます。

ギャップを埋めるあなたの実装を見ました。そこでは、対角要素を考慮していません。各ピクセルの周りに 3x3 または 5x5 のウィンドウを取り、各要素を比較してから結果を決定することをお勧めします。

counter=0;
for (int k=i-radius; k<=i+radius; k++)
{
  for (int l=j-radius; l<=j+radius; l++)
  {
    if (src[k][l] == -1)
    counter++;
  }
}

if (counter > 0)
  dest[k][l] = -1;
else
  dest[k][l] = 0;

これは、拡張 (またはギャップを埋める) に使用するサンプル コードです。半径は 1 (3x3) または 2 (5x5) です。

于 2013-08-14T12:25:49.773 に答える
0

AdaptiveThreshold の後で画像を膨張させてみてください。

于 2016-11-28T19:36:24.673 に答える