OpenCV | 에지 검출

박나연·2021년 4월 18일
0

OpenCV

목록 보기
26/40

미분과 그래디언트

영상에서 에지는 한쪽방향으로 픽셀 값이 급격하게 바뀌는 부분을 가리킨다. 영상에서 에지를 찾아내는 작업은 객체의 윤곽을 알아낼 수 있는 유용한 방법이다. 픽셀 값의 변화율을 측정하여 변화율이 큰 픽셀을 선택해야 한다. 따라서 주어진 함수의 순간 변화율인 미분을 구하여야 한다.

위 수식에서 의미하는 바는 x의 변화량이 0에 가까워질때의 함수 값 변화량이다. 함수 값이 증가하는 위치에서는 함수의 미분 값이 0보다 큰 양수, 감소하는 위치에서는 0보다 작은 음수를 갖게 된다. 함수 값이 일정한 구간에서는 함수의 미분이 0에 가까운 값을 가진다.

각각 x축과 y축 방향으로 편미분 하는 수식이다.

위와 같이 중앙 차분을 이용한 영상의 미분 근사는 마스크 연산을 이용하여 쉽게 구현가능하다.

x축 방향으로 편미분을 수행하기 위해서는 [-1 0 1] 필터마스크가 필요하고,
y축 방향으로 편미분을 수행하기 위해서는
[-1 필터마스크가 필요하다.
 0
 1]

2차원 공간에서 정의된 영상에서 에지를 찾으려면 x축방향과 y축 방향의 편미분을 모두 사용해야 한다. 2차원 공간에서 정의된 함수 f(x,y)가 있을 때 이 함수의 x축 방향 미분과 y축 방향 미분을 한꺼번에 벡터로 표현한 것을 그래디 언트라고 한다.

그래디언트 방향


소벨 필터 마스크

대부분의 영상에는 잡음이 포함되어 있어서 1x3, 3x1 마스크를 이용하여 미분을 구할경우 부정확한 결과가 생성될 수 있다. 따라서 좀 더 큰 크기의 마스크를 이용하는데 그 중 소벨 필터 마스크가 있다.

a는 x축방향으로의 편미분, b는 y축방향으로의 편미분을 구하는 소벨마스크이다.

OpenCV에서 소벨마스크를 이용하여 영상을 미분하는 Sobel()함수를 제공한다.

Sobel()

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

src : 입력영상
dst : 출력영상
ddepth : 출력 영상의 깊이
dx : x방향 미분 차수
dy : y방향 미분 차수
ksize : 소벨 커널의 크기
scale : 필터링 연산 후 추가적으로 곱할 값
delta : 필터링 연산 후 추가적으로 더할 값
borderType : 가장자리 픽셀 확장 방식


샤르 필터 마스크

소벨 마스크 외에도 널리 사용되는 샤르 필터마스크가 있다.

Scharr()

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

src : 입력영상
dst : 출력영상
ddepth : 출력 영상의 깊이
dx : x방향 미분 차수
dy : y방향 미분 차수
scale : 필터링 연산 후 추가적으로 곱할 값
delta : 필터링 연산 후 추가적으로 더할 값
borderType : 가장자리 픽셀 확장 방식


그래디언트 크기, 방향 계산

magnitude()

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

x : 벡터의 x 좌표를 나타내는 실수 행렬 또는 벡터
y : 벡터의 y 좌표를 나타내는 실수 행렬 또는 벡터
magnitude : 벡터의 크기를 나타내는 실수 행렬 또는 벡터

phase()

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

x : 벡터의 x좌표를 나타내는 실수 행렬 또는 벡터
y : 벡터의 y좌표를 나타내는 실수 행렬 또는 벡터
angle : 벡터의 방향을 나타내는 실수 행렬 또는 벡터
angleInDegrees : 이 값이 true이면 각도 단위를 사용하고, false이면 라디안 단위를 사용

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); // x축방향 편미분하여 dx에 저장
	Sobel(src, dy, CV_32FC1, 0, 1); // y축방향 편미분하여 dy에 저장

	Mat fmag, mag;
	magnitude(dx, dy, fmag); // 그래디언트 크기 계산, fmag에 저장
	fmag.convertTo(mag, CV_8UC1); // 그레이스케일 형식으로 변환 

	Mat edge = mag > 150; // 150보다 크면 255, 작으면 0으로 설정

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

	waitKey();
	destroyAllWindows();


}

profile
Data Science / Computer Vision

0개의 댓글