OpenCV | 직선 검출

박나연·2021년 4월 22일
1

OpenCV

목록 보기
28/40
post-custom-banner

허프 변환 직선 검출

영상에서 직선 성분을 찾기 위해서는 우선 에지를 찾아내고, 에지 픽셀들이 일직선상에 배열되어 있는지를 확인해야 한다. 영상에서 직선을 찾기위한 용도로 허프 변환 기법이 사용되고 있다. 허프 변환은 2차원 xy좌표에서 직선의 방정식을 파라미터 공간으로 변환하여 직선을 찾는 알고리즘이다. 일반적으로 y = ax + b 와 같이 나타낼 수 있으며, 이는 b = -xa + y 로 바꿔쓸 수 있다. 이것은 ab 좌표공간안에서 기울기가 -x 이고 y절편이 y인 직선의 방정식 처럼 보인다. 이를 통해 알 수 있는 점은 xy공간에서 직선은 ab공간에서 한 점으로 표현되고, 반대로 xy공간에서 한점은 ab 공간에서 직선의 형태로 나타난다는 것이다.

그러나 y = ax + b 형태의 직선의 방정식을 사용할 경우 모든 형태의 직선을 표현하기는 어렵다는 단점이 있다. 대표적으로 y축과 평행한 수직선을 표현할 수 없으며 수직선을 표현하려면 기울기 a값이 무한대가 되어야 하기 때문이다. 따라서 허프변환을 구현할 때는

xcosa + ysina = p

위와 같이 극좌표계 형식의 직선의 방정식을 사용한다. p는 원점에서 직선까지의 수직 거리, a (세타를 대신 표현) 는 원점에서 직선에 수직선을 내렸을때 x축과 이루는 각도이다.

p와 세타값을 통해 축적 배열을 구현하기 위해서는 p와 세타가 가질 수 있는 값의 범위를 적당한 크기로 나눠서 저장하는 양자화 과정을 거쳐야 한다.

OpenCV에서는 HoughLines() 함수를 사용하여 허프 변환 직선 검출을 수행할 수 있다.

HoughLines()

void HoughLines(InputArray image, OutputArray lines, 
double rho, double theta, int threshold, 
double srn = 0, double stn = 0,
double min_theta = 0, double max_theta = CV_PI);

image : 8비트 단일 채널 입력영상, 주로 에지 영상
lines : 직선 정보를 저장할 출력 벡터
rho : 축적배열에서 p값의 해상도
theta : 축적배열에서 세타 값의 해상도
threshold : 축적배열에서 직선으로 판단할 임계값
srn : 멀티스케일 허프 변환에서 rho해상도를 나누는 값
stn : 멀티스케일 허프 변환에서 theta해상도를 나누는 값
min_theta : 검출할 직선의 최소 theta값
max_theta : 검출할 직선의 최대 theta값

void hough_lines() {
	Mat src = imread("building.jpg", IMREAD_GRAYSCALE);

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

	Mat edge;
	Canny(src, edge, 50, 150);

	vector<Vec2f> lines;
	HoughLines(edge, lines, 1, CV_PI / 180, 250);

	Mat dst;
	cvtColor(edge, dst, COLOR_GRAY2BGR);

	for (size_t i = 0; i < lines.size(); i++) {
		float r = lines[i][0], t = lines[i][1];
		double cos_t = cos(t), sin_t = sin(t);
		double x0 = r * cos_t, y0 = r * sin_t;
		double alpha = 1000;

		Point pt1(cvRound(x0 + alpha * (-sin_t)), cvRound(y0 + alpha * cos_t));
		Point pt2(cvRound(x0 - alpha * (-sin_t)), cvRound(y0 - alpha * cos_t));
		line(dst, pt1, pt2, Scalar(0, 0, 255), 2, LINE_AA);
	}

	imshow("src", src);
	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}


확률적 허프변환

OpenCV는 기본적인 허프 변환 직선 검출 방법 외에 확률적 허프 변환에 의한 직선 검출 방법도 제공한다. 확률적 허프 변환 방법은 직선의 방정식 파라미터 p와 세타를 반환하는 것이 아닌 직선의 시작점과 끝점 좌표를 반환한다. 즉, 선분을 찾는 방법이다. 이는 HoughLinesP() 함수에 구현되어 있다.

HoughLinesP()

void HoughLinesP(InputArray image, OutputArray lines,
double rho, doubule theta, int threshold,
double minLineLength = 0, double maxLineGap = 0);

image : 8비트 단일 채널 입력 영상
lines : 선분의 시작점과 끝점의 정보를 저장할 출력 벡터
rho : 축적 배열에서 p값의 해상도
theta : 축적 배열에서 세타 값의 해상도
threshold : 축적 배열에서 직선으로 판단할 임계값
minLineLength : 검출할 선분의 최소길이
maxLineGap : 직선으로 간주할 최대 에지 점 간격

void hough_line_segments() {
	Mat src = imread("building.jpg", IMREAD_GRAYSCALE);

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

	Mat edge;
	Canny(src, edge, 50, 150);

	vector<Vec4i> lines;
	HoughLinesP(edge, lines, 1, CV_PI / 180, 160, 50, 5);

	Mat dst;
	cvtColor(edge, dst, COLOR_GRAY2BGR);

	for (Vec4i l : lines) {
		line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 2, LINE_AA);
	}

	imshow("src", src);
	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}

실제 직선에만 선이 그어진 모습

profile
Data Science / Computer Vision
post-custom-banner

0개의 댓글