Matlab을 이용한 영상처리 - 4. 양자화와 디더링

Programming/Image Processing 2010. 8. 25. 16:00

1. 양자화

GrayScale 에서, 대부분 256 색을 가지고있다. 이 색은 인간이 인식가능한 대부분의 색을 표현하는 데 무리가 없다. 그런데 ,만약 표현가능한 색이 256보다 제한되있다고 한다면 ?

양자화는 이런 제한사항을 가진 이미지를 만든다 .

매우 간단하게 2가지 색만 가진다고 한다면, 다양한 이미지에 적용될 수 있는 간단한 이분법은 중간값(256에선 128)을 기준으로 그 이하의 값을 가진 픽셀은 0 으로 , 그 값을 초과하는 픽셀은 1로 표시 할 수 있다.

f = floor(double(Image)/d);
와 같이 나누고
q = uint8(f*d);
를 통해 디스플레이에 좋은 값으로 스케일링해 표시 할 수 있다.
( 단순히 나눠 뿌리기만하면 d개의 다른 색이 표현되긴 하겠지만 인간이 인지할 수 없는 차이의 색이 선택될 것이다.)

그러나 영상처리에 관한한 아주 Powerful한 기능을 제공하는 Matlab은 보다 적합한 하나의 함수를 만들어 놓았다.
 
grayslice(Image,d)를 이용하여 d개의 그레이를 만들고,
gray(d)를 이용하여 디스플레이에 좋게 스케일링한다.

지루한 이론 설명은 이쯤하고 소스와 실행결과를 살펴보자.


중요한건 7번 라인이다. 앞에서 장황하게 늘어놓았던건 다 이 하나의 라인을 설명하기 위한 것이었다.

Figure 1. 양자화 결과

2개의 스케일 (흰색,검은색) 만을 가지기 때문에 이진영상과 같은 결과가 나왔다.
4개의 스케일을 가지게 하면 ,


하늘(흰색), 뒤쪽산(연한 회색) , 앞산(진한 회색) , 나무(검은색) 들이 4가지 색으로 표현 되었다.

2. 디더링

뭐 나름 이런 이미지도 분위기 있고 좋지만, 색상이 제한되어 있다 하더라도 이미지를 그자체로 느끼기가 너무 어렵다 !

필자가 만화를 좋아하므로 , 만화책을 생각해보자!
요새는 만화책 원고 작업도 디지털화되어서 잘은 모르겠지만, 가까운 몇년전만해도
색을 표현해야할때 톤을 붙이는 것이 일반적이었다.
기억나는지 ? 톤은 흰색과 검은색밖에 없지만 , 진한 부분은 검은 점이 잦게 찍혀있었고, 그렇지 못한 부분은 검은점이 드물게 찍혀있었다.
필자가 초등학생땐, 만화-라긴 민망하고 낙서에 가까웠다-를 그릴때 톤처럼 표현하겠다고 모나미 펜으로 일일히 점을찍기도......

쨌든!
요는 , 제한 된 개수의 색에서도 색을 좀 더 다채롭게 표현하는 이 '톤'의 기법이 Dithering 이다.

표준 디더링 매트릭스 D = [ 0 128 ; 192 64 ] 를 이용하여 디더링해보자!


13번 라인: repmat - 아마도 repeat matrix의 abbreviation? D 매트릭스를 128 X 128 개 갖는 매트릭스를 생성한다.
14번 라인: g는 grayImage이고, 매트릭스끼리의 비교는 동일한 인덱스끼리 이루어진다. 비교 대상 픽셀의 값이 계속해서 바뀌기 때문에 값이 같은 픽셀끼리도 다른 색이 될 수 있다. 하지만 상대적으로 밝은 부분은 아무리 인덱스가 바뀌어도 대부분 하얀색을 유지할것이며, 그렇지 않은 부분은 검은색을 유지하는데, 이 비교대상 픽셀값의 변경으로 '톤'과 같은 효과를 낼 수가 있다.

Figure 2. 디더링 결과


Figure 1과 같이 사실은 이진영상이지만 , 비교적 다채로운 색상이 표현되었다!

Matlab을 이용한 영상처리 - 3. 비트평면과 공간 분해능

Programming/Image Processing 2010. 8. 25. 01:33


