본문 바로가기

OpenCV

OpenCV 에지 검출

반응형

 

에지 검출은 이미지 내 객체나 영역의 경계(에지)를 식별하는 데 사용되는 이미지 처리 기술입니다. 에지는 이미지와 관련된 가장 중요한 특징 중 하나입니다. 우리는 에지를 통해 이미지의 기본 구조를 파악합니다. 따라서 컴퓨터 비전 처리 파이프라인은 애플리케이션에서 에지 검출을 광범위하게 사용합니다.

 

 

 

Table of Contents

  1. 에지는 어떻게 감지되나요?
  2. 소벨 에지 감지
  3. 캐니 에지 감지
  4. 요약

 

에지는 어떻게 감지되나요?

 

픽셀 강도의 급격한 변화는 에지의 특징입니다. 에지를 감지하려면 인접 픽셀의 이러한 변화를 살펴봐야 합니다. OpenCV에서 사용할 수 있는 두 가지 중요한 에지 감지 알고리즘인 소벨 에지 감지(Sobel Edge Detection)와 캐니 에지 감지(Canny Edge Detection)를 살펴보겠습니다. 이 알고리즘의 이론을 살펴보고 OpenCV에서 각 알고리즘을 사용하는 방법을 시연합니다.

 

먼저, 에지 감지를 보여주는 코드를 살펴보겠습니다. 각 코드 줄을 자세히 설명하여 완전히 이해할 수 있도록 하겠습니다.

 

파이썬:

 

import cv2
 
# Read the original image
img = cv2.imread('test.jpg') 
# Display original image
cv2.imshow('Original', img)
cv2.waitKey(0)
 
# Convert to graycsale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Blur the image for better edge detection
img_blur = cv2.GaussianBlur(img_gray, (3,3), 0) 
 
# Sobel Edge Detection
sobelx = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=5) # Sobel Edge Detection on the X axis
sobely = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=0, dy=1, ksize=5) # Sobel Edge Detection on the Y axis
sobelxy = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=1, ksize=5) # Combined X and Y Sobel Edge Detection
# Display Sobel Edge Detection Images
cv2.imshow('Sobel X', sobelx)
cv2.waitKey(0)
cv2.imshow('Sobel Y', sobely)
cv2.waitKey(0)
cv2.imshow('Sobel X Y using Sobel() function', sobelxy)
cv2.waitKey(0)
 
# Canny Edge Detection
edges = cv2.Canny(image=img_blur, threshold1=100, threshold2=200) # Canny Edge Detection
# Display Canny Edge Detection Image
cv2.imshow('Canny Edge Detection', edges)
cv2.waitKey(0)
 
cv2.destroyAllWindows()

 

C++:

 

#include <opencv2/opencv.hpp>
#include <iostream>
// using namespaces to nullify use of cv::function(); syntax and std::function();
using namespace std;
using namespace cv;
 
int main()
{
    // Reading image
    Mat img = imread("test.jpg");
    // Display original image
    imshow("original Image", img);
    waitKey(0);
 
    // Convert to graycsale
    Mat img_gray;
    cvtColor(img, img_gray, COLOR_BGR2GRAY);
    // Blur the image for better edge detection
    Mat img_blur;
    GaussianBlur(img_gray, img_blur, Size(3,3), 0);
     
    // Sobel edge detection
    Mat sobelx, sobely, sobelxy;
    Sobel(img_blur, sobelx, CV_64F, 1, 0, 5);
    Sobel(img_blur, sobely, CV_64F, 0, 1, 5);
    Sobel(img_blur, sobelxy, CV_64F, 1, 1, 5);
    // Display Sobel edge detection images
    imshow("Sobel X", sobelx);
    waitKey(0);
    imshow("Sobel Y", sobely);
    waitKey(0);
    imshow("Sobel XY using Sobel() function", sobelxy);
    waitKey(0);
 
    // Canny edge detection
    Mat edges;
    Canny(img_blur, edges, 100, 200, 3, false);
    // Display canny edge detected image
    imshow("Canny edge detection", edges);
    waitKey(0);
     
    destroyAllWindows();
    return 0;
}

 

 

