프로그래밍/영상처리

[별첨]소벨 마스크

산을좋아한라쯔 2017. 10. 15. 18:31
반응형

* Sobel Mask

Sobel Mask는 영상내 물체들에 대한 경계를 찾아낼 때 사용되는 대표적인 마스크로, 밝기에 대한 1차 미분값을 이용한다.

즉, 픽셀들이 있을 때 인접한 픽셀과의 1차 미분은 다음과 같이 인접 픽셀값과의 차(difference)로 근사값을 구할 수 있다. 

G(x) = f(x-1, y) - f(x,y)

G(y) = f(x, y-1) - f(x,y+1)


위와 같은 값이 되도록 하는 3 x 3 마스크는 다음과 같을 것이다. 

(입력영상과 마스크간의 컨볼루션 연산을 하게된다. 컨볼루션 연산이 무엇인지는 이 글 하단부 설명 참조)


세로 방향에 대한 마스크(X에 대한 변위)

1

0

-1

1

0

-1

1

0

-1


가로 방향에 대한 마스크(Y에 대한 변위) 

1

1

1

0

0

0

-1

-1

-1


이렇게 만들어진 마스크는 Prewit Mask이고, 여기에 중심부쪽에 좀 더 가중치둬서 경계선이 좀 더 명확하게 검출되도록 한 것이 Sobel Mask이다.  


[Sobel Mask]세로 방향에 대한 마스크(X에 대한 변위)

1

0

-1

2

0

-2

1

0

-1


[Sobel Mask]가로 방향에 대한 마스크(Y에 대한 변위) 

1

2

1

0

0

0

-1

-2

-1


* Sobel Mask에 대한 프로그래밍

3x3 마스크를 사용하는 경우, 입력영상의 가장 바깥쪽 상하좌우에 있는 픽셀들에 대해서는 계산하지 않는다.

그 외의 모든 픽셀에 대해서 컨볼루션 연산을 하게되기에 연산복잡도는 O(MN). <-- M x N 사이즈 이미지에 대해서


실제 코드를 보면, 세로쪽으로 1~(r-2) 까지, 가로쪽으로 1~(c-2)까지 for 루프를 돌며 해당 셀의 주변 3x3 매트릭스에 대해 Soble Mask와 컨볼루션 연산 진행.

CByteImage GetSobelImage(const CByteImage& img, double* mask) {

         int w = img.GetWidth();

         int h = img.GetHeight();

         int channel = img.GetChannel();

         int wStep = img.GetWStep();       

 

         ASSERT(channel == 1);     

        

         CByteImage outImg(w, h);

         BYTE* pIn = img.GetPtr();

         BYTE* pOut = outImg.GetPtr();

 

         int r, c;

         for (r = 1; r < (h - 1); r++) {

                  for (c = 1; c < (w - 1); c++) {

                           double sum = 0.0;

                           for (int y = 0; y < 3; y++) {

                                   for (int x = 0; x < 3; x++) {

                                            int py = r - 1 + y;

                                            int px = c - 1 + x;

 

                                            if (px >= 0 && px < w && py >= 0 && py < h)

                                                     sum += mask[y*3+x] * pIn[py*wStep+px];

                                   }

                           }

                          

                           pOut[r*wStep + c] = CLIP(sum + 128);

                           //pOut[r*wStep + c] = CLIP(sum);

                  }                

         }

         return outImg;

}   

컨볼루션 연산한 최종 값은 pOut에 들어가게 되는데, 이 때 sum값이 음수일 수도 있기에, 이 값을 표현해주기위해 128을 더해줬다. 


* 컨볼루션(Convolution) 연산

영상처리에 있어서 컨볼리션 연산은 "입력영상의 해당 화소에다가 주변화소들 각각의 가중치를 곱한 합을 반영하는 것"이라 할 수 있다. 여기서 주변화소들을 3x3, 5x5, 7x7 ... 등 홀수개의 매트릭스로 지정할 수 있고, 그 매트릭스의 값에 가중치를 부여할 수 있는데, 이렇게 만들어진 것이마스크가 된다.


예를 들어 아래 그림에서와 같이 왼쪽 입력이미지 A가 있고, 이에 대해 오른쪽 마스크 B가 있을 때, 둘 사이의 컨볼루션연산 결과는 다음과 같이 된다.

[X] [Y] [Z]

a

b

c

d

e

1

0

-1

A

B

C

D

E

f

g

h

i

j

*

1

0

-1

=

F

G

H

I

J

k

l

m

n

o

1

0

-1

K

L

M

N

O

p

q

r

s

t

P

Q

R

S

T


A=a, B=b, C=c, D=d, E=e, F=f, J=j, K=k, O=o, P=p, Q=q, R=r, S=s, T=t  //경계선의 경우 계산안하는 것으로 함

G = a - c + f - h + k - m

H = b -d + g - i + l - n

I = c - e + h - j + m - o

...


g라는 픽셀값을 예를 들어 설명해보면, g를 포함한 주위에 있는 3x3 행렬값과, [Y]마스크의 해당 위치값을 곱한 후 모두 더하면, 컨볼루션에 의한 [Z]의 G위치 값이 된다. 즉 G = ax1 + bx0 + cx(-1) + fx1 + gx0 + hx(-1) + kx1 + lx0 + mx(-1) = a - c + f - h + k - m


이러한 연산을 입력영상의 모든 화소값에 대해 수행해서 [Z]값을 만들어내게 된다.




-끝-

반응형