본문 바로가기
opencv

close contours (convexHull 사용)

by 꼰대코더 2025. 2. 16.

과제

findContours 에 RETR_EXTERNAL 옵션을 주면 가장 외곽의 연결된 선의 좌표들을 추출하는데, 만약 그 외곽선의 일부가 약한 픽셀로 되어 있다면 결과는 봉쇄되지 않은 contour로 인해 안쪽의 contour 좌표들도 결과로 추출되게 된다.

결과적으로 가장 외곽의 contour만 추출하고자 한다. 

 

아이디어

모든 contour의 포인터들을 하나의 벡터에 집어넣고 그 벡터를 convexHull 로 처리하면 외곽에 완만한 곡선의 결과 포인트들만 얻을 수 있다.

처리속도를 고려한다면 모든 포인트들을 전부 벡터에 넣을 필요는 없고 간격을 두고 처리하는 것도 좋은 아이디어이다.

convexHull 과 approxPolyDP 의 차이점은 approxPolyDP 가 모든 contour 포인트들 대상으로 심플화된 선의 포인트 집합을 리턴하는 반면  convexHull 은 가장 바깥쪽의 포인트를 따라가면서 완만한 곡선 포인트 집합을 리턴하게 된다.

 

 

    cv::Mat img = cv::imread("d:\\image.png");

    cv::Mat gray;
    cv::cvtColor(img, gray, CV_BGR2GRAY);
    cv::blur(gray, gray, cv::Size(3, 3));

    cv::Mat thresh;
    cv::Canny(gray, thresh, 0, 100, 3, true);

    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(thresh, contours, hierarchy, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    std::vector<cv::Point> ConvexHullPoints;
    std::vector<cv::Point> pts;
    for (size_t i = 0; i < contours.size(); i++)
        for (size_t j = 0; j < contours[i].size(); j++)
            pts.push_back(contours[i][j]);

    cv::convexHull(pts, ConvexHullPoints );

    cv::polylines(img, ConvexHullPoints, true, cv::Scalar(0, 0, 255), 2);
    cv::imwrite("d:\\result1.png", img);