본문 바로가기
코딩/OpenCV

[C++ opencv] 이미지에서 경계선 검출하기, Edge detection

by DIYver 2020. 7. 4.

본문 목표

Color 이미지의 Grayscale 로의 변환,

 

노이즈 제거와 이진화,

 

이 모든 과정은 오늘 다룰 경계선 검출을 위해서 선행되었어야 할 필수 과정이었다.

 

영상인식에서 경계선 검출이 되어야 컴퓨터가 물체를 인식하고 처리할 수 있다.

 

전문 용어로는 Edge detection 이라고 한다.

 

오늘은 이 경계선 검출 방법에 대해서 알아보고, 

 

OpenCV에서 어떻게 사용하는지 다뤄보도록 하겠다.

 

 

 

 

키워드 : Edge detection, Canny, 경계선 검출

 

 

 

 

 

알아볼 함수 원형

- 경계선 검출, 캐니 알고리즘 ( Edge_detection, Canny algorithm )

...
	Mat img = imread("Lenna.png", 0);	//이미지를 grayscale로 불러옴

	Mat img_edge;

	Canny(img, img_edge, 100, 150);
...

 

Canny( src, dst, threshold1, threshold2)

 

  ○ src : 입력할 이미지 변수 (grayscale 이미지를 입력해야함! )

 

  ○ dst : 필터가 적용되어 저장될 이미지 변수

 

  ○ threshold1 : 낮은 경계 값 (0~255)

 

  ○ threshold2 : 높은 경계 값 (0~255)

 

 

 

 

 

엄밀히 말하면 Canny Edge detection경계선 검출 기법 중 대표적인 예이다.

 

그래서 그런지, OpenCV 에서는 Canny Edge detection 만 기본으로 제공하고 다른 방식은 제공하지 않는 것 같다.

 

그냥 Canny Edge detection 을 사용해도 좋지만, 원리를 알고 싶다면 이 글을 읽으면 도움이 될 것이다.

 

 

(a) 와 (b) 의 빨간 네모 영역을 비교해보자.

 

(a) 는 같이 비슷비슷한 것을 알 수 있고,

 

(b) 는 옆의 픽셀과 값이 확연히 차이나는 것을 알 수 있다.

 

여기서 경계선이 있다고 한다면 (a)에 경계선이 있다고 하는게 타당할까?

 

(b)에 경계선이 있다고 하는게 타당할까?

 

당연 (b)에 경계선이 있다고 하는 것이 타당하다.

 

값이 확연히 차이가 나기 때문이다.

 

 

왼쪽은 밝기 차이를 나타내는 이미지이고,

 

오른쪽은 가로축에 대한 픽셀 들의 밝기 정도를 나타낸 그래프이다.

 

밝기가 서서히증가하는 경우와

 

밝기가 갑자기 어두워지는 경우로 예를 들고 있다.

 

사람은 그냥 대충 경계가 보이겠지만, 컴퓨터는 어느 경우를 경계라고 인식하게 할지 설정해줘야한다.

 

그게 바로 저렇게 상승엣지가 나타나거나,

 

갑작스럽게 하강이 일어나는 경우 등을 통해서 경계라고 인식하게 하는 것이다.

 

 

여기서 미분의 개념이 들어간다.

 

기울기가 증가하면 양수(+)

 

기울기가 감소하면 음수(-) 가 나오는 것을 이용해서

 

기울기의 부호가 바뀌는 지점이 경계인 것이다.

 

 

이런 기울기 변화를 검사하는데

 

x축과 y축 두 방향을 각각 조사한다.

 

위의 이미지는 원본 이미지이다.

 

 

원본 이미지에 위의 필터 커널을 각각의 축방향으로 적용한다.

 

이 필터 이름을 'Prewitt filter' 라고 한다.

 

(a) 가 x축 방향으로 검사하면서 기울기 변화가 있는 부분이 하얀색으로 표시되었고,

 

(b) 가 y축 방향으로 검사하면서 기울기 변화가 있는 부분이 하얀색으로 표시되었다.

 

이 두가지 결과를 합하면 된다.

 