비트평면에 대해서도 이미지를 첨부할까 했지만 본인의 귀차니즘으로인해 .. -ㅅ-
글로만 정리하게 될 것 같다. 자주 사용되는 기능은 아닌것 같으니 ( 뭐 Most significant bit는 영상의 또렷함?을 강조하기위해 사용될 수도 있을거 같긴하다!)..

1. bit plane

grayscale 영상은 비트평면(bit plane)으로 분리, 2진 영상의 수열로 변환할 수가 있다.
각 화소의 그레이 값이 8비트의 2진 워드일때, 최하위 비트(0번째)는 이미지에 가장 영향을 적게 미치는, 자주 변하게 되는 값일 것이며, 최상위 비트(7번째)는 가장 큰 영향을 미치는 비트일 것이다.
- 이 말이 잘 와닿지 않는가 ?  숫자 128 을 생각해보자. 128에서 가장 영향이 큰 숫자는 당연히 최상위 10진 비트 , 1( 이 예에서 숫자 8의 자리수의 100배의 영향 ) 의 값을 가진 100의 자리다. -

grayscale 이미지 g에서 , mod를 이용해 나머지를 얻어낼 수 있으며, floor를 통해 내림효과를 낸다.
이를 조합해 최상위비트(7번째)의 비트 평변을 얻어내는 소스는 다음과 같다

g7 = mod(floor(g/128),2);



2. 공간 분해능


Line 4 : 같은 이미지를 불러왔다.
Line 6 : GrayScale화.
Line 7 : 공간분해능 
 이 부분이 공간 분해능의 Core이다. nested imresize의 형태를 취하고 있는데, 첫번째(안쪽)의 imresize는 먼저 이미지를 1/16로 축소를 한다.

이 작업을 설명하기 위해 단순화 시킨 예를 먼저 생각해보자.

W(1,1)  W(1,2)  W(1,3)  W(1,4)  ....
W(2,1)  W(2,2)  W(2,3)  W(2,4)  ....
W(3,1)  W(3,2)  W(3,3)  W(3,4)  ....
W(4,1)  W(4,2)  W(4,3)  W(4,4)  ....

위 배열은 순서쌍을 인덱스로 하여 Matrix W를 나열한 것이다.
만약 imresize(W,1/2) 를 수행하면 위 Matrix는

W(1,1)  W(1,2)  W(1,3)  W(1,4)  ....
W(2,1)  W(2,2)  W(2,3)  W(2,4)  ....
W(3,1)  W(3,2)  W(3,3)  W(3,4)  ....
W(4,1)  W(4,2)  W(4,3)  W(4,4)  ....

색깔이 칠해진 배열만을 선택하여 출력하게 된다. 4 X 4 에서 색칠한 배열은 정리하면 2 X 2 가 되니 뭐 그럭저럭 원하는 대로 축소된 셈이다.

이 이미지를 다시 imresize(W,2)를 통해 2배 확대를 하면 어떻게 되는가 ?
축소전의 W(1,1) W(1,2) 등은 복구가 불가능하다.
때문에 확대시에는

W(2,2)  W(2,2)  W(2,4)  W(2,4)  ....
W(2,2)  W(2,2)  W(2,4)  W(2,4)  ....
W(4,2)  W(4,2)  W(4,4)  W(4,4)  ....
W(4,2)  W(4,2)  W(4,4)  W(4,4)  ....

와 같이 남은 인덱스를 그 자승만큼의 수가 될 수 있도록 복사한다.
때문에 출력된 이미지는 모자이크와 같은 이미지가 된다.

Figure 1. 공간분해능 실행결과



생각보다 Blurring에 가까워 졌다 .. 왜지 ? ㅡㅡ 이렇게 하면 이론상으론 모자이크에 가까워야하는데 . .
아무튼 저 이론은 맞다. 원인을 파악하는대로 수정하겠다. (무책임..)

Matlab을 이용한 영상처리 - 2. Matlab의 기본

Programming/Image Processing 2010. 8. 25. 00:43

2 학년때 Matlab기본 조작법을 선형대수학 시간에 알려줬었지만, 사실 실제로 실습을 한 것도 아니고 ..
제대로 사용해 보는 것도 이번이 처음이다.

