라즈베리파이에서 Processing을 이용한 영상처리- 히스토그램 평활화

메카 2017-04-03 (월) 13:43 4년전 2846  

5.3 히스토그램 평활화

 

5.2 절에서 설명한 것처럼 히스토그램은 영상이 가지는 밝기 분포도를 알 수 있다. 만약 히스토그램이 0~50사이에 분포한다면 어두운 영상이 될 것이며(그림 5-5 (c)), 150~255사이에 분포한다면(그림 5-5 (b)) 아주 밝은 영상이 될 것이다. 이렇듯 영상의 밝기 값 분포를 이용하여 영상을 분석할 수 있으며, 좋지 않은 밝기 값을 가진 영상도 향상시킬 수 있다. 발기 값의 분포가 한쪽으로 치우치거나 균일하지 못한 영상은 히스토그램 평활화를 통해서 명암값의 분포가 균일한 영상으로 향상될 수 있다. 다시 말하면 히스토그램 평활화는 한곳에 집중된 밝기 값을 펼쳐서 밝기 값이 균일한 분포가 되도록 밝기 값의 분포를 재배치하는 것이다.

히스토그램 평활화는 다음과같이 3단계를 거친다.

1) 히스토그램을 생성한다.

2) 히스토그램의 정규화된 합을 계산한다.

3) 입력 영상을 정규화된 축적 히스토그램을 그레이스케일 사상함수를 이용하여 그레이 레벨값을 맵핑한다.

첫 번째 단계는, 영상에서의 화소의 밝기 값을 카운트 하는 것이다. 예를 들면, 밝기 값 0이 몇 개인지, 밝기 값 150이 몇갠이지, 밝기 값 255가 몇 개인지, 빈도수를 조사하는 것이다.

두 번째 단계는, 첫 번째 단계에서 구한 값을 계속 더해 나가 축적하는 방법이다. 즉 새로운 배열 요소 1은 히스토그램의 요소 01의 합을 포함하는 것이다. 이 배열 요소 2550~255까지의 히스토그램 모든 요소를 포함하는 것이다.

첫 번째 단계부터 세 번째 단계까지 과정을 그림 5-6에 나타내었다

 

02c7232450ce0f92271d32085c8e4707_1491194
                        (a)
02c7232450ce0f92271d32085c8e4707_1491194
                          (b)

02c7232450ce0f92271d32085c8e4707_1491194
                            (c)

[그림 5-6] 히스토그램 평활화 예제; (a) 원영상의 데이터와 히스토그램, (b) 평활화의 정규화, (c) 평활화 영상의 데이터와 히스토그램 

 

[실습5-6] 히스토그램 평활화

a) 소스코드 및 결과 영상

 size(1285, 980);

background(255);

 

PImage img = loadImage("darkImage.jpg");

PImage equal_img = createImage( img.width, img.height, RGB );

image(img, 0, 0);

 

int[] hist = new int[256];

int[] sum_hist = new int[256];

float factor=0;

int sum=0;

 

for (int y = 0; y < img.height; y++) {

for (int x = 0; x < img.width; x++) {

int bright = int(brightness(get(x, y)));

hist[bright]++;

}

}

 

int histMax = max(hist);

 

for (int i = 0; i < img.width; i += 2) {

int which = int(map(i, 0, img.width, 0, 255));

int y = int(map(hist[which], 0, histMax, img.height, 0));

line(img.width+i, img.height, img.width+i, y);

}

 

factor=(255.0)/(img.width*img.height);

 

sum=0;

for(int i=0;i<256;i++){

sum+=hist[i];

sum_hist[i]=sum;

}

 img.loadPixels();

for (int y = 0; y < img.height; y++) {

for (int x = 0; x < img.width; x++) {

int pos = y*img.width+x;

color c = img.pixels[pos];

int val=int(brightness(c));

int new_val=(int)(sum_hist[val]*factor+0.5);

equal_img.pixels[pos] = color(new_val);

}

}

equal_img.updatePixels(); 

 

line(640, 479, 1280, 479);

line(640, 480, 1280, 480);

textSize(20);

fill(0, 0, 0);

text("0", 640, 500);

text("255", 1247, 500);

 

image(equal_img,0,500);

 

int[] new_hist = new int[256];

 

equal_img.loadPixels();

for (int y = 0; y < equal_img.height; y++) {

for (int x = 0; x < equal_img.width; x++) {

int pos = y*equal_img.width+x;

color c = equal_img.pixels[pos];

int bright=int(brightness(c));

new_hist[bright]++;

}

}

int new_histMax = max(new_hist);

 

for (int i = 0; i < equal_img.width; i += 2) {

int which = int(map(i, 0, equal_img.width, 0, 255));

int y = int(map(new_hist[which], 0, new_histMax, equal_img.height, 0));

line(equal_img.width+i, 500+equal_img.height, equal_img.width+i, y+500);

}

equal_img.loadPixels();

 

02c7232450ce0f92271d32085c8e4707_1491194 

[그림 5-6] 히스토그램 평활화 코드 및 결과 영상; 위 영상 - 히스토그램 평활화 전 영상 및 히스토그램, 아래 영상- 히스토그램 평활화 후 영상 및 히스토그램

 

b) 코드 설명

이번 실습에서는 setup()함수와 draw()함수를 사용하지 않고 히스토그램 평활화를 구현했다. 입력 영상에 대한 히스토그램과 히스토그램 평활 후의 영상과 히스토그램을 그림 5-6에 나타내었다. 설명에서처럼, 첫 번째로 전체 영상에 대한 히스토그램을 hist[]배열 변수에 저장한다. 정규화를 구하기 위해 식 (255.0)/(img.width*img.height)을 사용하였다. 두 번째는 히스토그램 누적합을 구하여 sum_hist[] 배열에 저장하였다. 픽셀을 다루어야 하므로 loadPixels() 함수를 이용하였다. 세 번째는 원래의 영상과 정규화된 합의 히스토그램 매핑 과정으로써, 최종적으로 매핑된 결과 값 new_val값을 새로운 영상 equal_img.pixels[]에 저장하였다. 그림 5-6의 결과처럼 원래의 영상보다 훨씬 개선된 영상을 확인 할 수 있다. 

 

 

메카리워즈 Image Map


모바일 버전으로 보기