Edge detection
Peponi │ 5/15/2025 │ 11m
Edge detection
Peponi
1. Introduction
사람이 시각을 통해 사물을 인식하는 경우, 객체 형상에 대한 특징 (질감, 모양 등) 을 이용하여 판단하게 된다. 컴퓨터 또한 이미지 프로세싱을 통해 형상에 대한 특징을 추론하여 적절한 객체 인식을 수행할 수 있다. 이 때, 형상에 대한 감지 기법 중 하나로 edge detection
을 활용할 수 있다.
Edge는 이미지상 서로 다른 영역의 경계에서 발생하는 밝기, 색상의 변화가 급변하는 지점을 의미한다. Edge detection은 커널을 활용해 컨볼루션 연산을 수행함으로써 미분 값을 근사적으로 계산하며, 이 과정을 통해 객체의 외관에 대한 특징을 찾아낼 수 있다.
Edge detection은 주로 다음과 같은 상황에 활용할 수 있다.
- 객체 인식, 분류
감시 카메라와 같은 비전 시스템의 경우 edge를 활용하여 사람, 자동차 등을 인식할 수 있다. - ROI 분할
이미지 영역 중 문서에 해당하는 부분만 추출하는 등 ROI를 세분화하여 분석에 활용할 수 있다. - 이미지 압축
이미지의 디테일한 정보가 필요 없는 경우, edge만 추출하여 저장함으로써 데이터 양을 줄일 수 있다.
이 문서에서는 edge detection을 수행할 수 있는 방법에 대해 간략하게 소개한다.
실습에 사용할 이미지는 다음과 같다.

2. Filter2D



Mat.Filter2D()
메서드는 이미지 필터링에 사용되는 메서드로, 커널을 이용한 correlation 연산을 수행한다. 커널을 구성하기에 따라 블러, 샤프닝 등의 효과를 얻을 수 있으며 엣지를 검출하는 것 또한 가능하다.
기초적인 커널의 모양은 다음과 같다.
Mat.Filter2D()
를 이용한 edge detection은 가장 기초적인 방법으로, 후술하는 다른 방법들은 이 과정을 간략하게 수행할 수 있도록 편의 기능을 제공해 주는 것으로 이해할 수 있다. 여기서는 Sobel edge detection을 수행하는 커널을 구성하고 연산을 수행하는 예시를 보여준다.
private void Filter2D(Mat image)
{
// Sobel example
// Kernel 생성
float[] weightX = [-1,0,1,
-2,0,2,
-1,0,1];
float[] weightY = [-1,-2,-1,
0,0,0,
1,2,1];
using var kernelX = Mat.FromPixelData(3, 3, MatType.CV_32FC1, weightX);
using var kernelY = Mat.FromPixelData(3, 3, MatType.CV_32FC1, weightY);
using var edgeX = image.Filter2D(-1, kernelX);
using var edgeY = image.Filter2D(-1, kernelY);
using var edgeXYMerged = edgeX + edgeY;
Cv2.ImShow("Filter Edge X", edgeX);
Cv2.ImShow("Filter Edge Y", edgeY);
Cv2.ImShow("Filter Edge X+Y", edgeXYMerged);
}
3. Sobel



Sobel edge detection
은 Mat.Filter2D()
를 이용하는 대표적인 방법 중 하나로, 수평과 수직 방향의 edge를 따로 계산하여 전체 edge를 구할 수 있다.
Sobel 연산에 사용되는 기본적인 커널의 모양은 다음과 같다.
private void Sobel(Mat image)
{
// Sobel(depth, xorder, yorder, ...)
using var sobelX = image.Sobel(-1, 1, 0);
using var sobelY = image.Sobel(-1, 0, 1);
using var sobelXYMerged = sobelX + sobelY;
Cv2.ImShow("Sobel X", sobelX);
Cv2.ImShow("Sobel Y", sobelY);
Cv2.ImShow("Sobel X+Y", sobelXYMerged);
}
4. Scharr



