[별첨]소벨 마스크
* 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]값을 만들어내게 된다.
-끝-