9

バイナリ画像の膨張がどのように行われるかについて理論的に理解しています。

AFAIK、私のSE(構造化要素)がこれなら

0 1
1 1. 

どこ 。は中心を表し、私の画像(バイナリはこれです)

0 0 0 0 0
0 1 1 0 0
0 1 0 0 0
0 1 0 0 0
0 0 0 0 0

したがって、膨張の結果は

0 1 1 0 0 
1 1 1 0 0
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0

SE によると、Image を 0、+1 (上)、および -1 (左) 方向にシフトし、これら 3 つのシフトすべてを結合して上記の結果を得ました。

ここで、これを C、C++ で実装する方法を理解する必要があります。どのように開始し、どのようにセットの結合を取るかがわかりません。元の画像、3 つのシフトされた画像、および和をとって得られた最終的な画像を表すことを考えました。すべてマトリックスを使用しています。

開始するためのサンプル ソリューションや、続行するためのアイデアを入手できる場所はありますか?

ありがとう。

4

4 に答える 4

17

そこにはたくさんのサンプル実装があります.. Googleはあなたの友達です :)

編集
以下は、プロセスの疑似コードです (2D で畳み込みを行うのと非常に似ています)。それを行うためのより賢い方法があると確信しています:

// grayscale image, binary mask
void morph(inImage, outImage, kernel, type) {
 // half size of the kernel, kernel size is n*n (easier if n is odd)
 sz = (kernel.n - 1 ) / 2;

 for X in inImage.rows {
  for Y in inImage.cols {

   if ( isOnBoundary(X,Y, inImage, sz) ) {
    // check if pixel (X,Y) for boundary cases and deal with it (copy pixel as is)
    // must consider half size of the kernel
    val = inImage(X,Y);       // quick fix
   }

   else {
    list = [];

    // get the neighborhood of this pixel (X,Y)
    for I in kernel.n {
     for J in kernel.n {
      if ( kernel(I,J) == 1 ) {
       list.add( inImage(X+I-sz, Y+J-sz) );
      }
     }
    }

    if type == dilation {
     // dilation: set to one if any 1 is present, zero otherwise
     val = max(list);
    } else if type == erosion {
     // erosion: set to zero if any 0 is present, one otherwise
     val = min(list);
    }
   }

   // set output image pixel
   outImage(X,Y) = val;
  }
 }
}

上記のコードは、このチュートリアルに基づいています (ページの最後にあるソース コードを確認してください)。


EDIT2

list.add( inImage(X+I-sz, Y+J-sz) );

アイデアは、(X,Y) にある現在の画像ピクセルに sz (マスクの半分のサイズ) を中心とする (サイズ nxn の) カーネル マスクを重ね合わせ、マスクが存在するピクセルの強度を取得することです。値は 1 です (リストに追加しています)。そのピクセルのすべての近傍を抽出したら、出力イメージ ピクセルを、拡張用にそのリストの最大値 (最大強度) に設定し、浸食用に最小値に設定します (もちろん、これはグレースケール イメージとバイナリ マスクでのみ機能します)
。両方の X のインデックス上記のステートメントの /Y および I/J は、0 から始まると想定されています。必要に応じて、I/J のインデックスをマスクのサイズの半分 (-sz から +sz まで) でいつでも書き換えることができます。小さな変更(私がリンクしたチュートリアルが使用している方法)...


:
この 3x3 カーネル マスクが配置され、ピクセル (X,Y) を中心として配置されていると考えて、その周囲をどのようにトラバースするかを確認します。

 --------------------
|      |       |     |    sz = 1;
 --------------------     for (I=0 ; I<3 ; ++I)
|      | (X,Y) |     |      for (J=0 ; J<3 ; ++J)
 --------------------         vect.push_back( inImage.getPixel(X+I-sz, Y+J-sz) );
|      |       |     |
 --------------------
于 2009-09-24T18:41:27.633 に答える
2

おそらく、膨張の出力ピクセルをどのように生成するかということを見るのがより良い方法です。イメージ内の対応するピクセルについて、構造化要素の原点がそのイメージ ピクセルになるように、構造化要素を配置します。オーバーラップがある場合は、その位置の拡張出力ピクセルを 1 に設定し、そうでない場合は 0 に設定します。

したがって、これは、画像内の各ピクセルを単純にループし、適切にシフトされた構造要素が画像と重なるかどうかをテストすることで実行できます。これは、おそらく x img、y img、x se、y se の 4 つのネストされたループがあることを意味します。したがって、画像ピクセルごとに、構造化要素のピクセルをループして、オーバーラップがあるかどうかを確認します。これは最も効率的なアルゴリズムではないかもしれませんが、おそらく最も単純です。

また、あなたの例は間違っていると思います。拡張は、構造化要素の起点によって異なります。由来なら…

左上のゼロ: 画像 (-1,-1)、(-1,0)、および (0,-1) をシフトする必要があります。

1 1 1 0 0
1 1 0 0 0
1 1 0 0 0
1 0 0 0 0
0 0 0 0 0 

右下: 画像 (0,0)、(1,0)、および (0,1) をシフトする必要があります。

0 0 0 0 0
0 1 1 1 0
0 1 1 0 0
0 1 1 0 0
0 1 0 0 0

MATLAB は floor((size(SE)+1)/2) を SE の原点として使用するため、この場合は SE の左上のピクセルを使用します。これは、 imdilate MATLAB 関数を使用して確認できます。

于 2009-09-24T18:57:47.333 に答える
1

OpenCV

例:侵食と拡張

于 2009-09-24T17:58:25.333 に答える
0
/* structure of the image variable
 * variable n stores the order of the square matrix */

typedef struct image{
        int mat[][];
        int n;
        }image;


/* function recieves image "to dilate" and returns "dilated"*
 * structuring element predefined:
 *             0  1  0
 *             1  1  1
 *             0  1  0
 */

image* dilate(image* to_dilate)
{
       int i,j;
       int does_order_increase;
       image* dilated;

       dilated = (image*)malloc(sizeof(image));
       does_order_increase = 0;

/* checking whether there are any 1's on d border*/       

       for( i = 0 ; i<to_dilate->n ; i++ )
       {
            if( (to_dilate->a[0][i] == 1)||(to_dilate->a[i][0] == 1)||(to_dilate->a[n-1][i] == 1)||(to_dilate->a[i][n-1] == 1) )
            {
                does_order_increase = 1;
                break;
            }
       }

/* size of dilated image initialized */       

       if( does_order_increase == 1)
           dilated->n = to_dilate->n + 1;
       else
           dilated->n = to_dilate->n;

/* dilating image by checking every element of to_dilate and filling dilated *
 * does_order_increase serves to cope with adjustments if dilated 's order increase */

       for( i = 0 ; i<to_dilate->n ; i++ )
       {
            for( j = 0 ; j<to_dilate->n ; j++ )
            {
                 if( to_dilate->a[i][j] == 1)
                 {
                     dilated->a[i + does_order_increase][j + does_order_increase] = 1;
                     dilated->a[i + does_order_increase -1][j + does_order_increase ] = 1;
                     dilated->a[i + does_order_increase ][j + does_order_increase -1] = 1;
                     dilated->a[i + does_order_increase +1][j + does_order_increase ] = 1;
                     dilated->a[i + does_order_increase ][j + does_order_increase +1] = 1;
                 }
            }
       }

/* dilated stores dilated binary image */

       return dilated;
}

/* end of dilation */ 
于 2010-01-17T06:37:26.637 に答える