때문에 내 의지와 상관없이 아주 기본부터 해보았다..
불행히도 나는 하이라이트 기능 사용법을 모르기 때문에 (ㅠ_ㅠ) 스크린샷을 일일히 찍었다.


첫 소스답게 짧다. 하지만 의외로 많은 것이 이루어져있다.
C 나 Java에서 이만한 작업을하려면 , 먼저 이미지를 불러오는데만 3~5라인, (CreateBitmap, DrawBitmap...) 픽셀을 받아오는데만 수십 라인... (Java , 안드로이드에서는 그래도 함수하나로 해결이 된다)그리고 조작에 for문 등의 삽질이 들어가는데 .. 아주 편하다.

짧지만 이미지 크기 조정도 해보고, grayscale로도 만들어보고, 밝기조절(?)도 해보고 이진화도 되었다. 평균 2라인.. 이래서 영상처리는 Matlab을 하라고 하는가 보다.

아무튼, Line by line으로 짚고 넘어가보자.
먼저 첫번째 라인 w = imread('img_0605.jpg'); Image read의 약어(Abbreviation) 이다.
현재 폴더(Matlab의 작업환경)에서 이미지를 읽어와 w 변수에 저장, resize를 통해 250 x 250의 크기로 조정하였다.

figure를 통해 새창을 띄우고, 그 새창에 image를 보여준다(show)  여기서 콤마(,)는 그저 한 작업이 끝났음을 표기한 것이다. (한 라인에 표기하기 위해. 콤마가 없을때는 에러가 발생한다. 콤마없이 쓰고싶다면 엔터키를 살포시 눌러주자)
이를 세미콜론(;)과 혼동할 가능성이 있는데, Matlab에서 세미콜론은 조금 특별한 의미가 있다.

; 표기시, 실행결과를 보여주지 않는다. 만약 1번째나 2번째 라인에서 ;이 표기 되지 않고 한줄이 끝났다면, w 의 사이즈 만큼의 Matrix가 Command Window에 출력된다. 이 Matrix의 수치값은 지금 당장 필요치 않기때문에 ;을 넣어주었다.

3번 라인까지의 실행결과는 다음과 같다. Figure 1 : 원본이미지


9번라인이 현재 주석처리가 되어있다. 머리에 붙어있는 %를 떼고 실행하면 Figure 2가 짜잔하고 나타난다. RGB 형태인 원본이미지 w를 함수(rgb2gray)를 사용, 간단하게 grayscale화 시켰다.


Figure 2 : GrayScale


11번 라인을 보자. w를 double형으로 변환시켜 d 변수에 저장했다.
Matrix d의 어떤 픽셀은 125.00 일 수도 있고, 255.00 일 수도 있다. 그런데 imshow 함수는 double형을 출력 할때 0~1의 범위내에서만 색상을 표현한다. 그럼 125.00인 픽셀과 255.00인 픽셀은 어떻게 될까?
1로 간주 된다. 1은  흰색으로 약속되어 있기 때문에 , 125도 255도 , 1도 흰색이 되어 원하는 이미지를 얻기는 어렵다.

그럼 double형의 이미지를 제대로 출력하려면 어떻게 해야 할까 ?
간단하다. d를 /255로 나눈 몫을 이용하면 된다. 12라인과 같이 매트릭스에 /x 를 연산하면 매트릭스의 모든 값이 /x연산을 수행한 결과가 되기 때문에 올바르게 분포된 0~1사이의 이미지를 얻을수 있다.

11번라인은 /255 대신에 128을 수행하였다.
128로 나누면 범위가 0~2임을 의미하고, 여기서 1~2는 흰색으로 디스플레이 되므로
그 결과는 원본 이미지보다 밝게 나타나게 된다.

Figure 3. 밝은 이미지
 

15번 라인을 보자. grayscale 이미지중 100보다 큰 값은 참 (1)이 된 Matrix를 b에 저장하였다.
나머지는 거짓(0)이 되므로 1과 0 두값만 가지게 되며, 따라서 이미지는 이진화가 된다.

Figure 5 . 이진화


Matlab에 대한 기본적인 문법설명 또한 첨부되다보니 분량이 많이 늘었다.
그래도 이미지가 들어가니 이제 좀 영상처리에 대한 포스팅 다워졌다.

다음 글은 비트평면과 공간분해능(모자이크)에 대해 알아본다.