시스템에 이미 OpenCV가 설치되어 있다고 가정합니다. OpenCV를 설치해야 하는 경우 아래 관련 링크를 방문하세요.

 

Windows에 OpenCV 설치

MacOS에 OpenCV 설치

Ubuntu에 OpenCV 설치

 

이 호랑이 이미지는 여기의 모든 예시에 사용됩니다.

 

OpenCV를 사용하여 엣지 감지를 위한 입력 이미지입니다.

 

 

에지 감지에 사용되는 이미지

 

각 알고리즘을 자세히 살펴보기 전에, 에지 검출을 위한 몇 가지 예비 단계를 살펴보겠습니다. 아래 코드와 같이 OpenCV 라이브러리를 임포트하는 것으로 시작합니다.

 

파이썬:

 

import cv2

 

C++:

 

#include<opencv2/opencv.hpp>
#include<iostream>
 
// Namespace nullifies the use of cv::function(); 
using namespace std;
using namespace cv;

 

 

imread()첫 번째 단계는 OpenCV의 함수를 사용하여 이미지를 읽는 것입니다 .

 

여기서는 경계선을 감지하는 데 색상 정보가 필요하지 않으므로 컬러 이미지를 회색조 이미지로 읽어옵니다. 자세한 내용은 " OpenCV를 사용하여 이미지 읽기, 표시 및 쓰기" 를 참조하세요 .

 

이미지를 읽은 후, GaussianBlur()함수를 사용하여 이미지를 블러 처리합니다. 이는 이미지의 노이즈를 줄이기 위한 것입니다. 에지 검출에서는 픽셀 강도의 수치적 미분을 계산해야 하는데, 이로 인해 일반적으로 '노이즈가 있는' 에지가 생성됩니다. 다시 말해, 이미지 내 인접 픽셀(특히 에지 근처)의 강도가 상당히 변동하여 우리가 찾고 있는 주된 에지 구조를 나타내지 않는 에지가 생성될 수 있습니다.

 

블러링은 가장자리 근처의 강도 변화를 부드럽게 하여 이미지 내에서 두드러진 가장자리 구조를 더 쉽게 식별할 수 있도록 합니다. 이 함수 에 대한 자세한 내용은 OpenCV 문서GaussianBlur() 를 참조하세요 . 블러링의 정도를 지정하는 컨볼루션 커널 크기(이 경우 1 3×3 커널)를 제공합니다.

 

파이썬:

 

# Read the original image
img = cv2.imread('test.jpg',flags=0)  
# Blur the image for better edge detection
img_blur = cv2.GaussianBlur(img,(3,3), SigmaX=0, SigmaY=0)

 

C++:

 

// Reading image
Mat img = imread("test.jpg",0);
// Blur the image for better edge detection
Mat img_blur;
GaussianBlur(img, img_blur, Size(3,3), SigmaX=0, SigmaY=0);

 

 

Sobel 소벨 에지 감지

 

소벨 에지 검출(Sobel Edge Detection)은 에지 검출에 가장 널리 사용되는 알고리즘 중 하나입니다. 소벨 연산자는 아래 그림과 같이 픽셀 강도의 급격한 변화로 표시된 에지를 검출합니다.

 

 

t의 함수로서 픽셀 강도의 그래프, t의 함수로서의 픽셀 강도( 출처 )

 

강도 함수의 1차 도함수를 그래프로 나타내면 강도의 증가가 더욱 뚜렷하게 나타납니다.

 

 

t의 함수로서 픽셀 강도의 1차 미분 그래프, t의 함수로서 픽셀 강도의 1차 도함수( 출처 )

 

위 그림은 기울기가 특정 임계값보다 높은 영역에서 에지를 감지할 수 있음을 보여줍니다. 또한, 미분의 급격한 변화는 픽셀 강도의 변화를 나타냅니다. 이를 염두에 두고 3×3 커널을 사용하여 미분을 근사할 수 있습니다. 한 커널은 X 방향의 픽셀 강도의 급격한 변화를 감지하고, 다른 커널은 Y 방향의 픽셀 강도의 급격한 변화를 감지합니다. (자세한 내용은 이미지 필터링 및 합성곱 커널 에 대한 이 게시물을 참조하세요 .)

 

