Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Here is a code that gets the largest and second largest contour areas (along with their centres). Perhaps you should start over. This code uses a multiset to sort the areas. Like mentioned above, you could also use a vector and then just use the sort function.

#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")

#include <iostream>
#include <map>
#include <set>
using namespace std;


// For later use with multiset
class double_point2d_pair
{
public:
    double area;
    Point2d centre;
};

// For later use with multiset
bool operator<(const double_point2d_pair &lhs, const double_point2d_pair &rhs)
{
    return lhs.area < rhs.area;
}


int main(void)
{
    Mat frame = imread("cards.png", CV_LOAD_IMAGE_GRAYSCALE);

    if (frame.empty())
    {
        cout << "Error loading image file" << endl;
        return -1;
    }

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    Mat flt_frame(frame.rows, frame.cols, CV_32F);

    for (int j = 0; j < frame.rows; j++)
        for (int i = 0; i < frame.cols; i++)
            flt_frame.at<float>(j, i) = frame.at<unsigned char>(j, i) / 255.0f;

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if (contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;

        return 0;
    }

    Mat output = Mat::zeros(flt_frame.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++)
        drawContours(output, contours, i, Scalar(0, 127, 255), 1, 8, hierarchy, 0, Point());

    vector<double> areas(contours.size());

    for (int i = 0; i < contours.size(); i++)
        areas[i] = contourArea(contours[i]);

    vector<Point2d> mass_centres(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        const Moments mu = moments(contours[i], false);
        mass_centres[i] = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    }

    multiset<double_point2d_pair> dpp_set;

    for (int i = 0; i < contours.size(); i++)
    {
        double_point2d_pair dpp;
        dpp.area = areas[i];
        dpp.centre = mass_centres[i];
        dpp_set.insert(dpp);
    }

    int count = 0;
    Point2d first_centre, second_centre;
    double first_area, second_area;

    // Get the two largest contour areas
    for (multiset<double_point2d_pair>::const_reverse_iterator cri = dpp_set.rbegin(); cri != dpp_set.rend(); cri++)
    {
        if (count == 0)
        {
            first_centre = cri->centre;
            first_area = cri->area;
            count++;
        }
        else
        {
            second_centre = cri->centre;
            second_area = cri->area;
            break;
        }
    }

    cout << "Largest contour area: " << first_area << endl;
    cout << "Second contour area:  " << second_area << endl;

    return 0;
}

Here is a code that gets the largest and second largest contour areas (along with their centres). Perhaps you should start over. This code uses a multiset to sort the areas. Like mentioned above, you could also use a vector and then just use the sort function.

#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")

#include <iostream>
#include <map>
#include <set>
using namespace std;


// For later use with multiset
class double_point2d_pair
{
public:
    double area;
    Point2d centre;
};

// For later use with multiset
bool operator<(const double_point2d_pair &lhs, const double_point2d_pair &rhs)
{
    return lhs.area < rhs.area;
}


