[문제1] 왼쪽의 동전들을 입력 받아 오른쪽 그림 처럼 동전의 모양을 표현한다.

알고리즘 방법들
1. 명암도 영상변환
2. 가우시안 블러링
3. 이진화
4. 모폴로지 연산

[문제2] 구해진 동전 이진 영상에서 동전의 개수를 세어보자.

알고리즘
1. 입력영상과 레이블링 영상 두개의 버퍼를 준비한다.
2. 물체(밝기값 255) 부분에 해당한 위치의 레이블링 영상에서 이웃 (8방향)의 픽셀의 number로 설정한다.
3. 이웃하는 픽셀에 number가 없을 경우는 새로운 번호를 부여한다. (count++)
4. 반복한다.



* 위 그림에서 8방향에 대해 검색한 후 주위에 2가지 이상의 번호가 있을 수 있다. 즉, 연결된 하나의 도형에 2개 이상의 번호로 되어 있는 경우 하나로 합치기 위해 다음과 같이한다.
if (label_img( 8방향)에 번호가 있는가?) {
if( 2가지 이상의 번호가 있는가) {
* List 버퍼에 큰 번호(2) 와 작은 번호(1) 두 개를 추가한다.
}
* 현재 위치에 작은 번호를 부여한다.
}
else {
* 새 번호를 부여한다.
}
LabelTable[256]
------------------------------
LabelTable[큰 번호] = 작은 번호
------------------------------
2 1
4 3
7 3
6 5
5 3
------------------------------
List 버퍼를 다음과 같이 중복된 것을 정리한후,
------------------------------
LabelTable[큰 번호] = 작은 번호
------------------------------
2 1
4 3
7 3
6 3
5 3
------------------------------
label_img 영상 코드를 모두 바꾼다.
* 다음은 Blob 영상처리 소스. (Visual C++와 OpenCV로 배우는 디지털 영상처리 책)
- Grass Fire 알고리즘을 사용한 방법이다.
void CWinTestDoc::m_BlobColoring(int height, int width)
{
//
int i,j,m,n,top, BlobArea[1000];
short curColor=0, r,c, area;
// 스택으로 사용할 메모리 할당
short* stackx=new short [height*width];
short* stacky=new short [height*width];
// 라벨링된 픽셀을 저장하기 위해 메모리 할당
short *coloring = new short [height*width];
for(i=0; i<height*width; i++) coloring[i]=0; //메모리 초기화
for(i=0; i<height; i++)
{
for(j=0; j<width; j++)
{
// 이미 방문한 점이거나 픽셀값이 255가 아니라면 처리 안함
if(coloring[i*width+j]!=0 || m_InImg[i][j]!=255) continue;
r=i;
c=j;
top=0; area=1;
curColor++;
while(1)
{
GRASSFIRE:
for(m=r-1; m<=r+1; m++)
{
for(n=c-1; n<=c+1; n++)
{
// 관심 픽셀이 영상경계를 벗어나면 처리 안함
if(m<0 || m>=height || n<0 || n>=width) continue;
if((int)m_InImg[m][n]==255 && coloring[m*width+n]==0)
{
coloring[m*width+n]=curColor; // 현재 라벨로 마크
if(push(stackx,stacky,(short)m,(short)n,&top)==-1) continue;
r=m;
c=n;
area++;
goto GRASSFIRE;
}
}
}
if(pop(stackx,stacky,&r,&c,&top)==-1) break;
}
if(curColor<1000) BlobArea[curColor] = area; // 면적
}
}
// 라벨링된 데이터를 m_OutImg배열을 이용하여 화면출력
float grayGap = 250.0f/(float)curColor;
for(i=0; i<height; i++)
{
for(j=0; j<width; j++)
{
int value = (int)(coloring[i*width+j]*grayGap);
if(value==0) m_OutImg[i][j] = 255;
else m_OutImg[i][j] = value;
}}
delete []coloring; delete []stackx; delete []stacky;
}
int CWinTestDoc::push(short *stackx, short *stacky, short vx, short vy, int *top)
{
if(*top>=300000) return(-1);
(*top)++;
stackx[*top]=vx;
stacky[*top]=vy;
return(1);
}
int CWinTestDoc::pop(short *stackx, short *stacky, short *vx, short *vy, int *top)
{
if(*top<=0) return(-1);
*vx=stackx[*top];
*vy=stacky[*top];
(*top)--;
return(1);
}