Gradient

그래디언트란  x방향으로 미분과 y방향으로의 미분을 따로 계산하고 그걸 하나로 묶어서 벡터로 표현 한것을 말한다.

아래의 [그림1]은 원본이미지 및 원본이미지에 소벨필터를 x 및 y 방향으로 적용하고, 가시성을위해 delta값을 추가로 128 적용한 영상이다.

[그림1]

수학적 기호로 그래디언트를 표현할때는 역삼각형(▽)으로 표현한다.

위의 수식을 살펴보면 그래디언트 ▽f 는 x축과 y축으로 각각 편미분하여 fx와 fy의 행렬 형태로 표현하고 있다. 다시 한번 강조하자면, 그래디언트라는 것은 x방향의 미분성분과 y방향의 미분성분을 함께 하나의 벡터형태로 표현하고 있다는 점이다.

보통 벡터는 2차원 평면상에서 다음과 같이 한 점의 형태로 표현이 된다. 빨간점을 살펴보자.

원점으로부터 빨간점까지의 길이가 magnitude라고 하는 그래디언트의 크기(=벡터의 크기)이고 이를 구하는 공식은 유클리디언 거리를 구하는 공식과 동일하다.

그래디언트의 방향(=벡터의 방향)은 x축과 이루는 각도 θ로 표현하는데 역탄젠트를 통해 구할 수 있다.

이미지에서 그래디언트 크기는 인접하는 픽셀 값이 얼마나 차이가 나는지 보여주고, 그래디언트의 방향은 픽셀 값의 변화량이 어느쪽으로 급격하게 증가하는지 나타낸다.

OpenCV에서는 그래디언트의 크기와 방향을 계산하기 위한 함수를 제공한다.

magnitude : 벡터의 크기 계산 함수
phase : 벡터의 방향 계산 함수 

2D 벡터의 크기 계산을 도와주는 magnitude 함수의 인자는 다음과 같다 .

Core.magnitude(Mat x, Mat y, Mat magnitude)
x : 2D벡터의 x좌표 행렬. 실수형
y : 2D벡터의 y좌표 행렬. x와 같은 크기. 실수형
magnitude : 2D벡터의 크기 행렬. x와 같은 크기, 같은 타입. 유클리디언 거리 구하는 방법으로 결과 도출

2D 벡터의 방향 계산을 도와주는 phase 함수의 인자는 다음과 같다.

Core.phase(Mat x, Mat y, Mat angle, boolean angleInDegrees)
x : 2D벡터의 x좌표 행렬. 실수형
y : 2D벡터의 y좌표 행렬. x와 같은 크기. 실수형
angle : 2D 벡터의 크기 행렬. x와 같은 크기, 같은 타입.
        angle(I) = atan2(y(I), x(I)) 
        만약 x(I) = y(I) = 0이면 angle은 0으로 설정됨.
angleInDegrees : true이면 각도 단위, false이면 radian 단위 

그래디언트와 엣지 검출 예제

위에서 배운 내용을 토대로 레나 이미지의 엣지를 검출해보자. 가장 먼저 해야 할 일은 그래디언트의 크기(magnitude)를 구하는 것이다. x 및 y방향으로 소벨필터를 적용한 행렬 두개를 준비하여 magnitude 함수의 인자로 전달 하자.

//x방향으로 소벨필터 적용
val dx = Mat()
Imgproc.Sobel(src, dx, CvType.CV_32F, 1, 0, 3)

//y방향으로 소벨필터 적용
val dy = Mat()
Imgproc.Sobel(src, dy, CvType.CV_32F, 0, 1, 3)

//위의 두개의 행렬을 이용하여 그라디언트 크기 구하기
var mag = Mat()
Core.magnitude(dx, dy, mag)

이렇게 해서 mag를 출력하면 다음과 같은 영상을 얻을 수 있다.

픽셀값의 변화량에 따라 엣지가 밝게 표현되는 것을 확인할 수 있다.

여기에 threshold를 적용하여 특정 밝은 엣지만 남도록 수정하면 다음과 같은 이미지를 얻을 수 있다.

엣지가 좀 두툼하긴 하지만 어느정도 원하는 결과를 얻을 수 있게 되었다.

최종 소스 코드는 다음과 같다.

val src = ... // 레나 이미지 

// 흑백으로 전환
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY)

//x방향으로 소벨필터 적용
val dx = Mat()
Imgproc.Sobel(src, dx, CvType.CV_32F, 1, 0, 3)

//y방향으로 소벨필터 적용
val dy = Mat()
Imgproc.Sobel(src, dy, CvType.CV_32F, 0, 1, 3)

//위의 두개의 행렬을 이용하여 그라디언트 크기 구하기
var mag = Mat()
Core.magnitude(dx, dy, mag)

// Float형으로 계산된 결과기 때문에 비트맵으로 표현 할 수 있는 타입으로 변경
mag.convertTo(mag, CvType.CV_8UC1)

// 뚜렷한 엣지만 검출하기 위해 밝은 픽셀만 검출
Imgproc.threshold(mag, mag, 70.0, 255.0, Imgproc.THRESH_BINARY)
Buy me a coffeeBuy me a coffee
카테고리: AndroidOpenCV

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.