int main(void)
{
    Mat frame = imread("cards.png", CV_LOAD_IMAGE_GRAYSCALE);

    if (frame.empty())
    {
        cout << "Error loading image file" << endl;
        return -1;
    }

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    Mat flt_frame(frame.rows, frame.cols, CV_32F);

    for (int j = 0; j < frame.rows; j++)
        for (int i = 0; i < frame.cols; i++)
            flt_frame.at<float>(j, i) = frame.at<unsigned char>(j, i) / 255.0f;

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if (contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;

        return 0;
    }

    Mat output = Mat::zeros(flt_frame.size(), Mat::zeros(frame.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++)
        drawContours(output, contours, i, Scalar(0, 127, 255), 1, 8, hierarchy, 0, Point());

    vector<double> areas(contours.size());

    for (int i = 0; i < contours.size(); i++)
        areas[i] = contourArea(contours[i]);

    vector<Point2d> mass_centres(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        const Moments mu = moments(contours[i], false);
        mass_centres[i] = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    }

    multiset<double_point2d_pair> dpp_set;

    for (int i = 0; i < contours.size(); i++)
    {
        double_point2d_pair dpp;
        dpp.area = areas[i];
        dpp.centre = mass_centres[i];
        dpp_set.insert(dpp);
    }

    int count = 0;
    Point2d first_centre, second_centre;
    double first_area, second_area;

    // Get the two largest contour areas
    for (multiset<double_point2d_pair>::const_reverse_iterator cri = dpp_set.rbegin(); cri != dpp_set.rend(); cri++)
    {
        if (count == 0)
        {
            first_centre = cri->centre;
            first_area = cri->area;
            count++;
        }
        else
        {
            second_centre = cri->centre;
            second_area = cri->area;
            break;
        }
    }

    cout << "Largest contour area: " << first_area << endl;
    cout << "Second contour area:  " << second_area << endl;

    return 0;
}

Here is a code that gets the largest and second largest contour areas (along with their centres). Perhaps you should start over. This Like mentioned above, this code uses a multiset sorted vector to sort store the areas. Like mentioned above, you could also use a vector contour areas and then just use the sort function.centres.

#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")

#include <iostream>
#include <map>
#include <set>
using namespace std;


// For later use with multiset
class double_point2d_pair
{
public:
    double area;
    Point2d centre;
};

// For later use with multiset
bool operator<(const double_point2d_pair &lhs, const double_point2d_pair &rhs)
{
    return lhs.area < rhs.area;
}


int main(void)
{
    Mat frame = imread("cards.png", CV_LOAD_IMAGE_GRAYSCALE);

    if (frame.empty())
    {
        cout << "Error loading image file" << endl;
        return -1;
    }

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if (contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;

        return 0;
    }

    Mat output = Mat::zeros(frame.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++)
        drawContours(output, contours, i, Scalar(0, 127, 255), 1, 8, hierarchy, 0, Point());

    vector<double> areas(contours.size());

    for (int i = 0; i < contours.size(); i++)
        areas[i] = contourArea(contours[i]);

    vector<Point2d> mass_centres(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        const Moments mu = moments(contours[i], false);
        mass_centres[i] = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    }

    multiset<double_point2d_pair> dpp_set;
vector<double_point2d_pair> dpp_vec;

    for (int i = 0; i < contours.size(); i++)
    {
        double_point2d_pair dpp;
        dpp.area = areas[i];
        dpp.centre = mass_centres[i];
        dpp_set.insert(dpp);
dpp_vec.push_back(dpp);
    }

    int count = 0;
sort(dpp_vec.begin(), dpp_vec.end());

    Point2d first_centre, second_centre;
first_centre = dpp_vec[dpp_vec.size() - 1].centre;
    double first_area, second_area;

    // Get the two largest contour areas
    for (multiset<double_point2d_pair>::const_reverse_iterator cri = dpp_set.rbegin(); cri != dpp_set.rend(); cri++)
    {
        if (count == 0)
        {
            first_centre = cri->centre;
            first_area = cri->area;
            count++;
        }
        else
        {
            dpp_vec[dpp_vec.size() - 1].area;

    Point2d second_centre = cri->centre;
            dpp_vec[dpp_vec.size() - 2].centre;
    double second_area = cri->area;
            break;
        }
    }
dpp_vec[dpp_vec.size() - 2].area;

    cout << "Largest contour area: " << first_area << endl;
    cout << "Second contour area:  " << second_area << endl;

    return 0;
}

Here is a code that gets the largest and second largest contour areas (along with their centres). Perhaps you should start over. Like mentioned above, this code uses a sorted vector to store the contour areas and centres.

#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")

#include <iostream>
#include <map>
#include <set>
using namespace std;


// For later use with multiset
class double_point2d_pair
{
public:
    double area;
    Point2d centre;
};

// For later use with multiset
the sorted vector
bool operator<(const double_point2d_pair &lhs, const double_point2d_pair &rhs)
{
    return lhs.area < rhs.area;
}


int main(void)
{
    Mat frame = imread("cards.png", CV_LOAD_IMAGE_GRAYSCALE);

    if (frame.empty())
    {
        cout << "Error loading image file" << endl;
        return -1;
    }

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if (contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;

        return 0;
    }

    Mat output = Mat::zeros(frame.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++)
        drawContours(output, contours, i, Scalar(0, 127, 255), 1, 8, hierarchy, 0, Point());

    vector<double> areas(contours.size());

    for (int i = 0; i < contours.size(); i++)
        areas[i] = contourArea(contours[i]);

    vector<Point2d> mass_centres(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        const Moments mu = moments(contours[i], false);
        mass_centres[i] = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    }

    vector<double_point2d_pair> dpp_vec;

    for (int i = 0; i < contours.size(); i++)
    {
        double_point2d_pair dpp;
        dpp.area = areas[i];
        dpp.centre = mass_centres[i];
        dpp_vec.push_back(dpp);
    }

    sort(dpp_vec.begin(), dpp_vec.end());

    Point2d first_centre = dpp_vec[dpp_vec.size() - 1].centre;
    double first_area = dpp_vec[dpp_vec.size() - 1].area;

    Point2d second_centre = dpp_vec[dpp_vec.size() - 2].centre;
    double second_area = dpp_vec[dpp_vec.size() - 2].area;

    cout << "Largest contour area: " << first_area << endl;
    cout << "Second contour area:  " << second_area << endl;

    return 0;
}

Here is a code that gets the largest and second largest contour areas (along with their centres). Perhaps you should start over. Like mentioned above, this code uses a sorted vector to store the contour areas and centres.

#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")

#include <iostream>
#include <map>
<vector>
#include <set>
<algorithm>
using namespace std;


// For later use with multiset
class double_point2d_pair
{
public:
    double area;
    Point2d centre;
};

// For later use with the sorted vector
bool operator<(const double_point2d_pair &lhs, const double_point2d_pair &rhs)
{
    return lhs.area < rhs.area;
}


int main(void)
{
    Mat frame = imread("cards.png", CV_LOAD_IMAGE_GRAYSCALE);

    if (frame.empty())
    {
        cout << "Error loading image file" << endl;
        return -1;
    }

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if (contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;

        return 0;
    }

    Mat output = Mat::zeros(frame.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++)
        drawContours(output, contours, i, Scalar(0, 127, 255), 1, 8, hierarchy, 0, Point());

    vector<double> areas(contours.size());

    for (int i = 0; i < contours.size(); i++)
        areas[i] = contourArea(contours[i]);

    vector<Point2d> mass_centres(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        const Moments mu = moments(contours[i], false);
        mass_centres[i] = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    }

    vector<double_point2d_pair> dpp_vec;

    for (int i = 0; i < contours.size(); i++)
    {
        double_point2d_pair dpp;
        dpp.area = areas[i];
        dpp.centre = mass_centres[i];
        dpp_vec.push_back(dpp);
    }

    sort(dpp_vec.begin(), dpp_vec.end());

    Point2d first_centre = dpp_vec[dpp_vec.size() - 1].centre;
    double first_area = dpp_vec[dpp_vec.size() - 1].area;

    Point2d second_centre = dpp_vec[dpp_vec.size() - 2].centre;
    double second_area = dpp_vec[dpp_vec.size() - 2].area;

    cout << "Largest contour area: " << first_area << endl;
    cout << "Second contour area:  " << second_area << endl;

    return 0;
}

Here is a code that gets the largest and second largest contour areas (along with their centres). Perhaps you should start over. Like mentioned above, this code uses a sorted vector to store the contour areas and centres.

#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


// For later use with multiset
the sorted vector
class double_point2d_pair
{
public:
    double area;
    Point2d centre;
};

// For later use with the sorted vector
bool operator<(const double_point2d_pair &lhs, const double_point2d_pair &rhs)
{
    return lhs.area < rhs.area;
}


int main(void)
{
    Mat frame = imread("cards.png", CV_LOAD_IMAGE_GRAYSCALE);

    if (frame.empty())
    {
        cout << "Error loading image file" << endl;
        return -1;
    }

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if (contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;

        return 0;
    }

    Mat output = Mat::zeros(frame.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++)
        drawContours(output, contours, i, Scalar(0, 127, 255), 1, 8, hierarchy, 0, Point());

    vector<double> areas(contours.size());

    for (int i = 0; i < contours.size(); i++)
        areas[i] = contourArea(contours[i]);

    vector<Point2d> mass_centres(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        const Moments mu = moments(contours[i], false);
        mass_centres[i] = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    }

    vector<double_point2d_pair> dpp_vec;

    for (int i = 0; i < contours.size(); i++)
    {
        double_point2d_pair dpp;
        dpp.area = areas[i];
        dpp.centre = mass_centres[i];
        dpp_vec.push_back(dpp);
    }

    sort(dpp_vec.begin(), dpp_vec.end());

    Point2d first_centre = dpp_vec[dpp_vec.size() - 1].centre;
    double first_area = dpp_vec[dpp_vec.size() - 1].area;

    Point2d second_centre = dpp_vec[dpp_vec.size() - 2].centre;
    double second_area = dpp_vec[dpp_vec.size() - 2].area;

    cout << "Largest contour area: " << first_area << endl;
    cout << "Second contour area:  " << second_area << endl;

    return 0;
}