2009-09-24 2 views
6

2 진 이미지에서 확장이 어떻게 수행되는지 이론적으로 이해합니다.C, C++에서 침식, 팽창을 구현

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 

그렇게 팽창의 결과가 I가 0에서 1 (최대) 및 및 이미지를 이동하여 결과 이상 가지고

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에 따라 1 (왼쪽) 방향으로 움직이고,이 모든 3 교대의 결합을 취한다.

이제 C, C++에서이를 구현하는 방법을 알아야합니다. 시작하는 방법과 세트 조합을 가져 오는 방법을 잘 모르겠습니다. 원본 이미지, 세 개의 시프트 된 이미지 및 유니온을 가져 와서 얻은 최종 이미지를 나타내는 것으로 생각했습니다. 모두 매트릭스를 사용합니다.

시작하기위한 샘플 솔루션이나 진행할 아이디어가있는 곳이 있습니까?

감사합니다.

답변

10

밖에 샘플 구현의 톤이있다 .. Google 다음
프로세스의 의사 코드 (매우 당신의 친구 :

EDIT입니다 2D에서 컨볼 루션을하는 것과 유사). 임 확실히 그 일을 더 영리한 방법이 있습니다 : 위의 코드는이 tutorial을 기반으로

// 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까지) 작은 변화 (내가 사용하는 튜토리얼의 사용 방법)와 함께 ...


:
픽셀 (X, Y)에 배치하고 중심이 3 × 3 커널 마스크를 고려, 우리는 주변의 이웃 통과 방법 : 아마도

-------------------- 
|  |  |  | 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)); 
|  |  |  | 
-------------------- 
+0

그리고 커널 크기가 MxN = 1x3 인 경우는 어디에 M은 너비이고 N은 높이입니까? – svlada

+0

코드는 실제 구현이 아닌 개요 일뿐입니다. 하지만 자세히 보시면 N이 홀수 인 N * N 커널 만 처리하는 것을 볼 수 있습니다. – Amro

+0

:) 그래요. kernelWidth kernelHeght를 추가하고 경계를 확인하여 코드를 향상시킬 수 있다고 말하고 싶습니다. – svlada

2

볼 수있는 더 좋은 방법을 그것이 확장의 출력 픽셀을 생성하는 방법입니다. 이미지의 해당 픽셀에 대해 구조 요소의 원점이 이미지 픽셀에 있도록 구조 요소를 정렬합니다. 겹치는 부분이 있으면 그 위치의 확장 출력 픽셀을 1로 설정하고 그렇지 않으면 0으로 설정하십시오.

이렇게하면 이미지의 각 픽셀을 반복하고 적절히 이동 된 구조화 요소는 이미지와 겹칩니다. 즉, x img, y img, x se, y se라는 4 개의 중첩 루프가있을 것입니다. 따라서 각 이미지 픽셀에 대해 구조화 요소의 픽셀을 반복하고 겹치는 부분이 있는지 확인합니다. 이것은 가장 효율적인 알고리즘은 아니지만, 아마도 가장 간단합니다.

또한 귀하의 예가 잘못되었다고 생각합니다. 팽창은 구조 요소의 기원에 달려 있습니다. 당신은 이미지 (-1, -1), (-1,0) 이동해야하고, (0, -1) 제공 : 기원 인 경우 ... 상단에

은 0 왼쪽

포기하면 이미지 (0,0)을 이동해야합니다 (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 0 0 0 
0 1 1 1 0 
0 1 1 0 0 
0 1 1 0 0 
0 1 0 0 0 

MATLAB 바닥 ((크기를 사용합니다 (SE) +1)/2)를 SE의 원점으로 사용하므로이 경우 SE의 왼쪽 위 픽셀을 사용합니다. imdilate MATLAB 함수를 사용하여이를 확인할 수 있습니다.

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 */