Scharr edge detection
은 Sobel 커널에 비해 중심부 픽셀의 가중치가 크게 적용된다. 일반적으로 커널을 사용하거나 대각 엣지를 검출하는 경우 Sobel 연산보다 유리할 수 있다고 알려져 있다. Sobel 연산과 달리, Scharr 연산은 커널만을 사용한다.
Scharr 연산에 사용되는 커널의 모양은 다음과 같다.
private void Scharr(Mat image)
{
// Scharr(depth, xorder, yorder, ...)
using var scharrX = image.Scharr(-1, 1, 0);
using var scharrY = image.Scharr(-1, 0, 1);
using var scharrXYMerged = scharrX + scharrY;
Cv2.ImShow("Scharr X", scharrX);
Cv2.ImShow("Scharr Y", scharrY);
Cv2.ImShow("Scharr X+Y", scharrXYMerged);
}
5. Laplacian
Laplacian edge detection
또한 커널을 이용한 연산을 수행한다. 앞선 방법들과는 달리, Laplacian 연산은 모든 방향의 2차 미분 값을 더하는 방식으로 동작하며 라플라시안이 0이 되는 지점 (zero crossing point) 이 엣지가 된다. 또한 라플라시안 커널의 특성상 엣지의 방향에 대한 정보는 찾기 어렵다.
Laplacian edge detection은 노이즈에 취약한 관계로 가우시안 블러를 통해 노이즈를 제거한 후 수행하는 것이 일반적이다. 이 방법을 LoG (Laplacian of Gaussian)
라고 한다.
Laplacian 연산에 사용되는 일반적인 커널의 모양은 다음과 같다. (OpenCV의 Mat.Laplacian()
은 ksize = 1
인 경우 이 커널을 사용한다)
경우에 따라서는 다음과 같이 커널을 구성하기도 한다.
private void Laplacian(Mat image)
{
using var gaussian = image.GaussianBlur(new OpenCvSharp.Size(3, 3), 0);
//아래 Laplacian() 호출의 ksize가 1인 경우, 다음 주석 과정과 동일함
//float[] weight = [0,1,0,
// 1,-4,1,
// 0,1,0];
//using var kernel = Mat.FromPixelData(3, 3, MatType.CV_32FC1, weight);
//using var edge = gaussian.Filter2D(-1, kernel);
//Cv2.ImShow("Laplacian Edge", edge);
// Laplacian(depth, ksize, ...)
using var laplacian = gaussian.Laplacian(-1, 3);
Cv2.ImShow("Laplacian", laplacian);
}
6. Canny
Canny edge detection
은 이미지 프로세싱에서 엣지를 검출하는데 가장 많이 사용하는 방법 중 하나이다. 단계적으로 알고리즘이 구성되어 있으며 노이즈에 강하고 엣지를 얇고 정확하게 찾을 수 있는 특징이 있다. Canny 엣지 검출은 다음과 같은 단계를 거쳐 수행된다.
- Gaussian blur
이미지에서 노이즈를 제거하기 위해 Gaussian blur를 적용한다. - Sobel edge detection
노이즈가 제거된 이미지에 Sobel 커널을 이용하여 X, Y 방향의 gradient를 구한다. - Non-maximum suppression
계산된 gradient 방향에 놓인 주변 픽셀과의 gradient 크기를 비교한다. 픽셀의 gradient 크기가 주변보다 작다면 픽셀 값을 0으로 바꾸어준다. 이 과정에서 엣지가 간결하게 정리된다. - Thresholding
간결해진 엣지 정보를 대상으로 thresholding을 수행한다. 지정한 min보다 작은 경우 엣지에서 제외하며, max보다 큰 경우 확실하게 엣지로 보존한다. min ~ max 사이 값의 경우 확실한 엣지와의 연결 여부를 따져 엣지로 보존한다.
상기 과정을 거쳐 보존된 엣지 정보가 최종 결과로 출력된다. 다음은 canny edge detection을 수행하는 코드이다.
private void Canny(Mat image)
{
// Grayscale 변환
// Color 이미지에도 canny edge detection이 적용 가능하지만, 흑백 이미지에서 더 잘 작동하는 것으로 알려져 있다.
using var grayscale = image.CvtColor(ColorConversionCodes.BGR2GRAY);
// Canny(threshold_min, threshold_max, ...)
// max값을 넘어서는 pixel은 바로 엣지로 취급
// min ~ max 사이의 pixel은 확실한 엣지와 연결이 되어 있는 경우 엣지로 취급
// min보다 낮은 pixel은 엣지에서 제외
using var canny = grayscale.Canny(100, 200);
Cv2.ImShow("Canny", canny);
}
7. Gradient
미분을 이용하는 앞선 과정들과는 달리, gradient는 형태 차이 (팽창과 침식의 차이) 를 이용하여 엣지를 찾는 방법이다. Dilation - erosion을 수행하며, 계산 과정에서 객체의 경계 부분만 남게 되어 간단하게 엣지를 검출하는 데 사용된다.
private void Gradient(Mat image)
{
using var grayscale = image.CvtColor(ColorConversionCodes.BGR2GRAY);
using var binary = grayscale.Threshold(200, 255, ThresholdTypes.Binary);
using var kernel = Mat.Ones(3, 3, MatType.CV_8UC1);
using var transformed = binary.MorphologyEx(MorphTypes.Gradient, kernel);
Cv2.ImShow("Gradient", transformed);
}