에지 검출

nugurii0·2022년 9월 23일
0

다중차로인식

목록 보기
6/11

에지(edge)란 픽셀 값이 급격하게 변경되는 부분이다.

픽셀 값의 급격한 변화는 픽셀 값의 변화율이 크다고 볼 수 있고 이를 미분을 통해 구해 사용할 수 있다.

쉽게 생각해서 edge 뜻 그대로 경계나 가장자리, 즉 윤곽선을 구별하기 위해 사용한다.

픽셀이 급격하게 변한다? → 색상, 명암 등이 변하는 경계 == 영역과 영역을 구별하는 윤곽선

미분과 그래디언트

미분

중앙 차분을 이용하는 것이 이론적으로 근사화 오류가 가장 적기 때문에 중앙 차분을 사용한다.

Untitled

xi+1 대신 x+h, xi-1 대신 x-h로 쓰기도 한다.

영상은 2차원 행렬이기 때문에 가로 방향, 세로 방향을 각각 미분해야 한다.

즉 편미분을 사용하여 근사화하여 사용한다.

예를 들어 x축 방향으로 편미분하면 변화량 행렬이 결과물로 나온다. 이는 y축은 고정한 채 인접한 x축의 픽셀끼리 값을 대조하여 변화량을 표시한 것이다.

영상은 2차원 공간이므로 x축 방향과 y축 방향의 편미분을 모두 사용하여 에지를 검출하는 것이 정확하다.

그래디언트

2차원 공간에서 x축, y축 방향 미분을 한꺼번에 벡터로 표현한 것을 그래디언트라고 한다.

그래디언트는 벡터이므로 크기와 방향 성분으로 표현할 수 있다. 그래디언트의 방향은 변화 정도가 가장 큰 방향이고, 벡터의 크기는 변화율의 세기이다.

그래디언트 벡터의 방향과 수직인 방향을 에지의 방향이라고 부른다.

마스크 기반 에지 검출

소벨 필터 마스크

실제 영상에서 처리를 진행할 땐 잡음이 다량 포함되어 있기 때문에 잡음의 영향을 줄이기 위해 큰 크기의 마스크를 이용한다. 그 중 가장 많이 사용되는 미분 마스크는 소벨 필터(Sobel filter) 마스크이다.

소벨 필터 마스크는 3*3 크기로, x축 방향 미분 마스크의 경우 현재 행에 대해 중앙 차분 연산을 2회, 이전 행과 다음 행에 대해서도 중앙 차분 연산을 1회씩 수행한다.

이는 현재 행과 이웃 행에서의 픽셀 변화가 유사하다는 점을 이용한 것으로 잡음의 영향을 줄이기 위함이다. 특히 현재 행에 대하여 2회 연산을 적용하는 것은 더 큰 가중치를 주기 위함이다.

OpenCV 라이브러리에서는 다음과 같이 구현되어 있다.

void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy,
						int ksize=3, double scale = 1, double delta = 0,
						int borderType = BORDER_DEFAULT);

dx, dy는 각 방향의 미분 차수이다. x방향으로 편미분 하려면 (dx,dy)=(1,0)이 된다.

ksize는 ksize3, 3ksize 크기의 마스크를 사용한다는 의미이다.

scale, delta는 각각 필터링 연산 후 곱하거나 더할 값을 의미하며 borderType은 가장자리 픽셀 확장 방식이라고 한다.

샤르 필터 마스크

소벨 마스크 외에도 샤르 필터(Scharr filter) 마스크도 존재한다. 샤르 필터는 소벨 마스크보다 정확한 미분 계산을 수행한다고 한다.

샤르 필터를 사용하려면 Scharr() 를 사용하거나 또는 Sobel() 함수에서 ksize인자에 FILTER_SCHARR 값 또는 -1을 지정하면 된다.

그래디언트의 크기와 방향 계산

마스크를 통해 얻어낸 x방향, y방향 미분 행렬을 이용하여 그래디언트 크기를 구할 수 있다.

void magnitude(InputArray x, InputArray y, OutputArray magnitude);

x,y는 CV_32F Ehsms CV_64F depth를 사용하는 행렬 또는 벡터이다.

내부적으로 magnitude를 구성하는 요소는 magnitude(I)=(X(I)^2+Y(I)^2)^(1/2) 를 통해 계산된다.

x, y방향 미분이 저장된 두 개의 행렬로 그래디언트의 방향을 계산하고 싶다면

void phase(InputArray x, InputArray y, OutputArray angle, 
						bool angleInDegrees = false);

angleInDegrees 값이 true면 각도(degree)를, false면 라디안(radian)단위를 사용한다.

angle은 angle(I) = atan2(Y(I)/X(I)) 를 통해 계산된다.

캐니 에지 검출기

소벨 마스크의 문제점과 캐니 에지 검출기

