에지검출과 소벨필터

전종원·2022년 11월 2일
0

1. 에지검출과 영상의 미분

엣지란

  • 영상에서 픽셀의 밝기 값이 급격하게 변하는 부분
  • 일반적으로 배경과 객체, 또는 객체와 객체의 경계

기본적인 에지 검출방법

  • 영상을 (x,y) 변수의 함수로 간주했을 때, 이 함수의 1차 미분값이 크게 나타나는 부분을 검출
  • 입력영상에 가우시안 블러를 적용하여 잡음을 제거한 후 에지를 검출하는 것이 바람직함

1차미분의 근사화

다양한 에지검출 마스크

실습코드

#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

void sobel_impl();

int main()
{
	sobel_impl();
}

void sobel_impl()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat dx = Mat::zeros(src.size(), CV_8UC1);
	Mat dy = Mat::zeros(src.size(), CV_8UC1);
	Mat mag = Mat::zeros(src.size(), CV_8UC1);

	for (int j = 1; j < src.rows - 1; j++) {
		for (int i = 1; i < src.cols - 1; i++) {
			int v1 = src.at<uchar>(j - 1, i + 1)
				+ src.at<uchar>(j, i + 1) * 2
				+ src.at<uchar>(j + 1, i + 1)
				- src.at<uchar>(j - 1, i - 1)
				- src.at<uchar>(j, i - 1) * 2
				- src.at<uchar>(j + 1, i - 1);
			int v2 = src.at<uchar>(j + 1, i + 1)
				+ src.at<uchar>(j + 1, i) * 2
				+ src.at<uchar>(j + 1, i + 1)
				- src.at<uchar>(j - 1, i + 1)
				- src.at<uchar>(j - 1, i) * 2
				- src.at<uchar>(j - 1, i + 1);
			dx.at<uchar>(j, i) = saturate_cast<uchar>(v1 + 128);
			dy.at<uchar>(j, i) = saturate_cast<uchar>(v2 + 128);
			mag.at<uchar>(j, i) = saturate_cast<uchar>(sqrt(v1 * v1 + v2 * v2));
		}
	}

	Mat edge = mag > 120;

	imshow("src", src);
	imshow("dx", dx);
	imshow("dy", dy);
	imshow("mag", mag);
	imshow("edge", edge);

	waitKey();
	destroyAllWindows();
}

결과영상

2. 그래디언트와 소벨필터

영상의 그래디언트

  • 함수 f(x,y)를 x축과 y축으로 각각 편미분하여 벡터 형태로 표현한 것
  • 그래디언트 크기: 픽셀 값의 차이 정도, 변화량
  • 그래디언트 방향: 픽셀 값이 가장 급격하게 증가하는 방향

magnitude image(그래디언트 크기로 계산)

OpenCV sobel filter

void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, 
		   double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT);
  • src: 입력영상
  • dst: 출력영상. src와 같은 크기, 같은 채널 수
  • ddepth: 출력 영상 깊이
  • dx, dy: x방향과 y방향으로의 미분 차수
  • ksize: 커널 크기
  • scale: 연산 결과에 추가적으로 곱할 값
  • delta: 연산결과에 추가적으로 더할 값
  • borderType: 가장자리 픽셀 확장 방식

OpenCV 2D 벡터의 크기 계산 함수

void magnitude(InputArray x, InputArray y, OutputArray magnitude);
  • x: 2D벡터의 x좌표 행렬. 실수형.
  • y: 2D벡터의 y좌표 행렬. x와 같은 크기. 실수형.
  • magnitude: 2D 벡터의 크기 행렬. x와 같은 크기, 같은 타입

OpenCV 2D 벡터의 방향 계산 함수

void phase(InputArray, x, InputArray y, OutputArray angle, bool angleInDegrees = false);
  • x: 2D벡터의 x좌표 행렬. 실수형.
  • y: 2D벡터의 y좌표 행렬. x와 같은 크기. 실수형.
  • angle: 2D벡터의 크기행렬. x와 같은 크기, 같은 타입.
  • angleInDegrees: true이면 각도 단위, false이면 radian 단위.

sobel 실습 코드

void sobel_func()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat dx, dy;
	Sobel(src, dx, CV_32FC1, 1, 0);
	Sobel(src, dy, CV_32FC1, 0, 1);

	Mat mag;
	magnitude(dx, dy, mag);
	mag.convertTo(mag, CV_8UC1);

	Mat edge = mag > 150;

	imshow("src", src);
	imshow("mag", mag);
	imshow("edge", edge);

	waitKey();
	destroyAllWindows();
}

결과영상

0개의 댓글