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

1) 에지 : 영상에서 픽셀 밝기 값이 급격히 변하는 부분으로 객체와 객체 또는 객체와 배경의 의 경계를 표현한다.

에지검출(edge detection)은 객체분할 및 인식을 위한 기본 과정 

 

2) 1차 미분의 근사화

  a) 전진차분

 

  b) 후진차분

 

c) 중앙차분

 

중앙차분을 선택 시 가장 미분을 정확히 계산하게 됨

**  h 의 최솟값 1px

 

** 미분

f(x) = x^n  

f'(x) = n*x^(n-1)

 

f(x) = sinX

f'(x) = -cosX

 

f(x) = e^x

f'(x) = e^x

 

 

3) 다양한 에지 검출마스크

  -  Prewitt (plat한 가중치)  , Sobel(가우시안 형태의 가중치 적용) , Scharr

가로방향
-1 0 1     -1  0  1             -3  0  3
-1 0 1     -2  0  2             -10 0 10
-1 0 1     -1  0  1              -3 0  3

세로방향
-1 -1 -1    -1  -2  -1         -3  -10 -3
 0  0  0     0   0   0          0   0  0
 1  1  1     1   2   1          3  10  3
 Prewitt      Sobel             Scharr

 

Sobel이 Prewitt보다 좋은 결과 얻을 수 있음.

Sharr 가 Sobel 보다 좀 더 정확하나 Sobel이 간단하고 연산도 빠르기에 Sobel 사용

 

소벨 마스크 구현

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

using namespace std;
using namespace cv;

int main()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

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

	Mat dx = Mat::zeros(src.rows, src.cols, CV_8UC1); // Gray scale 형식
	/*
	//dst 픽셀값 for문 이용해 채우기
	for (int y = 0; y < src.rows; y++) {
		for (int x = 0; x < src.cols; x++) {
			//입력영상의 픽셀값 접근 , 소벨마스크
			int v1 = src.at<uchar>(y - 1, x + 1)  // y -1 이나 x-1 이 처음에 y, x  0일 경우 -1 값으로 나오게되어 assert에러 뜸.
				+ src.at<uchar>(y, x + 1) * 2
				+ src.at<uchar>(y + 1, x + 1)
				- src.at<uchar>(y - 1, x - 1)
				- src.at<uchar>(y, x - 1) * 2
				- src.at<uchar>(y + 1, x - 1);
			//출력영상의 픽셀값 접근
			dx.at<uchar>(y, x) = saturate_cast<uchar>(v1); // 255보다 커지거나 0보다 작아질경우 staturate cast하여 uchar 변환 후 v1값을 dx에 넣기.

		}
	}
	*/
	/*
	assert error
	((unsigned)i0 < (unsigned)size.p[0])
	 에서 참이 아닌 거짓이 나온 경우 에러뜸.
	*/


	//dst 픽셀값 for문 이용해 채우기
	for (int y = 1; y < src.rows-1; y++) { //최외곽은 엣지가 적용되지 않지만 이걸 감안해서 코드작성. ( 개개별로 조건문 달면 되나 코드가 좀 더러워지기에 이 와 같이 작성함)
		for (int x = 1; x < src.cols-1; x++) {
			//입력영상의 픽셀값 접근 , 소벨마스크
			int v1 = src.at<uchar>(y - 1, x + 1) 
				+ src.at<uchar>(y, x + 1) * 2
				+ src.at<uchar>(y + 1, x + 1)
				- src.at<uchar>(y - 1, x - 1)
				- src.at<uchar>(y, x - 1) * 2
				- src.at<uchar>(y + 1, x - 1);
			//출력영상의 픽셀값 접근
			//dx.at<uchar>(y, x) = saturate_cast<uchar>(v1); // 255보다 커지거나 0보다 작아질경우 staturate cast하여 uchar 변환 후 v1값을 dx에 넣기.
			//다만 이렇게 하여 출력시 미분값 낮아지는 부분들은 그레이스케일 영상에 의해 엣지가 나타나지 않음
			dx.at<uchar>(y, x) = saturate_cast<uchar>(v1 + 128); // 미분값이 커지는 부분과 작아지는 부분 모두 엣지가 잡혀짐
		   //dx이미지에서 픽셀값이 흰색에 가까워질 정도로 밝거나 검정색에 가까워질 정도로 어두운 부분은 픽셀값의 변화가 큰 부분이다.
		}
	}
	imshow("src", src);
	imshow("dst", dx);
	waitKey();
}

 

dy도 구현하자

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

using namespace std;
using namespace cv;

int main()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

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

	Mat dx = Mat::zeros(src.rows, src.cols, CV_8UC1); // Gray scale 형식
	Mat dy = Mat::zeros(src.rows, src.cols, CV_8UC1);

	//dst 픽셀값 for문 이용해 채우기
	for (int y = 1; y < src.rows-1; y++) { //최외곽은 엣지가 적용되지 않지만 이걸 감안해서 코드작성. ( 개개별로 조건문 달면 되나 코드가 좀 더러워지기에 이 와 같이 작성함)
		for (int x = 1; x < src.cols-1; x++) {
			//입력영상의 픽셀값 접근 , 소벨마스크
			int v1 = src.at<uchar>(y - 1, x + 1)
				+ src.at<uchar>(y, x + 1) * 2
				+ src.at<uchar>(y + 1, x + 1)
				- src.at<uchar>(y - 1, x - 1)
				- src.at<uchar>(y, x - 1) * 2
				- src.at<uchar>(y + 1, x - 1);
			int v2 = src.at<uchar>(y + 1, x + 1) 
				+ src.at<uchar>(y + 1, x) * 2
				+ src.at<uchar>(y + 1, x - 1)
				- src.at<uchar>(y - 1, x + 1)
				- src.at<uchar>(y - 1, x) * 2
				- src.at<uchar>(y - 1, x - 1);
			dx.at<uchar>(y, x) = saturate_cast<uchar>(v1 + 128); // 미분값이 커지는 부분과 작아지는 부분 모두 엣지가 잡혀짐
			dy.at<uchar>(y, x) = saturate_cast<uchar>(v2 + 128);
		}
	}
	imshow("src", src);
	imshow("dx", dx);
	imshow("dy", dy);
	waitKey();
}

 

 

기둥을 보면 x축에선 미분변화값이 큼에 따라 엣지가 추출됬지만, y축에선 미분변화값이 일정하여(거의 0의 값) 엣지가 없는 걸 확인 할수 있다. (좌측)

 

입력영상에서 어느 한 방향으로만 큰 변화가 있을 경우, x방향으로의 미분과 y방향으로의 미분 모두 조합해 그 결과를  반영하여, 입력영상에서 임의의 방향에서 변화가 큰걸 모두 검출 할 수 있다.

dx, dy값을 어떻게 조합해서 변화량이 큰 부분을 모두 찾을 수 있을 지 고민을 해야한다.

 

 

2. 다양한 미분 마스크

'프로그래머스 > OPENCV' 카테고리의 다른 글

캐니 에지 검출기  (0) 2022.12.07
에지검출과 소벨필터(2)  (0) 2022.12.07
색상범위 관련  (0) 2022.12.07
특정 색상 영역 추출 하기 [다시]  (0) 2022.12.07
컬러영상처리  (0) 2022.12.07

+ Recent posts