Sobel Edge Detection에 사용되는 커널은 다음과 같습니다.

 

 

X-Direction 커널

 

 

Y-Direction 커널

 

이러한 커널을 원본 이미지와 합성하면 '소벨 에지 이미지'를 얻습니다.

 

  • 수직 커널만 사용하는 경우 합성은 X 방향으로 모서리가 강화된 Sobel 이미지를 생성합니다.
  • 수평 커널을 사용하면 Y 방향으로 모서리가 강조된 Sobel 이미지가 생성됩니다.

 

Gx와 Gy를 각각 x와 y방향으로 강도 기울기를 나타냅니다. A와 B는위에서 정의한 X와 Y 커널을 나타냅니다.

 

 

 

 

 

여기서  * 는 합성 연산자를 나타내고, I는 입력 이미지를 나타냅니다.

 

기울기 크기의 최종 근사값은 G다음과 같이 계산할 수 있습니다.

 

 

 

 

그러면 기울기의 방향은 다음과 같이 근사화할 수 있습니다.

 

 

아래 코드 예제에서는 Sobel()함수를 사용하여 다음을 계산합니다.

 

  • 소벨 에지 이미지를 양방향(x 및 y)으로 개별적으로 표시합니다,
  • 두 방향(xy)의 합성 그래디언트

 

다음은 OpenCV를 사용하여 Sobel 에지 감지를 적용하기 위한 구문입니다.

 

Sobel(src, ddepth, dx, dy)

 

매개변수는 ddepth출력 이미지의 정밀도를 지정하고, 과 는 dx각 dy방향의 미분 순서를 지정합니다. 예를 들면 다음과 같습니다.

 

  • 만약 dx=1와 이면 dy=0, x방향으로 1차 미분 소벨 이미지를 계산합니다.

 

dx=1와 둘 다인 경우 dy=1, 우리는 양방향으로 1차 미분 Sobel 이미지를 계산합니다.

 

파이썬:

 

# Sobel Edge Detection
sobelx = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=5) # Sobel Edge Detection on the X axis
sobely = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=0, dy=1, ksize=5) # Sobel Edge Detection on the Y axis
sobelxy = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=1, ksize=5) # Combined X and Y Sobel Edge Detection
 
# Display Sobel Edge Detection Images
cv2.imshow('Sobel X', sobelx)
cv2.waitKey(0)
 
cv2.imshow('Sobel Y', sobely)
cv2.waitKey(0)
 
cv2.imshow('Sobel X Y using Sobel() function', sobelxy)
cv2.waitKey(0)

 

C++:

 

// Sobel edge detection
Mat sobelx, sobely, sobelxy;
Sobel(img_blur, sobelx, CV_64F, 1, 0, 5);
Sobel(img_blur, sobely, CV_64F, 0, 1, 5);
Sobel(img_blur, sobelxy, CV_64F, 1, 1, 5);
 
// Display Sobel edge detection images
imshow("Sobel X", sobelx);
waitKey(0);
imshow("Sobel Y", sobely);
waitKey(0);
imshow("Sobel XY using Sobel() function", sobelxy);
waitKey(0);

 

결과는 아래 그림에 나와 있습니다. x 방향의 소벨 이미지가 수직 에지(즉, x 방향, 즉 수평 방향에서 기울기가 가장 큰 에지)를 주로 식별하는 방식을 살펴보세요. 그리고 y 방향의 소벨 이미지는 수평 에지(즉, y 방향, 즉 수직 방향에서 기울기가 가장 큰 에지)를 식별하는 방식을 살펴보세요. 두 이미지에서 호랑이 줄무늬를 자세히 살펴보세요. 줄무늬의 강한 수직 에지가 x 방향의 소벨 이미지에서 더 뚜렷하게 나타나는 것을 확인할 수 있습니다.

 

X-kernel을 사용하여 Sobel Edge Detection으로 얻은 이미지

 

