디지털영상처리 실습 : 히스토그램 방송영상미디어과 히스토그램 (Histogram) 히스토그램이란? n 디지털영상을구성하는화소는명도값을나타내는데어떤명도값을가진픽셀수가몇개있는가를나타내는함수 n 화소의명도값은 0~255 인데각명도값에해당하는화소의수를나타내는함수 히스토그램구하는방법 4 4 3 3 픽셀갯수 6 5 <Histogram> 4 4 3 3 4 1 2 3 2 2 0 1 2 3 1 <Image> 0 1 2 3 4 5 6 명도 1
히스토그램구하기 사전준비 : 히스토그램을저장할메모리가필요함 필요한메모리개수 à 전체영상의픽셀은그값이 0 ~ 255이므로 256 개의메모리필요함 영상을구성하는픽셀의개수는매우크므로메모리형식은 unsigned long으로해야함 ( unsigned 란 +/- 를고려하지않는다는의미 ) 형식 표현가능범위 unsigned char 0 ~ 255 unsigned int 0 ~ 65,535 unsigned long 0 ~ 4,294,967,295 히스토그램을저장하는메모리를마련함 unsigned long Histo[256]; memset(histo, 0, sizeof(unsigned long) * 256); 256 개의메모리를선언함 256 개의메모리를 0 으로청소함 대상메모리명 메모리에채울수 unsigned long 한개가차지하는바이트수 x 메모리수 히스토그램구하기 영상픽셀값과히스토그램의관계 픽셀값 : 171 픽셀값 : 169 메모리내용 1 증가 (+1) 메모리내용 1 증가 (+1) à 메모리는 0 부터시작하므로결국해당픽셀의수를카운트... Histo[167] Histo[168] Histo[169] Histo[170] Histo[171] Histo[172] Histo[173] Histo[174]... 2
히스토그램구하기 void CDibView::OnHistogram() { // TODO: Add your command handler code here CDibDoc* Doc = GetDocument(); HDIB hdib = Doc->GetHDIB(); if (hdib == NULL){ MessageBox("Fail to oen the Image", NULL, MB_OK); return; LPSTR ldibhdr = (LPSTR) ::GlobalLock((HGLOBAL) hdib); int cxdib = (DWORD) ::DIBWidth(lDIBHdr); int cydib = (DWORD) ::DIBHeight(lDIBHdr); int rwidth = ((int)cxdib + 3)/4*4; LPSTR ldibbits = ::FindDIBBits(lDIBHdr); int i, j; unsigned long Histo[256]; memset(histo, 0, 256*sizeof(unsigned long)); for(j=0; j<cydib; j++){ for(i=0; i<cxdib; i++){ int idx; idx = ((int)*(ldibbits + rwidth*j + i)) & 0x00ff; Histo[idx]++; 실제영상의히스토그램을구하기위해서는영상의모든픽셀을읽어야한다. 2 중 FOR 문을사용하여영상의가로, 세로를통해모든데이터를읽어낸다. 실제영상에서의히스토그램은명암이 256 레벨이므로배열도 256 개마련. memset() 으로메모리를 0 으로모두청소 idx 에영상의명도값을입력시킨후 idx 에해당하는배열값을 1 증가시킨다. Invalidate(TRUE); 히스토그램구하기 : 실습 (1) 메뉴항목추가 (3) 마우스우클릭 (5) CDibView 선택 (4) Add Event Handler 선택 (2) ID 변경 (6) Add and Edit 클릭 3
히스토그램구하기 : 실습 히스토그램을그래프로나타내려면복잡하고난이도높은작업필요메모리에올바른히스토그램데이터가채워졌는지알아보는방법으로대체 à 디버거 (Debugger) 사용에의한메모리검사방법 (2) Debug à Start Debuggin 클릭 (3) 프로그램이실행되며비트맵영상을열면됨 (1) Sto oint를설정 à 프로그램영역좌측에커서가형태로바뀌면클릭함 히스토그램구하기 : 실습 (1) 히스토그램을클릭 (2) Visual Studio 로돌아옴 (3) Sto Point 에서멈춤 à 노란색 가정지점을알려줌 (4) Locals 탭을선택하면메모리를볼수있음 à Histo 의앞 + 클릭 4
히스토그램구하기 : 실습 우측스크롤바를아래로내리면더많은히스토그램을볼수있음 기본명암대비스트레칭 히스토그램의최소값 MIN 과최대값 MAX 를구하는알고리즘으로표현하면다음과같음 BYTE MIN=255, MAX=0; int i, j; for(j=0; j<cydib; j++){ for(i=0; i<cxdib; i++){ BYTE tm; tm = *(ldibbits + i + j*rwidth); if(tm <= MIN) MIN = tm; for(j=0; j<cydib; j++){ for(i=0; i<cxdib; i++){ BYTE tm; tm = *(ldibbits + i + j*rwidth); if(tm >= MAX) MAX = tm; ( 다음페이지에이어짐 ) 5
기본명암대비스트레칭 MIN, MAX 값을이용한 Contrast Stretching 알고리즘은다음과같음 for(j=0; j<cydib; j++){ for(i=0; i<cxdib; i++){ int TMP; TMP = (int)((*(ldibbits + i + j*rwidth)&0x00ff); TMP = (TMP MIN)*255 / (MAX-MIN); //stretching if(tmp < 0) TMP = 0; // 계산값이초과되면제한 if(tmp > 255) TMP = 255; // 계산값이초과되면제한 *(ldibbits + i + j*rwidth) = (BYTE) TMP; 기본명암대비스트레칭 : 실습 (1) 점처리 항에 스트레칭 추가 (2) ID 항목에 ID_STRETCH 추가 (4) CDibView 선택 (3) 스트레칭 우클릭 à Add Event Handler 선택 (5) Add and Edit 선택 6
기본명암대비스트레칭 : 실습 새롭게추가된부분 기본명암대비스트레칭 : 실습 명암대비스트레칭결과 7
기본명암대비스트레칭 : 엔드 - 인 엔드-인 (end-in) 탐색기법의도입 : 모든범위의명도값을가짐에도불구하고화소의대부분이특정값에몰려있는경우 à 최저와최고명도값주의에는히스토그램이거의없음이경우화질을향상시키는방법이엔드-인탐색기법임 기본명암대비스트레칭 : 엔드 - 인 for(j=0; j<cydib; j++){ for(i=0; i<cxdib; i++){ int TMP; TMP = (int)((*(ldibbits + i + j*rwidth)&0x00ff); TMP = (TMP MIN)*255 / (MAX-MIN); //stretching 엔드 - 인기법도입한알고리즘 if(tmp < 0) TMP = 0; // 계산값이초과되면제한 if(tmp > 255) TMP = 255; // 계산값이초과되면제한 *(ldibbits + i + j*rwidth) = (BYTE) TMP; for(j=0; j<cydib; j++){ for(i=0; i<cxdib; i++){ int TMP, min, max; min = (int)min; max = (int)max; TMP = (int)((*(ldibbits + i + j*rwidth)&0x00ff); if(tmp <= min) TMP = 0; els if(tmp >= max) TMP = 255; else TMP = (TMP min)*255 / (max - min); //stretching if(tmp < 0) TMP = 0; // 계산값이초과되면제한 if(tmp > 255) TMP = 255; // 계산값이초과되면제한 *(ldibbits + i + j*rwidth) = (BYTE) TMP; 8
히스토그램평활화의 3 단계 1 단계 : 영상의히스토그램 Histo[j] 를구함 2 단계 : 각명도에대해서그때까지의히스토그램의합즉누적히스토그램을구함 3 단계 : 누적히스토그램을정규화함 n[i] : 정규화된히스토그램 N : 영상의총픽셀수 Imax: 영상의최고명도값 히스토그램평활화를적용한영상 콘트라스트가나쁜영상 히스토그램균일화된영상 < 좁은명도분포 > < 확대개선된명도분포 > 9
히스토그램평활화를적용한영상 히스토그램평활화 : 실습 1) Histogram 을구한다 : for(j=0;j<cydib;j++){ for(i=0;i<cxdib;i++){ int idx = *(ldibbits + rwidth*j + i] & 0x00ff; Histo[idx]++; 2) ScaleFactor 를구한다 : TotalPixel = (long)cydib * (long)cxdib; ScaleFactor = 255./TotalPixel; 3) 누적 Histogram 을구한후 ScaleFactor 로곱하여균일화한다 : for(i=0;i<256;i++){ Sum += Histogram[i]; Sum_Hist[i] = (Sum * ScaleFactor) +0.5; if(sum_hist[i] >=255) Sum_Hist[i] = 255; else if(sum_hist[i]<=0) Sum_Hist[i] = 0; 4) 균일화된값으로새영상을만든다 : for(j=0;j<cydib;j++){ for(i=0;i<cxdib;i++){ int tm = *(ldibbits + rwidth*j + i) &0x00ff; *(ldibbits + rwidth*j + i) = (BYTE)(Sum_Hist[tm]); 10
히스토그램평활화 : 실습 (1) (2) (4) (3) (5) 히스토그램평활화 : 실습 히스토그램구하는부분에서추가된부분 11
히스토그램평활화 : 결과 12