void CWin Test Doc grasslabelint height int width
영상 라벨링 • 재귀호출 방법 void CWin. Test. Doc: : grass_label(int height, int width) { // 라벨링된 영상을 저장하기 위한 배열의 메모리 할당 short *coloring = new short [height*width]; int i, j, cur. Color=0; for(i=0; i<height*width; i++) coloring[i]=0; // 입력 영상의 라벨링 for(i=0; i<height; i++) { for(j=0; j<width; j++) { if(m_In. Img[i][j]==255 && coloring[i*width+j]==0) { cur. Color++; grass(coloring, height, width, i, j, cur. Color); } } } float gray. Gap = 250. 0 f/(float)cur. Color; // 라벨링된 데이터를 m_Out. Img배열을 이용하여 화면출력 for(i=0; i<height; i++) { for(j=0; j<width; j++) { int value = (int)(coloring[i*width+j]*gray. Gap); if(value==0) m_Out. Img[i][j] = 255; else m_Out. Img[i][j] = value; } } delete []coloring; // 메모리 해제 void CWin. Test. Doc: : grass(short *coloring, int height, int width, int i, int j, int cur. Color) { int k, l, index; for(k=i-1; k<=i+1; k++) { for(l=j-1; l<=j+1; l++) { // 영상의 경계를 벗어나면 라벨링하지 않음 if(k<0 || k>=height || l<0 || l>=width) continue; } } } index = k*width+l; // 아직 방문하지 않은 픽셀이고 값이 255라면 라벨링함 if(m_In. Img[k][l]==255 && coloring[index]==0) { coloring[index] = cur. Color; grass(coloring, height, width, k, l, cur. Color); } 7
영상 라벨링 • 반복법: Stack 사용 void CWin. Test. Doc: : m_Blob. Coloring(int height, int width) { // 스택으로 사용할 메모리할당 short* stackx=new short [height*width]; short* stacky=new short [height*width]; ………. for(i=0; i<height; i++) { for(j=0; j<width; j++) { // 이미 방문한 점이거나 픽셀값이 255가 아니라면 처리안함 if(coloring[i*width+j]!=0 || m_In. Img[i][j]!=255) continue; 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_In. Img[m][n]==255 && coloring[m*width+n]==0) { coloring[m*width+n]=cur. Color; // 현재 라벨로 마크 if(push(stackx, stacky, (short)m, (short)n, &top)==-1) continue; r=m; c=n; area++; goto GRASSFIRE; } r=i; c=j; top=0; area=1; cur. Color++; } } if(pop(stackx, stacky, &r, &c, &top)==-1) break; } …… 8
영상경계의 추적 do void CWin. Test. Doc: : m_Border. Follow(int height, int width) { // 영역의 경계정보를 저장하기 위한 구조체 메모리 typedef struct tag. BORDERINFO{ short *x, *y; short n, dn; } BORDERINFO; BORDERINFO st. Border. Info[1000]; // 영상에 있는 픽셀이 방문된 점인지를 마크하기 위해 영상 메모리 할당 unsigned char *visited = new unsigned char [height*width]; memset(visited, 0, height*width*sizeof(char)); // 메모리 초기화 { // 관심점 주위에서 같은 칼라를 가진 경계점을 찾기 위함 for(k=0; k < 8; k++, n=((n+1) & 7)) // 01234567 { // 12345670 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(m_In. Img[u][v]==c 0) break; // 관심점의 주위를 돌다가 같은 밝기의 // 경계를 만나면 다음으로 추적할 점이 됨 } if(k == 8) break; // isolated point occurs visited[x*width+y]=255; // 방문한 점으로 마크 xchain[border_count]=x; ychain[border_count++]=y; // 추적점을 임시로 저장하기 위한 메모리 short *xchain = new short [10000]; short *ychain = new short [10000]; if(border_count>=10000) break; // 관심 픽셀의 시계방향으로 주위점을 나타내기 위한 좌표 설정 const POINT nei[8] = // clockwise neighbors { {1, 0}, {1, -1}, {0, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; x = x + nei[n]. x; y = y + nei[n]. y; if(n%2==1) diagonal_count++; // 01234567 n = (n + 5) & 7; // 56701234 } while(!(x == x 0 && y == y 0)); for(x=1; x < height; x++) { for(y=1; y < width; y++) { c 0=m_In. Img[x][y]; c 1=m_In. Img[x-1][y]; if (k == 8) continue; // isolated point occurs // 경계정보를 저장 if(border_count<10) continue; // 너무작은 영역의 경계이면 무시한다. st. Border. Info[number. Border]. x=new short [border_count]; st. Border. Info[number. Border]. y=new short [border_count]; if(c 0!=c 1&&c 0==(unsigned char)255 && visited[x*width+y]==0 ) //c 0!=c 1(경계이고) { border_count=0; // 경계점의 갯수를 세기 위한 카운터 diagonal_count=0; // for(k=0; k<border_count; k++) { st. Border. Info[number. Border]. x[k]=xchain[k]; st. Border. Info[number. Border]. y[k]=ychain[k]; } st. Border. Info[number. Border]. n=border_count; st. Border. Info[number. Border++]. dn=diagonal_count; x 0 = x; y 0 = y; n = 4; } } if(number. Border>= 1000) break; } 12
[Win. Test. View. cpp] void CWin. Test. View: : On. Bin. Labeling() { // TODO: Add your command handler code here CWin. Test. Doc* p. Doc = Get. Document(); // 다큐멘트 클래스를 참조하기 위해 ASSERT_VALID(p. Doc); // 인스턴스 주소를 가져옴 // 도큐멘트 클래스에 있는 재귀라벨링 함수 호출 p. Doc->grass_label(256, 256); } Invalidate(FALSE); //화면 갱신 [Win. Test. Doc. h] public: void grass(short* coloring, int height, int width, int i, int j, int cur. Color); void grass_label(int height, int width); 17
[Win. Test. Doc. cpp] void CWin. Test. Doc: : grass_label(int height, int width) { // 라벨링된 영상을 저장하기 위한 배열의 메모리 할당 short *coloring = new short [height*width]; int i, j, cur. Color=0; for(i=0; i<height*width; i++) coloring[i]=0; // 입력 영상의 라벨링 for(i=0; i<height; i++) { for(j=0; j<width; j++) { if(m_In. Img[i][j]==255 && coloring[i*width+j]==0) { cur. Color++; m_Blob. Pixel. Sum =0; grass(coloring, height, width, i, j, cur. Color); } } } void CWin. Test. Doc: : grass(short *coloring, int height, int width, int i, int j, int cur. Color) { int k, l, index; for(k=i-1; k<=i+1; k++) { for(l=j-1; l<=j+1; l++) { // 영상의 경계를 벗어나면 라벨링하지 않음 if(k<0 || k>=height || l<0 || l>=width) continue; } } } index = k*width+l; // 아직 방문하지 않은 픽셀이고 값이 255라면 라벨링함 if(m_In. Img[k][l]==255 && coloring[index]==0) { coloring[index] = cur. Color; m_Blob. Pixel. Sum++; grass(coloring, height, width, k, l, cur. Color); } float gray. Gap = 250. 0 f/(float)cur. Color; // 라벨링된 데이터를 m_Out. Img배열을 이용하여 화면출력 for(i=0; i<height; i++) { for(j=0; j<width; j++) { int value = (int)(coloring[i*width+j]*gray. Gap); if(value==0) m_Out. Img[i][j] = 255; else m_Out. Img[i][j] = value; } } } delete []coloring; // 메모리 해제 18
- Slides: 20