CHOU

[Abe先生の授業] Image Processing - 경계추적 알고리즘 구현해 보기 본문

Japan/From Kyushu

[Abe先生の授業] Image Processing - 경계추적 알고리즘 구현해 보기

chobabo 2009. 5. 20. 17:12


 Visual c++ 을 이용한 디지털 영상처리하는 책에 나와 있는 내용과 교수님께서 수업해 주신 내용이 동일해서 이 책의 코드를 보고 따라해 봤습니다.

물체의 최외곽선을 추적하면서 외곽선의 총 길이와 해당 이미지의 면적을 구해주는 간단한 소스코드 입니다. 최근에 연구실에서 가상 수술 시스템이라던지, 가상 로봇 시스템등 비전을 이용한 처리를 많이 해주면서 영상처리를 자주 접하게 되는데 이번 기회에 심도있게 공부할 필요성도 있겠다고 느끼고 있습니다^^.

소스를 간단하게 살펴보면 영상의 맨위쪽부터 탐색을 하면서 영상값이 true 인 것이 검출되면 그때부터 경계추적을 시작하게 됩니다. 이때 8방향 검색을 통해 다음에 추적할 영상을 계산하고 그 영역으로 가서 다시 경계를 추적하게 됩니다. 이때 조금 독특한건 n = (n+5) & 7 이라는 계산을 통해서 다음에 시작되는 추적위치를 결정해 주게 되는 것 입니다.

대체로 소스를 보면 어렵지 않게 이해하실 수 있습니다.


void CImageDlg::OnButton1()
{
 // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください

 // Detecting Edge and Calculate Area

 Invalidate(false); //re_display

 CEdit *myEdit1 = (CEdit*)GetDlgItem(IDC_EDIT4); //結果表示用 PLATE
 CEdit *myEdit2 = (CEdit*)GetDlgItem(IDC_EDIT5); //結果表示用 CAM

 typedef struct tagBORDERINFO
 {
  short *x, *y;
  short n, dn;
 }BORDERINFO;

 BORDERINFO stBorderInfo[1000];

 //--------------------variable declation-------------------------//

 //bool *labelOutPut = &parts.OUTPUT[0][0]; //import output image
 
 CString m_String; //convert integer to string
 CString n_String;

 //Image size
 int width = 320;
 int height = 240;

 int areaCount = 0;

 double edgeLength = 0.0;

 unsigned char *visited = new unsigned char[height*width];
 memset(visited, 0, height*width*sizeof(char));

 short *xchain = new short[1000];
 short *ychain = new short[1000];

 const POINT nei[8] =
 {
  {1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}
 };

 int x0, y0, x, y, k, n;
 int numberBorder = 0, border_count, diagonal_count;
 bool c0, c1;


 //------------------detecting edge------------------------------//
 for(x=1; x < height; x++)
 {
  int IndexCount = x * width;

  for(y=1; y < width; y++)
  {
   //c0 = labelOutPut[IndexCount + y];
   //c1 = labelOutPut[IndexCount - width + y];
   c0 = parts.OUTPUT[x][y];
   c1 = parts.OUTPUT[x-1][y];

   if( (c0 != c1) && (c0 == true) && (visited[IndexCount + y] == 0) )
   {
    border_count = 0;
    diagonal_count = 0;

    x0 = x;
    y0 = y;
    
    n=4;

    do
    {
     for(k=0; k<8; k++, n=((n+1)&7) )
     {
      short u = (short)(x + nei[n].x);
      short v = (short)(y + nei[n].y);

      if( (u < 0) || (u >= height) || (v < 0) || (v >= width) )
       continue;

      if(parts.OUTPUT[u][v] == c0)
       break;
     }//end for k
     if(k == 8 )
      break;

     visited[IndexCount + y] = 255;
     
     xchain[border_count] = x;
     ychain[border_count++] = y;

     if(border_count >= 10000)
      break;

     x = x + nei[n].x;
     y = y + nei[n].y;

     if(n%2 == 1)
      diagonal_count++;

     n = (n + 5) & 7;
    }//end do
    while(!(x == x0) && (y==y0) );

    if(k == 8)
     continue;

    if(border_count < 10)
     continue;

    stBorderInfo[numberBorder].x = new short[border_count];
    stBorderInfo[numberBorder].y = new short[border_count];

    for(k=0; k<border_count; k++)
    {
     stBorderInfo[numberBorder].x[k] = xchain[k];
     stBorderInfo[numberBorder].y[k] = ychain[k];
    }//end for k

    stBorderInfo[numberBorder].n = border_count;
    stBorderInfo[numberBorder++].dn = diagonal_count;

    if(numberBorder >= 1000)
     break;
   }//end if
  }//end for y
 }//end for x

 //--------------------area count---------------------------//
 for(x=0; x < height; x++)
 {
  for(y=0; y < width; y++)
  {
   if(parts.OUTPUT[x][y] == true)
   {
    areaCount++;
   }//end if
  }//end for y
 }//end for x

 edgeLength = (sqrt(2) * diagonal_count) + border_count;

 //display on edit1
 m_String.Format("%f", edgeLength);  //covert int to string
 myEdit1->SetWindowText(m_String);  //display myEdit1

 //display on edit2
 n_String.Format("%d", areaCount);  //covert int to string
 myEdit2->SetWindowText(n_String);  //display myEdit1

 delete[] visited;
 delete[] xchain;
 delete[] ychain;
 
}


현재까지 만든 화면 입니다. 라벨링 한후에 색깔을 바꿔주는 부분하고 에지 추출해서 에지 길이와 면적을 구하는거 까지 알아봤습니다.





Reference

1. Visual C++ 을 이용한 디지털 영상처리 (강동중, 하종은 저)

2. 코드 소스 파일