그림에 존재하는 선 (lines)을 찾기 위해선 그림의 경계선을 먼저 그려야 하고, OpenCV에는 그림에 존재하는 경계선을 찾는 Canny Edge라는 함수를 지원한다.
1. Canny Edge란?
간단하게 구글에 "Canny Edge" 키워드를 검색하면 위키 페이지가 나온다. en.wikipedia.org/wiki/Canny_edge_detector
Canny edge detector - Wikipedia
From Wikipedia, the free encyclopedia Jump to navigation Jump to search The Canny edge detector is an edge detection operator that uses a multi-stage algorithm to detect a wide range of edges in images. It was developed by John F. Canny in 1986. Canny also
en.wikipedia.org
긴 글인데, 요약하자면 grayscale에서 색값의 변화의 정도에 따라 경계를 판단할 수 있다. 이에 대한 자세한 설명은 이 블로그글을 참고하면 되고, 일부만 발췌하자면 gradient에 대한 강한임계/약한임계 기준이 있고, 강한임계값을 넘은 곡선은 항상 경계선 (line)으로 구분함. (아래그림 참조)
2. Canny Edge 예제
위의 설정을 이용한 함수, Cv2.Canny를 살펴본다.
CPP: Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
C#(OpenCvSharp4): Canny(InputArray, OutputArray, Double, Double, Int32)
예시 이미지는 OpenCV 공홈의 스도쿠 이미지를 사용했는데, 갱지에 흑백 인쇄가 된 사각형 박스들이 존재한다.
1) 우선 커널 사이즈에 따른 차이를 보면, 커널 사이즈가 커질수록 더 많은 경계(혹은 Noise)가 잡히는 것을 알 수 있다. 커널은 Gradient를 판단하는 조리개(aperture, 실제로 OpenCvSharp에는 tile로 표기함) 사이즈라고 할 수 있는데, 이 규격이 커질수록 해당 범위 내의 색값 변동이 다양해지기 때문이다.
2) 위에서 다룬 임계값 차이에 따라서도 역시 경계선이 차이가 나는데, 이를 보기 위해 아래와 같은 코드를 적용했다. (kernel 3 기준)
for(int th1 = 0; th1 < 200; th1 += 50)
{
for(int th2 = th1+50; th2< 255; th2 += 50)
{
Cv2.Canny(_imgRef, _imgCanny3, th1, th2, 3);
Cv2.Canny(_imgRef, _imgCanny5, th1, th2, 5);
Cv2.Canny(_imgRef, _imgCanny7, th1, th2, 7);
_imgCanny3.SaveImage(String.Format("Canny_{0}_{1}_aperture_3.png",th1,th2));
_imgCanny5.SaveImage(String.Format("Canny_{0}_{1}_aperture_5.png", th1, th2));
_imgCanny7.SaveImage(String.Format("Canny_{0}_{1}_aperture_7.png", th1, th2));
}
}
50 간격으로 threshold를 변경하면서 맵핑을 했고, 그 결과 아래와 같이 임계값에 따른 차이를 명확히 볼 수 있다.
3) 최종적으로, 낮은임계 0, 높은임계 100 값이 해당 스도쿠 이미지에는 적합한 경계값으로 보인다. 조금 더 세분화 하면 와하단의 노이즈가 없는 경계도 딸 수 있겠지만.. 굳이 여기서 그럴 필요는 없어보이고.
최근댓글