Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

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

using namespace std;
using namespace cv;
int main()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // Create binary image from source image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    imshow("bin", bw);

image description

    // Find contours
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // The array for storing the approximation curve
    std::vector<cv::Point> approx;

    // We'll put the labels in this destination image
    cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

//    vector<RotatedRect> minEllipse;
    for (int i = 0; i < contours.size(); i++)
    {
        // Approximate contour with accuracy proportional
        // to the contour perimeter with approxPolyDP. In this,
        // second argument is called epsilon, which is maximum
        // distance from contour to approximated contour. It is
        // an accuracy parameter. A wise selection of epsilon is
        //needed to get the correct output.
        double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
        cv::approxPolyDP(
            cv::Mat(contours[i]),
            approx,
            epsilon,
            true
        );

        // Skip small or non-convex objects
        if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
            continue;

        drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
    }

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    waitKey(0);
    return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.

Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

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

using namespace std;
using namespace cv;
int main()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // Create binary image from source image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    imshow("bin", bw);

image description

    // Find contours
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // The array for storing the approximation curve
    std::vector<cv::Point> approx;

    // We'll put the labels in this destination image
    cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

//    vector<RotatedRect> minEllipse;
    for (int i = 0; i < contours.size(); i++)
    {
        // Approximate contour with accuracy proportional
        // to the contour perimeter with approxPolyDP. In this,
        // second the third argument is called epsilon, which is maximum
        // distance from contour to approximated contour. It is
        // an accuracy parameter. A wise selection of epsilon is
        //needed to get the correct output.
        double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
        cv::approxPolyDP(
            cv::Mat(contours[i]),
            approx,
            epsilon,
            true
        );

        // Skip small or non-convex objects
        if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
            continue;

        drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
    }

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    waitKey(0);
    return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.

Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

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

using namespace std;
using namespace cv;
int main()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // Create binary image from source image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    imshow("bin", bw);

image description

    // Find contours
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // The array for storing the approximation curve
    std::vector<cv::Point> approx;

    // We'll put the labels in this destination image
    cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

//    vector<RotatedRect> minEllipse;
    for (int i = 0; i < contours.size(); i++)
    {
        // Approximate contour with accuracy proportional
        // to the contour perimeter with approxPolyDP. In this,
        // the third argument is called epsilon, which is maximum
        // distance from contour to approximated contour. It is
        // an accuracy parameter. A wise selection of epsilon is
        //needed to get the correct output.
        double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
        cv::approxPolyDP(
            cv::Mat(contours[i]),
            approx,
            epsilon,
            true
        );

        // Skip small or non-convex objects
        if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
            continue;

        drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
    }

    imshow("contours", dst);

image description

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    waitKey(0);
    return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.

Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

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

using namespace std;
using namespace cv;
int main()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // Create binary image from source image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    imshow("bin", bw);

image description

    // Find contours
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // The array for storing the approximation curve
    std::vector<cv::Point> approx;

    // We'll put the labels in this destination image
    cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

//    vector<RotatedRect> minEllipse;
    for (int i = 0; i < contours.size(); i++)
    {
        // Approximate contour with accuracy proportional
        // to the contour perimeter with approxPolyDP. In this,
        // the third argument is called epsilon, which is maximum
        // distance from contour to approximated contour. It is
        // an accuracy parameter. A wise selection of epsilon is
        //needed to get the correct output.
        double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
        cv::approxPolyDP(
            cv::Mat(contours[i]),
            approx,
            epsilon,
            true
        );

        // Skip small or non-convex convex objects
        if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
            continue;

        drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
    }

    imshow("contours", dst);

image description

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    waitKey(0);
    return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.

Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

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

using namespace std;
using namespace cv;
int main()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // Create binary image from source image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    imshow("bin", bw);

image description

    // Find contours
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // The array for storing the approximation curve
    std::vector<cv::Point> approx;

    // We'll put the labels in this destination image
    cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

//    vector<RotatedRect> minEllipse;
    for (int i = 0; i < contours.size(); i++)
    {
        // Approximate contour with accuracy proportional
        // to the contour perimeter with approxPolyDP. In this,
        // the third argument is called epsilon, which is maximum
        // distance from contour to approximated contour. It is
        // an accuracy parameter. A wise selection of epsilon is
        //needed to get the correct output.
        double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
        cv::approxPolyDP(
            cv::Mat(contours[i]),
            approx,
            epsilon,
            true
        );

        // Skip small or convex objects
        if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
            continue;

        drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
    }

    imshow("contours", dst);

image description

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    waitKey(0);
    return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.

Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

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

using namespace std;
using namespace cv;
int main()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // Create binary image from source image
    Mat bw;
    cvtColor(src, bw, CV_BGR2GRAY);
    threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    imshow("bin", bw);

image description

    // Find contours
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // The array for storing the approximation curve
    std::vector<cv::Point> approx;

    // We'll put the labels in this destination image
    cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

    // Loop through detected contours, and process accordingly
    for (int i = 0; i < contours.size(); i++)
    {
        // Approximate contour with accuracy proportional
        // to the contour perimeter with approxPolyDP. In this,
        // the third argument is called epsilon, which is maximum
        // distance from contour to approximated contour. It is
        // an accuracy parameter. A wise selection of epsilon is
        //needed to get the correct output.
        double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
        cv::approxPolyDP(
            cv::Mat(contours[i]),
            approx,
            epsilon,
            true
        );

        // Skip small or convex objects
        if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
            continue;

        drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
    }

    imshow("contours", dst);

image description

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    waitKey(0);
    return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.