[OpenCV] 에지 검출 – 소벨 필터(Sobel filter)

이번 글에서는 소벨 필터 마스크에 대해 알아보겠습니다.

소벨 필터 마스크는 에지 검출 개념에 대한 글에서 설명했던 마스크처럼 1 X 3 또는 3 X 1 크기의 마스크를 사용하지 않습니다.
소벨 마스크는 3 X 3 크기를 가집니다.

좌측 x방향, 우측 y방향 편미분

OpenCV에서 소벨 함수는 아래와 같습니다.

/*
@param src 입력 영상
@param dst 출력 영상
@param ddepth 출력 영상 깊이
@param dx x방향 미분 차수
@param dy y방향 미분 차수
@param ksize 커널 크기
@param scale 연산 후 추가로 곱할 값
@param delta 연산 후 추가로 더할 값
@param borderType 가장자리 타입
 */
CV_EXPORTS_W 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 );

2차원 공간에서 에지를 찾으려면 소벨과 같이 x축 방향과 y축 방향 편미분을 모두 사용해야합니다.
그래디언트(gradient)는 x축 방향 미분과 y축 방향 미분을 한번에 벡터로 표현한 것입니다.
그래디언트는 벡터이므로 방향과 크기가 있으며, 그래디언트 벡터의 방향을 통해 수직 방향으로 에지의 방향을 알 수 있고, 그래디언트 벡터의 크기로 에지의 임계값을 설정할 수 있습니다.

그림으로 표현하면 아래와 같습니다.

갑자기 그래디언트를 설명하는 이유는 OpenCV에서 그래디언트 크기를 계산하는 함수를 제공하기 때문입니다.

/** 
@param x 벡터의 x좌표를 나타내는 실수 행렬 또는 벡터
@param y 벡터의 y좌표를 나타내는 실수 행렬 또는 벡터
@param magnitude 벡터의 크기를 나타내는 실수 행렬 또는 벡터
*/
CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude);

예제 코드는 아래와 같습니다.

Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty())
{
	cerr << "image load fail" << endl;
	return ;
}

Mat x, y;
Sobel(src, x, CV_32FC1, 1, 0); // x방향 편미분
Sobel(src, y, CV_32FC1, 0, 1); // y방향 편미분


Mat float_mag, mag;
magnitude(x, y, float_mag); // 그래디언트 크기 계산
float_mag.convertTo(mag, CV_8UC1); // 타입 변경(실수 -> 정수)

Mat edge;
threshold(mag, edge, 100, 255, THRESH_BINARY);  // 크기가 100 이상만 에지로 판단
imshow("src", src);
imshow("mag", mag);
imshow("edge", edge);

waitKey();
destroyAllWindows();

실행 결과는 아래와 같습니다.