Ask Your Question

Revision history [back]

i have an answer posted before : dilating image before finding contours.

i tried another two ways :

  • drawing contours thicker and finding contours again.( works slower )

  • a trial implementation to relocate contour points ( it works faster but it still need to be improved )

the code and results are as follows ( i hope this information will be helpful )

input image:

image description

image description

image description

image description

#include <opencv2/opencv.hpp>
#include <ctime>
using namespace cv;
using namespace std;

vector<vector<Point> > getExpandedContours(Mat binary_img, int pixels, int method)
{
    if (method == 0)
    {
        dilate(binary_img, binary_img, Mat(), Point(-1, -1), pixels);
    }

    vector<vector<Point> > contours;

    findContours(binary_img, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    if (method == 1)
    {
        for (int i = 0; i < contours.size(); i++)
        {
            drawContours(binary_img, contours, i, Scalar(255), pixels * 2);
        }

        findContours(binary_img, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    }

    if (method == 2)
    {
        int erosion_value = pixels;
        int free_man_cc = -1;
        vector<Point> contour;
        for (int j = 0; j < contours.size(); j++)
        {
            contour = contours[j];
            int xdiff = 0;
            int ydiff = 0;

            for (int i = 0; i < contour.size() - 1; i++)
            {
                Point pt;

                if ((contour[i].y > contour[i + 1].y) & (contour[i].x == contour[i + 1].x))
                {
                    free_man_cc = 0;
                    xdiff = -1 * erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y > contour[i + 1].y) & (contour[i].x < contour[i + 1].x))
                {
                    free_man_cc = 1;
                    xdiff = -1 * erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y == contour[i + 1].y) & (contour[i].x < contour[i + 1].x))
                {
                    free_man_cc = 2;
                    xdiff = erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y < contour[i + 1].y) & (contour[i].x < contour[i + 1].x))
                {
                    free_man_cc = 3;
                    xdiff = erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y < contour[i + 1].y) & (contour[i].x == contour[i + 1].x))
                {
                    free_man_cc = 4;
                    xdiff = erosion_value;
                    ydiff = erosion_value;
                }

                if ((contour[i].y < contour[i + 1].y) & (contour[i].x > contour[i + 1].x))
                {
                    free_man_cc = 5;
                    xdiff = erosion_value;
                    ydiff = erosion_value;
                }

                if ((contour[i].y == contour[i + 1].y) & (contour[i].x > contour[i + 1].x))
                {
                    free_man_cc = 6;
                    xdiff = -1 * erosion_value;
                    ydiff = erosion_value;
                }

                if ((contour[i].y > contour[i + 1].y) & (contour[i].x > contour[i + 1].x))
                {
                    free_man_cc = 7;
                    xdiff = -1 * erosion_value;
                    ydiff = erosion_value;
                }
                contours[j][i].x = contour[i].x - xdiff;
                contours[j][i].y = contour[i].y - ydiff;
            }
        }
    }
    return contours;
}

int main(int argc, const char * argv[])
{
    Mat img = imread("d:/test.png");
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    gray = gray <127;

    std::time_t timeBegin = std::time(0);
    double elapsed = 0;
    int test_loop = 5000;
    int pixel_expansion = 10;

    vector<vector<Point> > contours;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getExpandedContours(gray.clone(), pixel_expansion, 0);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (dilating image before finding ) ";
    std::time_t timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img, contours, i, Scalar(0, 255, 0), 2);
    }
    imshow("result-0", img);
    timeBegin = std::time(0);
    elapsed = 0;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getExpandedContours(gray.clone(), pixel_expansion, 1);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (drawing contours thicker and finding contours again)  ";
    timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img, contours, i, Scalar(0, 0, 255), 2);
    }
    imshow("result-1", img);
    timeBegin = std::time(0);
    elapsed = 0;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getExpandedContours(gray.clone(), pixel_expansion, 2);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (new trial method)  ";
    timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img, contours, i, Scalar(255, 0, 0), 2);
    }
    imshow("result-2", img);

    waitKey();
    return 0;
}

i have an answer posted before : dilating image before finding contours.

We can do eroding image before finding contours to get opposite effect.

additionally i tried another two ways :

  • drawing contours thicker and finding contours again.( works slower )

  • a trial implementation to relocate contour points ( it works faster but it still need to be improved )

the code and results are as follows ( i hope this information will be helpful )

Performans comparison
***************************
0.00119661  seconds (dilating image before finding contours ) 0
0.0071249   seconds (drawing contours thicker and finding contours again)  4
0.000708922 seconds (new trial method)  0
0.00113688  seconds (eroding image before finding contours ) 1
0.0046207   seconds (drawing contours thicker with Scalar(0) and finding contours again)  2

input image:

image description

Output images:

image description

image descriptionimage description

image descriptionimage description

image description

image description

#include <opencv2/opencv.hpp>
#include <ctime>
using namespace cv;
using namespace std;

