본문 바로가기

프로그래밍 강좌/C++ - OpenCV

[OpenCV][C++] 영상 외곽선(contour) 추출 총정리(3) - boundingRect, minAreaRect, minEnclosingCircle arcLength contourArea

이번에는 지난 시간에 이어 findContours() 함수로 얻어왔던 정보를 응용하여 추가적인 정보를 얻을 수 있는 방법에 대해 알아보겠습니다.

boundingRect()

윤곽선 점들을 감싸는 가장 작은 크기의 사각형을 구하는 함수 입니다.

함수 원형은 아래와 같습니다.

points
std::vector<cv::Point> 타입 또는 Mat 타입
반환값
points 들을 감싸는 최소 크기 사각형 정보

 

소스는 아래와 같습니다.

RETR_TREE 모드의 0번째 contour는 좌하단에 있는 원의 외곽입니다. (이전 강의 참조)

그래서 boundingRect() contours[0]을 입력으로 넣으면 해당 원에 외접하는 최소 사각형 정보를 구할 수 있습니다.

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

int main()
{   
    cv::Mat src = cv::imread("../contour.bmp", cv::IMREAD_GRAYSCALE);
    if (src.empty())  return 1;

    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    
    int mode = cv::RETR_TREE;    
    int method = cv::CHAIN_APPROX_SIMPLE;
    
    cv::findContours(src, contours, hierarchy, mode, method);

    cv::Mat src_color;
    cv::cvtColor(src, src_color, cv::COLOR_GRAY2BGR);

    cv::Rect rect = cv::boundingRect(contours[0]);
    cv::rectangle(src_color, rect, cv::Scalar(0, 0, 255), 2);

    return 0;
}
 

결과는 아래와 같습니다.

 

minAreaRect()

윤곽선을 감싸는 최소 크기의 회전된 사각형을 구하고 싶을 때에 사용하는 함수 입니다.

함수 원형은 아래와 같습니다.

 
points
std::vector<cv::Point> 타입 또는 Mat 타입
반환값
points 들을 감싸는 최소 크기의 회전된 사각형 정보

 

전체 소스가 아닌 해당 소스만 보여드릴께요.

cv::RotatedRect rot_rect = cv::minAreaRect(contours[1]);
cv::Point2f pts[4];
rot_rect.points(pts);
for (int i = 0; i < 4; ++i)
    cv::line(src_color, pts[i], pts[(i + 1) % 4], cv::Scalar(0, 0, 255), 2);
 

결과는 아래와 같습니다.

이번엔 contours[1] 인 다이아몬드 그림의 점들을 넣어 봤는데요.

cv::RotatedRect 회전 중심점, 사각형의 크기, 회전 각도의 정보로 이루어져 있어요

필요하면 나중에 다뤄보도록 하겠습니다.

 

minEnclosingCircle()

윤곽선을 감싸는 최소 크기의 원을 구하고 싶을 때에 사용하는 함수 입니다.

함수 원형은 아래와 같습니다.

points
std::vector<cv::Point> 타입 또는 Mat 타입
center
외접원의 중심 좌표
radius
외접원의 반지름

소스는 아래와 같습니다.

contours[3] 사각형 내부에 있는 화살표 모양입니다.

외접원의 중심 좌표 반지름을 가져와서 cv::circle로 그림을 그려봤어요.

cv::Point2f center;
float radius;
cv::minEnclosingCircle(contours[3], center, radius);
cv::circle(src_color, center, radius, cv::Scalar(255, 0, 0));
 

 

arcLength()

윤곽선(폐곡선이 아니어도 가능함)의 둘레의 길이를 구하고 싶을 때 사용하는 함수 입니다.

함수 원형은 아래와 같습니다.

curve
std::vector<cv::Point> 타입 또는 Mat 타입
closed
폐곡선 여부
반환값
윤곽선의 길이

 

소스는 아래와 같습니다.

contours[2] 화살표를 둘러싼 사각형입니다.

현재 영상에서 length 306.000 이 나오네요.

double length = cv::arcLength(contours[2], true);
 
contourArea()

윤곽선의 면적을 계산하는 함수 입니다.

함수의 원형은 아래와 같습니다.

contour
std::vector<cv::Point> 타입 또는 Mat 타입
oriented
진행 방향 정보
true: 윤곽선 진행 방향에 따라 면적 부호 달라짐
(시계방향: 양수, 반시계 방향: 음수)
false: 면적의 절대값 반환
반환값
윤곽선의 면적

 

소스는 아래와 같습니다.

contours[9]는 별모양 입니다. area 값이 475.000 이 나왔네요.

double area = cv::contourArea(contours[9], false);
 

위의 소스 전체는 아래와 같습니다.

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

int main()
{   
    cv::Mat src = cv::imread("../contour.bmp", cv::IMREAD_GRAYSCALE);
    if (src.empty())  return 1;

    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    
    int mode = cv::RETR_TREE;    
    int method = cv::CHAIN_APPROX_SIMPLE;
    
    cv::findContours(src, contours, hierarchy, mode, method);

    cv::Mat src_color;
    cv::cvtColor(src, src_color, cv::COLOR_GRAY2BGR);

    cv::Rect rect = cv::boundingRect(contours[0]);
    cv::rectangle(src_color, rect, cv::Scalar(0, 255, 0));

    cv::RotatedRect rot_rect = cv::minAreaRect(contours[1]);
    cv::Point2f pts[4];
    rot_rect.points(pts);
    for (int i = 0; i < 4; ++i)
        cv::line(src_color, pts[i], pts[(i + 1) % 4], cv::Scalar(0, 0, 255));

    cv::Point2f center;
    float radius;
    cv::minEnclosingCircle(contours[3], center, radius);
    cv::circle(src_color, center, radius, cv::Scalar(255, 0, 0));

    double length = cv::arcLength(contours[2], true);
    std::string strLength = "Length: " + std::to_string((int)length);
    cv::drawContours(src_color, contours, 2, cv::Scalar(255, 0, 255));
    cv::putText(src_color, strLength, cv::Point(23, 21), cv::FONT_HERSHEY_PLAIN, 0.7, cv::Scalar(255, 0, 255));

    double area = cv::contourArea(contours[9], false);
    cv::drawContours(src_color, contours, 9, cv::Scalar(0, 255, 255), cv::FILLED, cv::LINE_AA);
    std::string strArea = "Area: " + std::to_string((int)area);
    cv::putText(src_color, strArea, cv::Point(145, 74), cv::FONT_HERSHEY_PLAIN, 0.7, cv::Scalar(0, 255, 255));

    return 0;
}
 

결과는 아래와 같네요.