본문 바로가기

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

[OpenCV][C++] 영상 외곽선(contour) 추출 총정리(2) - cv::drawContours cvtColor 컨투어 찾기 바깥 라인 convexhull

지난번에 영상의 윤곽선을 추출하는 findContours()에 대해 자세히 알아 봤습니다.

이번에는 findContours()로 찾은 윤곽선을 영상 위에 그리는 방법에 대해 알아보겠습니다.

drawContours

drawContours()의 원형은 아래와 같습니다.

src
윤곽선을 그릴 영상, gray, color 영상 가능
contours
윤곽선 정보, vector<vector<Point>> 타입
contourIdx
윤곽선 인덱스, -1일 경우 전체 윤곽선을 한번에 그림
color
윤곽선 색상
thickness
윤곽선 두께, FILLED 또는 -1일 경우 내부를 채움
lineType
윤곽선 타입
hierarchy
윤곽선 계층 정보
maxLevel
윤곽선의 최대 레벨, 0이면 지정한 번호의 윤곽선만, 1 이상이면 그 이하 레벨 윤곽선 그림
offset
윤곽선 점 좌표의 이동 변위 오프셋

 

윤곽선 그리는 기본 소스는 아래와 같습니다.

color는 random 변수를 사용하여 임의의 색으로 표시를 하였습니다.

#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::RNG rng(12345);
    for (int i = 0; i < contours.size(); ++i) {
        cv::drawContours(src_color, contours, i, cv::Scalar(rng.uniform(0, 256), 
                         rng.uniform(0, 256), rng.uniform(0, 256)), 2);                
    }
    
    return 0;
}
 

그림 결과는 아래와 같습니다.

for문을 이용할 경우 특정 index만 그림을 그릴 수 있고, 전체를 그리고 싶다면 contourIndex -1을 넣으시면 됩니다. 하지만 이럴 경우, 한가지 색상으로만 그림이 그려질 수 밖에 없어요.

만약 contour 내부를 채우고 싶다면, 아래와 같이 thickness -1 또는 cv::FILLED를 넣으시면 됩니다.

결과는 아래와 같습니다.

drawContours() 함수는 반드시 findContours() 에서 나온 결과값만 그려주는 것이 아닙니다.

아래와 같이 임의의 값을 넣어 그림을 그릴 수 있습니다. 이는 polygon 형태 roi를 그릴 때에도 사용이 가능합니다.

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

int main()
{
    cv::Mat src = cv::Mat::zeros(100, 100, CV_8UC1);

    std::vector<cv::Point> vecData{ cv::Point(1,1), 
                                    cv::Point(10, 10), 
                                    cv::Point(10, 30), 
                                    cv::Point(80, 80), 
                                    cv::Point(80, 1) };

    std::vector<std::vector<cv::Point>> vvecData{ vecData };
    cv::drawContours(src, vvecData, -1, cv::Scalar(255));
    
    return 0;
}
 

결과는 아래와 같습니다.