관리 메뉴

공부 기록장 💻

[OpenCV/C++] 에지 검출 2 - 소벨, 샤르 마스크 필터를 이용한 에지 검출 (Edge Detection using Sobel Mask 본문

# Tech Studies/Computer Vision • OpenCV

[OpenCV/C++] 에지 검출 2 - 소벨, 샤르 마스크 필터를 이용한 에지 검출 (Edge Detection using Sobel Mask

dream_for 2022. 12. 3. 17:29

OpenCV 4로 배우는 영상 처리와 컴퓨터 비전 CH9. 에지 검출과 응용 정리

마스크 기반 에지 검출

영상을 x, y축 방향으로 편미분 하는 1x3, 3x1 크기의 마스크를 통해 에지를 검출할 수 있는 것 같지만, 사실 대부분의 영상에는 잡음이 포함되어 있어 단순히 1x3, 3x1 마스크를 이용해서 미분을 구할 경우 다소 부정확한 결과가 생성될 수 있다. 따라서 실제 영상에서 미분을 구할 때는 좀 더 큰 크기의 마스크를 사용한다

가장 널리 사용되고 있는 미분 근사 마스크는 소벨 필터(Sobel Filter) 마스크 이다.
아래 그림 (a)는 x축으로 방향으로의 편미분을 구하는 소벨 마스크를, (b)는 y축 방향으로 편미분을 구하는 소벨 마스크이다.

(a)에 나타난 미분 마스크는 현재 행에 대해 중앙 차분 연산을 2회 수행하고, 이전 행과 다음 행에 대해서도 중앙 차분 연산을 1회씩 수행한다. 이는 현재 행과 이웃 행에서 픽셀 값 변화가 유사하다는 점을 이용해 잡음의 영향을 줄이기 위함이며, 특히 현재 행에서 2번의 중앙 차분 연산을 수행한 것은 현재 행의 중앙 차분 근사에 더 큰 가중치를 주기 위함이다.
(b) 마스크도 위와 같은 방식으로 설계되었다.


Sobel() 함수

OpenCV는 소벨 마스크를 이용해 영상을 미분하는 Sobel() 함수를 제공한다. 이는 3x3 소벨 마스크 또는 확장된 형태의 큰 마스크를 이용해 영상을 미분한다.

3x3 또는 그 이상의 크기의 마스크로 영상을 미분하는 Sobel() 함수


결과 영상의 자료형 ddepth에 -1를 지정하면 src와 같은 타입을 사용하는 dst 영상을 생성한다. dx와 dy인자는 각각 x와 y방향으로의 편미분 차수를 의미하며, dst 결과 행렬은 다음 수식과 같은 의미를 갖는다.

ksize는 소벨 커널의 크기로, 1을 지정하는 경우 3x1 또는 1x3 커널을 사용하고, 기본 값인 3을 지정하면 3x3 소벨 마스크를 사용한다.

Sobel() 함수는 x방향과 y방향으로의 고차 미분을 계산할 수 있지만, 대부분의 경우 x방향 또는 y방향으로의 1차 미분을 구하는 용도로 사용된다. 예를 들면 그레이스케일 레나 영상을 x방향으로 편미분한 결과를 dx 행렬에, y방향으로 편미분한 결과를 dy 행렬에 저장하려면 다음과 같이 작성하면 된다.

Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

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

OpenCV는 소벨 마스크 이외에도 샤르 필터(Scharr filter) 마스크 를 이용한 미분 연산도 지원한다.
이는 3x3 소벨 마스크보다 정확한 미분 계산을 수행하는 것으로 알려져 있다.
아래는 각각 가로, 세로 방향으로 미분을 수행하는 샤르 필터 마스크를 나타낸 것이다.

Scharr() 함수

Scharr() 함수의 원형은 위와 같은데,
샤르 필터를 이용한 영상의 미분은 앞서 설명한 Sobel() 함수를 이용하여 구할 수도 있다. Sobel() 함수의 ksize 인자에 FILTER_SCHARR 또는 -1을 지정하면 3x3 샤르 마스크를 사용하여 영상을 미분한다.



Sobel() 또는 Scharr() 함수를 이용하여 x, y방향으로 각각 미분을 계산하여 행렬에 저장한 후, 두 미분 행렬을 이용해 그래디언트 크기를 계산할 수 있다. OpenCV는 2차원 벡터의 x, y 방향 좌표를 이용해 벡터의 크기를 계산하는 magnitude() 함수를 제공한다.

magnitude() 함수

방향 좌표를 이용해 벡터의 크기를 계산하는 magnitude() 함수

함수의 입력으로 사용되는 x,y는 CV_32F 또는 CV_64F 깊이를 사용하는 행렬 또는 벡터여야 한다. 출력 magnitude를 구성하는 원소 값은 다음 수식에 의해 계산된다.

phase() 함수


만약 x방향으로 미분, y방향으로 미분이 저장된 두 행렬이 있을 때 그래디언트의 방향을 계산하고 싶다면 phase() 함수를 사용할 수 있다.

x,y는 입력이고 angle은 출력이다. angle의 각 원소는 다음 수식에 의해 계산된다.



이제 Sobel() 함수를 사용하여 실제 영상으로부터 그래디언트를 계산하고, 그래디언트 크기를 이용하여 에지를 검출하는 예제 코드를 살펴보자.

// 소벨 마스크 기반 에지 검출
void sobel_edge() {
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	// 가로, 세로 방향으로 각각 소벨 마스크 연산
	Mat dx, dy;
	Sobel(src, dx, CV_32FC1, 1, 0);
	Sobel(src, dy, CV_32FC1, 0, 1);

	// dx와 dy 행렬으로부터 그래디언트 크기 계산하여 fmag에 저장
	Mat fmag, mag;
	magnitude(dx, dy, fmag);
	fmag.convertTo(mag, CV_8UC1);

	// 에지 판별을 위한 그래디언트 크기 임계값을 150으로 설정 (150보다 크면 255로, 작으면 0으로 설정됨)
	Mat edge = mag > 150;

	imshow("src", src);
	imshow("mag", mag);
	imshow("edge", edge);

	waitKey();
	destroyAllWindows();
}


src는 원본 lenna 영상이고, mag는 그래디언트 크기를 그레이스케일 영상 형식으로 나타낸 것이다. 이때 각 픽셀에서 계산된 그래디언트 크기가 255보다 큰 경우에는 포화 연산에 의해 흰색으로 표현된다.
edge 영상은 그래디언트 크기 mag 가 150보다 큰 픽셀을 흰색으로, 아니면 검은색으로 표현한 이진 영상이다.



소벨 마스크를 이용한 에지 검출 방법은 구현이 간단하고 빠르게 동작하여 현재 컴퓨터 비전 시스템에서 사용되고 있지만, 그래디언트 크기만을 기준으로 에지 픽셀을 검출하기 때문에 임계값에 민감하고 에지 픽셀이 두껍게 표현되는 문제점이 있다. 따라서 다음 포스팅에서는 소벨 마스크의 단점을 보완한 캐니 에지 검출기에 대해 알아보며 에지 검출에 더 나은 성능을 보이는 검출 방법에 대해 이해해보도록 하자.

728x90
반응형
Comments