소벨 마스크 기반 에지 검출은 구현이 간단하고 빠르게 동작하지만 에지 픽셀이 두껍게 표현되는 문제점이 있다. 이를 보완할 수 있는 것이 캐니 에지 검출기이다.

캐니가 제시한 좋은 검출기의 조건은 다음과 같다.

  1. 정확한 검출 : 에지 검출의 오탐률, 미탐률을 최소화해야 한다.
  2. 정확한 위치 : 실제 에지의 중심을 찾아야 한다.
  3. 단일 에지 : 하나의 에지는 하나의 점으로 표현되어야 한다.

캐니가 제시한 캐니 에지 검출기는 네 가지 연산 과정을 거친다.

  1. 가우시안 필터링
  2. 그래디언트 계산
  3. 비최대 억제(non-maximum suppression)
  4. 이중 임계값을 이용한 히스테리시스 에지 트래킹(hysteresis edge tracking)

순서대로 살펴보면 다음과 같다.

가우시안 필터링

잡음을 제거하기 위해 존재한다. 가우시안 필터링을 거치면 영상이 부드러워지면서 에지의 세기가 약해진다. 따라서 적절한 표준 편차를 선택하여야 한다. 영상에 따라 잡음이 심하지 않다면 생략할 수 있다.

그래디언트 계산

소벨 에지 검출 방법에서는 오직 그래디언트 크기만을 이용하여 에지를 탐색하였다면 캐니 에지 검출기는 방향도 함께 고려한다.

x,y방향 모두 소벨 마스크 필터링을 수행하고 그래디언트의 크기, 방향을 계산하여 사용한다.

이때 그래디언트의 크기를 magnitude(I)=(X(I)^2+Y(I)^2)^(1/2) 로 구한다고 하였는데 이를 L2 노름이라고 한다.

하지만 실제 계산 시 연산 속도 향상을 위해 |X(I)|+|Y(I)| 로 근사치를 구하여 사용하기도 한다. 이를 L1 노름이라고 한다. OpenCV는 기본적으로 L1노름을 사용한다.

비최대 억제(non-maximum suppression)

그래디언트의 국지적 최대(local maximum)인 픽셀만을 에지 픽셀로 설정하는 기법이다.

2차원 영상에서 국지적 최대를 찾으려면 특정 픽셀을 둘러싸는 모든 픽셀 값을 검사하여 국지적 최대인지 판별해야 한다. 하지만 캐니 에지 검출기의 비최대 억제 과정에서는 그래디언트 벡터의 방향과 같은 방향의 인접한 픽셀끼리만 국지적 최대 검사를 수행한다.

국지적 최대가 아닌 픽셀을 제외하기 때문에 에지가 두껍지 않고 얇게 표현될 수 있다.

이중 임계값을 이용한 히스테리시스 에지 트래킹(hysteresis edge tracking)

소벨 에지 검출기에서는 특정 임계값 보다 크면 에지 픽셀로, 작으면 에지 픽셀이 아니라고 간주하였다.
이 경우 조명이나 임계값이 조금만 변해도 에지 픽셀 판단 결과가 크게 달라진다.

이를 해결하기 위해 캐니 에지 검출기에서는 T(high), T(low)라는 높음 임계 값과 낮은 임계 값을 사용한다.
T(high)보다 크다면 에지 픽셀로 간주, T(low)보다 작다면 에지 픽셀이 아니라고 간주한다.
만약 T(high)보다는 작지만 T(low)보다 큰 픽셀의 경우 추가적인 검사를 진행한다.

T(high)를 강한 에지(strong edge)라고 표현하고 T(low)와 T(high) 사이의 에지를 약한 에지(weak edge)라고 표현한다. 약한 에지는 에지픽셀일 수도 아닐 수도 있는 픽셀이다.

이때 히스테리시스 에지 트래킹 방법은 에지 픽셀은 대체로 상호 연결되어 있다는 점을 이용하여 약한 에지가 강한 에지와 연결되어 있다면 에지 픽셀로 분류한다. 만약 강한 에지와 연결되어 있지 않다면 에지 픽셀이 아닌 것으로 분류한다.

OpenCV Canny()

OpenCV에서는 두 가지 형태로 정의하고 있다.

void Canny(InputArray image, OutputArray edges,
						double thresshold1, double threshold2,
						int apertureSize = 3, bool L2gradient = false);
void Canny(InputArray dx, InputArray dy, OutputArray edges,
						double threshold1, double threshold2,
						bool L2gradient = false);

threshold값은 순서대로 낮은 임계값과 높은 임계값을 의미한다.

apertureSize는 소벨 마스크의 크기를 의미하며 L2gradient는 L2노름을 사용할 것인지를 지정하는 값이다.

profile
개발과 보안을 공부하는 학생

0개의 댓글