X 방향으로 에지가 강화된 Sobel 에지 이미지

 

Y-커널을 사용하여 Sobel Edge Detection으로 얻은 이미지

 

Y 방향으로 강화된 모서리가 있는 Sobel Edge 이미지

 

아래 그림은 두 방향의 그래디언트에 대한 소벨 이미지를 보여줍니다. 이는 원본 이미지를 에지 구조 표현으로 정제하여 구조적 무결성을 그대로 유지합니다.

 

커널을 사용하여 Sobel Edge Detection을 통해 얻은 이미지

 

 

XY 방향으로 에지가 강화된 Sobel Edge 이미지

 

캐니 에지 감지

 

캐니 에지 검출(Canny Edge Detection)은 매우 강력하고 유연하기 때문에 오늘날 가장 널리 사용되는 에지 검출 방법 중 하나입니다. 알고리즘 자체는 이미지에서 에지를 추출하는 3단계 프로세스를 따릅니다. 여기에 노이즈를 줄이기 위한 필수 전처리 단계인 이미지 블러링(Image Bluring)이 추가됩니다. 따라서 4단계 프로세스로 구성되며, 다음과 같습니다.

 

  1. 소음 감소
  2. 이미지의 강도 기울기 계산
  3. 거짓 모서리 억제
  4. 히스테리시스 임계값

 

소음 감소

 

원시 이미지 픽셀은 종종 노이즈가 많은 가장자리를 초래할 수 있으므로, 가장자리를 계산하기 전에 노이즈를 줄이는 것이 중요합니다. 캐니 가장자리 검출(Canny Edge Detection)에서는 가우시안 블러 필터를 사용하여 원치 않는 가장자리를 유발할 수 있는 불필요한 디테일을 제거하거나 최소화합니다. 아래 두 이미지의 호랑이를 살펴보세요. 오른쪽 이미지에는 가우시안 블러가 적용되었습니다. 보시다시피 약간 흐릿해 보이지만, 여전히 상당한 양의 디테일이 남아 있어 가장자리를 계산할 수 있습니다. 블러링 에 대해 자세히 알아보려면 이 링크를 클릭하세요 .

 

 

원본 이미지와 흐릿한 이미지 비교, 원본 이미지와 흐릿한 이미지 비교

 

이미지의 강도 기울기 계산

 

이미지가 평활화(흐리게 처리)되면, 수평 및 수직 방향으로 소벨 커널을 사용하여 필터링합니다. 이러한 필터링 연산의 결과는 아래와 같이 각 픽셀의 강도 기울기 크기( G)와 방향( )을 계산하는 데 사용됩니다.\세타

 

 

 

 

 

 

 

그런 다음 기울기 방향을 가장 가까운 45도 각도로 반올림합니다. 아래 그림(오른쪽)은 이 결합된 처리 단계의 결과를 보여줍니다.

 

 

소벨 필터로 얻은 이미지와 원본 이미지 비교, 원본과 소벨 필터 이미지 비교

 

잘못된 가장자리 억제

 

이 단계에서 알고리즘은 노이즈를 줄이고 강도 기울기를 계산한 후, 비최대값 에지 억제(non-maximum suppression of edges)라는 기법을 사용하여 원치 않는 픽셀(실제로는 에지가 아닐 수 있음)을 필터링합니다. 이를 위해 각 픽셀을 양수 및 음수 기울기 방향으로 인접 픽셀과 비교합니다. 현재 픽셀의 기울기 크기가 인접 픽셀보다 크면 변경되지 않습니다. 그렇지 않으면 현재 픽셀의 크기는 0으로 설정됩니다. 다음 이미지는 예시를 보여줍니다. 보시다시피, 호랑이 털과 관련된 수많은 '에지'가 상당히 억제되었습니다.

 

Sobel Filter를 이용하여 얻은 영상과 Non-maximum Suppression을 이용하여 얻은 영상의 비교

 

 

Sobel 필터 이미지와 비최대 억제 이미지 비교

 

 

히스테리시스 임계값 설정 - OpenCV를 사용한 에지 감지

 