단순히 덧셈 연산으로 합치는게 아니라

 

벡터끼리 합치듯, 루트(x축 결과^2 + y축 결과^2) 로 합친다.

 

그러면 위와 같은 이미지를 얻게 되는데;

 

여기서 이진화를 하면

 

위와 같이 된다.

 

이 이미지에서 필터를 하나 적용해줘야 한다.

 

역시 그 필터는 Prewitt filter 이다.

 

필터를 적용한 이미지가 위와같이 나온다.

 

 

 

 

 

다른 방법도 많지만,

 

다 소개하기는 힘드므로, 여기까지만 다루기로 하겠다.

 

다른 블로그에서는 소벨(sobel) 방식을 이용하는 것을 소개하기도 하는데,

 

자세히 다루지는 않겠다.

 

 

 

 

 

Canny Edge detection 을 간단하게 설명하자면

 

1. 가우시안 필터 적용하여 영상을 부드럽게(smooth) 해준다. [노이즈 제거]

 

 

2. sobel 커널을 사용하여, x축 y축에 대한 편미분 벡터를 구한다.

 

 

3. 이웃 픽셀들과의 비교를 통해서 변화량이 큰지를 판별하여 값이 큰 픽셀만 추출한다. 그리고 경계의 방향을 구한다.

 

 

4. 그 중에서 threshold1 값과 threshold2 값을 이용해서 진짜 경계만을 추출해낸다.

threshold1 보다 작으면 경계가 아닌것이고, threshold2 이상이면 강한 엣지이고, 

두 값 사이에 있으면 강한 엣지에 연결되어 있으면 엣지이고, 아니면 경계가 아닌것으로 판단한다.

 

 

 

 

 

 

이해하기 어렵다면

 

그냥 OpenCV 에서든, 다른 영상처리에서든

 

Canny Edge detection이 가장 효율적인 방법이라고 생각하고 사용하면 된다.

 

가우시안 필터가 적용되면서, 경계선을 가장 잘 얻을 수 있다.

 

설명했다싶이, 방향을 고려하고 강한 엣지를 찾아서 연결이 되기 때문이다.

 

 

 

 

 

 

 

 

 

코드 테스트 결과

- CODE

#include <opencv2/opencv.hpp>


using namespace cv;
using namespace std;


int main(int ac, char** av) {
	Mat img = imread("Lenna.png", 0);	//이미지를 grayscale로 불러옴
	
	//Mat img_threshold;

	Mat img_edge;

	Canny(img, img_edge, 50, 200);
	imshow("original", img);
	imshow("img_edge", img_edge);
	//imshow("erode2", img_erode2);
	waitKey(0);



	return 0;
}

 

- RESULT

 

원본 이미지의 grayscale 버전이다.

이젠 너무나도 익숙한 레나누나~

 

threshold1 : 50, threshold2 : 200

canny 엣지검출을 실시한 이미지이다.

 

확실히 깔끔하게 경계선을 검출해냈다.

 

 

 

 

 

 

threshold1 : 50, threshold2 : 100

이번에는 50과 100 값을 주었다.

 

threshold2 값을 낮추었더니 잡다한 경계가 많이 포함되어버렸다.

 

threshold2 값이 낮으니 그 이상되는 값들은 강한 엣지로 되어서 그렇다.

 

threshold2 값은 적당히 높을 필요가 있다.

 

 

 

이번에는 150과 200 값을 주었다.

 

threshold1 값을 높였더니, 경계들이 많이 없어졌다.

 

threshold1 밑의 값들은 경계가 아니라고 지시를 내렸기 때문이다.

 

 

 

 

 

 

결론.

OpenCV 에서는 사용자가 편하게 사용할 수 있게 Canny( ) 라는 경계선 검출 함수를 제공하고 있으므로,

 

threshold 값 2개만 적절히 조절하여,

 

자신이 원하는 경계를 잘 검출할 수 있다.

 

그 값을 찾는것은 사용자 몫이므로 여러가지 값을 넣어서 테스트를 해보시길 바란다.

 

 

 

 

 

 

 

 

도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!

감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^

댓글