vector<vector<Point> > getExpandedContours(Mat binary_img, int pixels, int method)
{
    if (method == 0)
    {
        dilate(binary_img, binary_img, Mat(), Point(-1, -1), pixels);
    }

    vector<vector<Point> > contours;

    findContours(binary_img, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    if (method == 1)
    {
        for (int i = 0; i < contours.size(); i++)
        {
            drawContours(binary_img, contours, i, Scalar(255), pixels * 2);
        }

        findContours(binary_img, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    }

    if (method == 2)
    {
        int erosion_value = pixels;
        int free_man_cc = -1;
        vector<Point> contour;
        for (int j = 0; j < contours.size(); j++)
        {
            contour = contours[j];
            int xdiff = 0;
            int ydiff = 0;

            for (int i = 0; i < contour.size() - 1; i++)
            {
                Point pt;

                if ((contour[i].y > contour[i + 1].y) & (contour[i].x == contour[i + 1].x))
                {
                    free_man_cc = 0;
                    xdiff = -1 * erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y > contour[i + 1].y) & (contour[i].x < contour[i + 1].x))
                {
                    free_man_cc = 1;
                    xdiff = -1 * erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y == contour[i + 1].y) & (contour[i].x < contour[i + 1].x))
                {
                    free_man_cc = 2;
                    xdiff = erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y < contour[i + 1].y) & (contour[i].x < contour[i + 1].x))
                {
                    free_man_cc = 3;
                    xdiff = erosion_value;
                    ydiff = -1 * erosion_value;
                }

                if ((contour[i].y < contour[i + 1].y) & (contour[i].x == contour[i + 1].x))
                {
                    free_man_cc = 4;
                    xdiff = erosion_value;
                    ydiff = erosion_value;
                }

                if ((contour[i].y < contour[i + 1].y) & (contour[i].x > contour[i + 1].x))
                {
                    free_man_cc = 5;
                    xdiff = erosion_value;
                    ydiff = erosion_value;
                }

                if ((contour[i].y == contour[i + 1].y) & (contour[i].x > contour[i + 1].x))
                {
                    free_man_cc = 6;
                    xdiff = -1 * erosion_value;
                    ydiff = erosion_value;
                }

                if ((contour[i].y > contour[i + 1].y) & (contour[i].x > contour[i + 1].x))
                {
                    free_man_cc = 7;
                    xdiff = -1 * erosion_value;
                    ydiff = erosion_value;
                }
                contours[j][i].x = contour[i].x - xdiff;
                contours[j][i].y = contour[i].y - ydiff;
            }
        }
    }
    return contours;
}

vector<vector<Point> > getShrinkedContours(Mat binary_img, int pixels, int method)
{
    if (method == 0)
    {
        erode(binary_img, binary_img, Mat(), Point(-1, -1), pixels);
    }

    vector<vector<Point> > contours;

    findContours(binary_img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    if (method == 1)
    {
        for (int i = 0; i < contours.size(); i++)
        {
            drawContours(binary_img, contours, i, Scalar(0), pixels * 2);
        }

        findContours(binary_img, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    }

    return contours;
}

int main(int argc, const char * argv[])
{
    Mat img = imread("d:/test.png");
    Mat img0 = img.clone();
    Mat img1 = img.clone();
    Mat img2 = img.clone();
    Mat img3 = img.clone();
    Mat img4 = img.clone();
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    gray = gray <127;

    std::time_t timeBegin = std::time(0);
    double elapsed = 0;
    int test_loop = 5000;
500;
    int pixel_expansion = 10;

    vector<vector<Point> > contours;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getExpandedContours(gray.clone(), pixel_expansion, 0);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (dilating image before finding contours ) ";
    std::time_t timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img, drawContours(img0, contours, i, Scalar(0, 255, 0), 2);
    }
    imshow("result-0", img);
img0);
    timeBegin = std::time(0);
    elapsed = 0;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getExpandedContours(gray.clone(), pixel_expansion, 1);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (drawing contours thicker with Scalar(255) and finding contours again)  ";
    timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img, drawContours(img1, contours, i, Scalar(0, 0, 255), 2);
    }
    imshow("result-1", img);
img1);
    timeBegin = std::time(0);
    elapsed = 0;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getExpandedContours(gray.clone(), pixel_expansion, 2);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (new trial method)  ";
    timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img, drawContours(img2, contours, i, Scalar(255, 0, 0), 2);
    }
    imshow("result-2", img);
img2);

    timeBegin = std::time(0);
    elapsed = 0;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getShrinkedContours(gray.clone(), pixel_expansion/2, 0);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (eroding image before finding contours ) ";
    timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img3, contours, i, Scalar(0, 255, 0), 2);
    }
    imshow("result-3", img3);
    timeBegin = std::time(0);
    elapsed = 0;
    for (int i = 0; i < test_loop; i++)
    {
        double t0 = (double)getTickCount();
        contours = getShrinkedContours(gray.clone(), pixel_expansion /2, 1);
        elapsed += ((double)getTickCount() - t0) / getTickFrequency();
    }
    cout << elapsed / test_loop << " seconds (drawing contours thicker with Scalar(0) and finding contours again)  ";
    timeNow = std::time(0) - timeBegin;
    cout << timeNow << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(img4, contours, i, Scalar(0, 0, 255), 2);
    }
    imshow("result-4", img4);

    waitKey();
    return 0;
}