1
2
3
4
5
6
7
8
9
// 알고리즘 3-3 캐니 에지 검출(스케치버전)
//입력 : 영상 f(j,i), 0≤ j ≤ M-1, 0 ≤ I ≤ N-1, 가우시안의 편차
//출력 : 에지 영상 e(j,i), 0 ≤ j ≤ M-1, 0 ≤ I ≤ N-1 // 에지는 1, 비에지는 0인 이진 영상
입력 영상 f에 σ 크기의 가우시안 스무딩을 적용한다.
결과 영상에 소벨 연산자를 적용하여 에지 강도와 에지 방향 맵을 구한다.
비최대 억제를 적용하여 얇은 두께 에지 맵을 만든다.
이력 임계값을 적용하여 거짓 긍정을 제거한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//알고리즘 3-4 캐니 에지 검출
//입력 : 영상 f(j,i), 0<=j<=M-1, 0<=i<=N-1, 가우시안의 표준편차 σ, 이력 임계값 Thigh, Tlow
//출력 : 에지 영상 e(j,i), 0<=j<=M-1, 0<=i<=N-1 // 에지는 1, 비에지는 0인 이진 영상
// f에 크기 σ인 가우시안을 적용하여 g를 얻는다.
// g에 소벨 연산자를 적용하여, 에지 강도맵 S와 에지 방향 맵 D를 얻는다. // D는 8-방향 양자화
//5~9행:비최대 억제
for(y=1 to M-2)
for(x=1 to N-2){
(y1,x1)과 (y2,x2)를 (y,x)의 두 이웃 화소라 하자. // [그림 3-17] 참고
if(S(y,x)<=S(y1,x1) or S(y,x)<=S(y2,x2)) S(y,x)=0; //비최대 억제
}
//12~16행:이력 임계값을 이용한 에지 추적
e(y,x) = 0, 0<=y<=M-1,0<=x<=N-1;
visited(y,x)=0,0<=y<=M-1,0<=x<=N-1; // 모든 화소가 아직 방문 안됨을 표시
for(y=1 to M-2)
for(x=1 to N-2)
if(S(y,x)>Thigh and visited(y,x)=0) follow_edge(y,x);
// 에지를 추적하는 재귀함수(배열은 모두 전역변수라 가정)
function flow_edge(y,x) {
visited(y,x) = 1; // 방문했음을 표시
e(y,x) = 1; // 에지로 판정
for(y,x)의 8이웃 (ny,nx) 각각에 대해)
if(S(ny,nx>Tlow and visited(y,x)=0) follow_edge(ny,nx)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//알고리즘 3-5 SPTA(껍질을 한 번 벗기는 연산)
//입력 : 에지 영상 e(j, i), 0 ≤ j ≤ M - 1, 0 ≤ i ≤ N - 1 // 에지는 1, 비에지는 0인 이진 영상
//출력 : 한 두께 얇아진 에지 영상 eout(j, i), 0 ≤ j ≤ M - 1, 0 ≤ i ≤ N - 1
e를 eout에 복사한다.
for (j = 1 to M - 2)
for (i = 1 to N - 2) {
if (e(j, i) = 1 and
((n0' and(n4 and(n5 or n6 or n2 or n3) and (n6 or n'7) and (n2 or n'1))) // n0=비에지, s0=참
or (n'4 and (n0 and (n1 or n2 or n6 or n7)and(n2 or n'3) and (n6 or n'5))) // n4=비에지, s4=참
or (n'2 and(n6 and(n7 or n0 or n4 or n5)and(n0 or n'1) and (n4 or n'3))) // n2=비에지, s2=참
or (n'6 and (n2 and (n3 or n4 or n0 or n1)and(n4 or n'5) and (n0 or n'7))))) // n6=비에지, s6=참
eout(j, i) = 0;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//알고리즘 3-6 에지 토막 검출
//입력 : 에지 영상 e(j, i), 0 ≤ j ≤ M - 1, 0 ≤ i ≤ N - 1
//출력 : segment(k), 1 ≤ k ≤ n(n개의 에지 토막)
Q = Φ; // 큐를 생성하고 공집합으로 초기화
for (j = 1 to M - 2)
for (i = 1 to N - 2) {
(j, i)의 전환 횟수를 세어 c라 한다.
if (c = 1 or c >= 3) // 끝점 또는 분기점
for (dir = 0 to 7) // 8-방향을 조사하여 추적 방향을 정하고 큐에 저장
if (dir 방향의 이웃 화소(y, x)가 e(y, x) = 1) addQueue(Q, (j, i, dir));
}
// 큐에 들어있는 요소에서 에지 추적을 시작(에지 토막 추적 시작)
n = 0; // 에지 토막의 개수
visited(j, i) = 0, 0 <= j <= M - 1, 0 <= i <= N - 1; // 이중 추적을 방지하기 위해 사용(방문하면 1로 바꿈)
while (Q≠Φ) {
(y, x, dir) = popQueue(Q);
(y, x)의 dir방향의 이웃을(cy, cx)라 하자.
if visited(cy, cx) continue; // 반대쪽에서 이미 추적했음.
n++;
segments(n)을 생성하고(y, x)와(cy, cx)라 하자.
visited(y, x) = visited(cy, cx) = 1; // 방문했음을 표시
if ((cy, cx)가 끝점 또는 분기점) continue; // 두 점으로 구성되는 짧은 에지 토막임
while (true) {
(cy, cx)의 dir 방향의 전방 화소를 조사한다. // [그림 3-26]에서 f 표시된 화소들
if (끝점 또는 분기점(y, x)가 있으면) {
segments(n)에(y, x)를 추가한다.
visited(y, x) = 1;
break; // segments(n)의 추적이 끝났음
}
else { // 전환 횟수가 2인 통과점
전방 화소 중 e(y, x) = 1인 화소를 찾는다.
segments(n)에(y, x)를 추가한다.
visited(y, x) = 1;
dir을(cy, cx)에서(y, x)로 진행하는 방향으로 갱신하다.
(cy, cx) = (y, x); // 앞으로 이동
}
}
}


출처 - Computer Vision