캐니 에지 검출의 마지막 단계에서는 그래디언트 크기를 두 개의 임계값과 비교하는데, 두 임계값 중 하나는 다른 하나보다 작습니다.

 

  • 그래디언트 크기 값이 더 큰 임계값보다 높으면 해당 픽셀은 솔리드 에지와 연관되고 최종 에지 맵에 포함됩니다.
  • 그래디언트 크기 값이 작은 임계값보다 낮으면 픽셀이 억제되고 최종 에지 맵에서 제외됩니다.
  • 이 두 임계값 사이에 그래디언트 크기가 있는 다른 모든 픽셀은 '약한' 에지로 표시됩니다(즉, 최종 에지 맵에 포함될 후보가 됩니다).
  • '약한' 픽셀이 단단한 모서리와 연관된 픽셀에 연결되어 있는 경우 최종 모서리 맵에도 포함됩니다.

 

다음은 OpenCV를 사용하여 Canny 엣지 감지를 적용하기 위한 구문입니다.

 

Canny(image, threshold1, threshold2)

 

아래 코드 예제에서 Canny()함수는 위에서 설명한 방법론을 구현합니다. 캐니 에지 검출 알고리즘에 사용되는 두 개의 임계값을 제공하고, OpenCV가 모든 구현 세부 사항을 처리합니다. Canny()함수를 호출하기 전에 이미지를 블러 처리하는 것을 잊지 마세요. 이는 매우 권장되는 전처리 단계입니다. 선택 인수에 대한 자세한 내용은 OpenCV 설명서 페이지를 참조하세요.

 

파이썬:

 

# Canny Edge Detection
edges = cv2.Canny(image=img_blur, threshold1=100, threshold2=200) 
 
# Display Canny Edge Detection Image
cv2.imshow('Canny Edge Detection', edges)
cv2.waitKey(0)

 

C++:

 

// Canny edge detection
Mat edges;
Canny(img_blur, edges, 100, 200, 3, false);
// Display canny edge detected image
imshow("Canny edge detection", edges);
waitKey(0);

 

 

최종 결과는 다음과 같습니다. 하한 임계값은 100, 상한 임계값은 200을 사용했습니다. 보시다시피, 알고리즘은 이미지에서 두드러지는 가장자리를 식별하고 전체 구조에 덜 중요한 가장자리를 제거하는 과정을 거쳤습니다. 하지만 결과는 쉽게 조정할 수 있으므로 다양한 이미지로 실험하고, 흐림 정도를 조절하고, 임계값을 다양하게 변경하여 직접 느껴보세요.

 

Canny Edge Detection으로 얻은 호랑이의 Edge Enhanced 이미지

 

 

Canny Edge Detection 후 최종 이미지

 

성능 측면에서 Canny Edge Detection은 Sobel Edge Detection뿐 아니라 Non-Maximum Suppression과 Hysteresis Thresholding을 모두 사용하기 때문에 최상의 결과를 제공합니다. 이는 알고리즘의 최종 단계에서 Edge를 식별하고 연결하는 방식에 더 큰 유연성을 제공합니다.

 

요약

 

에지 검출이 중요한 이미지 처리 기법인 이유를 논의하고, 가장 중요한 두 가지 알고리즘(소벨 에지 검출과 캐니 에지 검출)에 대해 집중적으로 살펴보았습니다. OpenCV에서 이 두 알고리즘의 활용을 시연하는 동시에, 블러링이 중요한 전처리 단계인 이유를 강조했습니다.

 

또한 Canny Edge Detection이 실제로 Sobel 연산자를 사용하여 수치 미분을 계산하는 방법을 살펴보았습니다. 이 방법은 견고하고 유연하며, 비최대값 억제(Non-Maximum Suppression)와 히스테리시스 임계값 설정(Hysteresis Thresholding)을 최대한 활용합니다. 마지막으로, Canny Edge Detection이 에지 감지에 가장 선호되고 널리 사용되는 방법인 이유를 이해했습니다.

 

이 게시물에서 논의된 모든 코드는 이 링크에서 찾을 수 있습니다 → OpenCV Colab Notebook을 사용한 에지 감지

 

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^