[OpenCV] 1. 외곽선 응용

[OpenCV] 1. 외곽선 응용

이전 글에서 findContours 함수를 이용하여 외곽선을 검출하였습니다.

이렇게 검출한 외곽선 정보에서 객체의 위치, 크기 등의 정보를 추출하는 방법에 대해서 알아보겠습니다.

객체를 감싸는 사각형, 원 구하는 함수

함수부터 빠르게 알아보겠습니다.

외곽선 정보에서 바운딩 박스를 구하기 위해서 boundingRect  함수를 사용합니다.

/** 
@param array 외곽선 정보
 */
Rect boundingRect( InputArray array );

객체를 최소한으로 감싸는 사각형을 구하는 함수는 minAreaRect 함수 입니다.

/** 
@param points 외곽선 정보
 */
RotatedRect minAreaRect( InputArray points );

객체를 최소한으로 감싸는 원을 구하는 함수는 minEnclosingCircle 함수 입니다.

/** 
@param points 외곽선 정보
@param center 원의 중심 좌표 반환
@param radius 원의 반지름 반환
 */
void minEnclosingCircle( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius );

샘플 코드는 아래와 같습니다.

Mat src = imread("alphabet_d.png", IMREAD_GRAYSCALE);
if (src.empty())
{
	cerr << "image open error" << endl;
	return -1;
}

vector<vector<Point>> contours;
findContours(src, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

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

for (int iIndex = 0 ; iIndex < contours.size() ; iIndex++)
{
	vector<Point> pnts = contours.at(iIndex);
	// 바운딩 박스
	Rect rc = boundingRect(pnts);
	rectangle(dst, rc, Scalar(rand() % 256, rand() % 256, rand() % 256), 2);

	// 회전된 사각형 - 제일 작은 영역의 사각형 반환
	RotatedRect rotated_rc = minAreaRect(contours.at(iIndex));
	Point2f pnt_rc[4];
	rotated_rc.points(pnt_rc);
	Scalar scalar = Scalar(rand() % 256, rand() % 256, rand() % 256);
	for (int i = 0; i < 4; i++)
		line(dst, pnt_rc[i], pnt_rc[(i+1)%4], scalar, 2);

	// 최소 크기 원
	Point2f pnt_circle;
	float radius;
	minEnclosingCircle(pnts, pnt_circle, radius);
	circle(dst, pnt_circle, radius, Scalar(rand() % 256, rand() % 256, rand() % 256), 2);
}

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

waitKey();
destroyAllWindows();

실행 결과는 아래와 같습니다.

면적 구하기

외곽선의 면적을 구하는 함수는 contourArea 함수 입니다. 폐곡선 형태로 이루어진 외곽선의 면적을 반환합니다.

/**
@param contour 외곽선 정보
@param oriented true: 곡선 진행 방향에 따라 부호 값이 달라짐. false: 절대적인 면적값 반환
 */
double contourArea( InputArray contour, bool oriented = false );

샘플 코드는 아래와 같습니다.

Mat src = imread("alphabet_d.png", IMREAD_GRAYSCALE);
if (src.empty())
{
	cerr << "image open error" << endl;
	return -1;
}

vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(src, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);

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

for (int iIndex = 0 ; iIndex < contours.size() ; iIndex++)
{
	vector<Point> pnts = contours.at(iIndex); // 외곽선 정보

	double area = contourArea(pnts); // 면적 구하기
	String strArea = format("%g", area);
	Scalar scalar = Scalar(rand() % 256, rand() % 256, rand() % 256);

	drawContours(dst, contours, iIndex, scalar, -1, LINE_8, hierarchy);
	putText(dst, strArea, Point(0, 50), FONT_HERSHEY_SIMPLEX, 2, scalar);
}

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

waitKey();
destroyAllWindows();

아래는 실행 결과입니다.