Home OpenCV 캐니 에지 기반 검출
Post
Cancel

OpenCV 캐니 에지 기반 검출

해당 포스팅은 OpenCV 4로 배우는 컴퓨터 비전과 머신러닝 (황선규 저)를 보고 공부하며 개인적인 용도를 위해 정리한 글이다.

캐니 에지 검출

  • 기존 방식의 에지 검출기는 임계값에 민감하여 에지 픽셀이 두껍게 표현 되는 등의 문제가 발생한다.
  • 해당 문제를 해결하기 위해 198년 캐니가 신규 에지 검출기를 3가지의 조건을 통해 제시했다.
    • 정확한 검출 (good detection): 에지를 검출하지 못하거나 또는 에지가 아닌데 에지로 검출하는 확률을 최소화한다.
    • 정확한 위치 (good localization): 실제 에지의 중심을 찾을 수 있어야한다.
    • 단일 에지 (single edge): 하나의 에지는 하나의 점 (픽셀) 으로 표현 되어야한다.
  • 기존의 소벨 필터 방법은 그래디언트의 크기만을 고려했지만 캐니는 크기와 방향을 모두 고려하였다.
  • 서로 연결 되어있는 가능성이 높다는 점을 고려해 에지 특성이 다소 약하게 나타나는 에지도 놓치지 않고 찾을 수 있었다.

캐니 에지 검출의 4단계 과정

가우시안 필터링

  • 제일 먼저 입력 영상에서 가우시안 필터링을 수행한다.
  • 잡음 제거가 목적이며 영상 내의 노이즈가 많지 않다면 생략하기도 한다.

그래디언트 계산

  • $(3, 3)$ 형태의 소벨 필터 마스크를 사용한다.
  • 각 축으로 필터링을 수행한 후 그래디언트 크기와 방향을 모두 계산한다.
  • 2차원에 정의 된 함수 $f(x, y)$의 그래디언트 크기를 $f$ 함수에 대한 L2 Norm이라고 하여 연산하지만 연산속도의 향상을 위해 L1 Norm으로 계산한다.

비최대 억제

  • 단순 그래디언트 크기가 임계값보다 클 때를 기준으로 에지를 검색하면 주변 픽셀들도 함께 에지로 검출 될 수 있다.
  • 에지가 두껍게 검출 되는 것을 막기 위해 비최대 억제 (non-maximum supperession) 과정을 수행한다.
    • 그래디언트 크기가 국지적 최대 (local maximum) 인 픽셀만을 에지 픽셀로 정의하는 기법이다.
    • 상대적으로 국지적 최대가 아닌 픽셀은 에지 픽셀에서 제외하기 때문에 비최대 억제라는 용어를 사용했다.
    • 일반적인 영상에서 국지적 최대를 찾기 위해선 특정 픽셀을 둘러싼 모든 픽셀을 검사하여 국지적 최대를 판명하지만 해당 연산은 그래디언트 벡터의 방향에 있는 인접한 픽셀끼리만 국지적 최대를 수행하므로 가장 변화율이 큰 위치의 픽셀만 에지로 검출 된다.

이중 임계값을 이용한 히스테리시스 에지 트래킹

  • 일반적인 에지 검출은 그래디언트 크기만을 고려하므로 조명이 바뀌거나 임게값을 조금만 조절해도 에지 판단의 결과가 크게 달라질 수 있다.
  • 하나의 임계값을 사용할 경우 이분법으로 결과가 판단 되기 때문에 환경 변화에 몹시 민감해지므로 캐니 에지에서는 2개의 임계값을 사용한다.
    • $T_high$: 해당 임계값보다 높은 값이면 에지로 판단한다.
    • $T_low$: 해당 임계값보다 낮은 값이면 일반 픽셀로 판단한다.
    • 픽셀의 에지 특성값이 두 임계값의 중간이면 추가적인 검사를 수행한다.
      • 해당 값이 위치한 픽셀이 에지와 연결 되어있는 픽셀이면 에지, 그렇지 않으면 일반 픽셀로 판단한다.

cv::Canny

  • OpenCV에서는 캐니 에지 검출 함수를 2가지 제공한다.
  • cv::Canny(image, edges, threshold1, threshold2, apertureSize=3, L2gradient=false);
    • 일반 영상을 입력으로 받는다.
    • threshold1, threshold2: 각각 임계값의 최저, 최대치를 지정해준다.
    • edges: 입력 영상과 크기와 타입이 같은 8비트 단일 채널의 출력 영상이다.
    • apetureSize: 그래디언트 계산을 위한 소벨 마스크의 크기이다.
    • L2gradient: 그래디언트 크기 계산시 L2 Norm의 사용 여부를 지정해준다.
  • cv::Canny(dx, dy, edges, threshold1, threshold2, L2gradient=false);
    • 미분값 행렬들을 입력으로 받는다.
    • dx, dy: 타입이 CV16SC1 혹은 CV16SC3으로 지정 된 입력 영상의 x, y 방향의 미분 행렬이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "opencv2/opencv.hpp"

int main(void)
{
    cv::Mat src= cv::imread("path/to/src", cv::IMREAD_GRAYSCALE);

    cv::Mat edges1, edges2, dx, dy;

    cv::Sobel(src, dx, CV_16SC1, 1, 0);
    cv::Sobel(src, dy, CV_16SC1, 0, 1);

    cv::Canny(src, edges1, 50, 150);
    cv::Canny(dx, dy, edges2, 50, 150);

    cv::imshow("src", src);
    cv::imshow("image", edges1);
    cv::imshow("dxdy", edges2);

    cv::waitKey(0);

    cv::destroyAllWindows();

    return 0;
}
This post is licensed under CC BY 4.0 by the author.

OpenCV 마스크 에지 기반 검출

OpenCV 허프 변환 직선 검출