Ask Your Question
0

Opencv_contourArea

asked 2016-08-05 05:57:18 -0600

harfbuzz gravatar image

updated 2016-08-05 05:59:43 -0600

HI,

When I calculate the area of via the contourArea function in binary image, I'm not getting the correct contour area. Below the snippet code, why the area is calculated incorrectly ? I have used a contour mask but it doesn't solve the problem.

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

//findContours(bw, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
findContours(bw, contours, hierarchy, CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
Mat mask = Mat::zeros(bw.size(), CV_8UC1);

for (size_t i = 0; i < contours.size(); ++i)
{

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

vector<Point> all_pixels;   // output, locations of non-zero pixels
cv::findNonZero(mask, all_pixels);

vector<Point> all_pixels;
cv::findNonZero(mask, all_pixels);
int inside_phase = all_pixels.size() - contours.size();
    // Calculate the area of each contour
    double area = contourArea(contours[i], true);

    cout << " Area#" << i <<": " << area << endl;
    cout << " inside: " << inside_phase << endl;
}
edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
2

answered 2016-08-05 07:26:13 -0600

LorenaGdL gravatar image

Have you checked docs? This is stated: The function computes a contour area. Similarly to moments , the area is computed using the Green formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using drawContours or fillPoly , can be different. Also, the function will most certainly give a wrong results for contours with self-intersections.

edit flag offensive delete link more
0

answered 2016-08-07 11:57:20 -0600

harfbuzz gravatar image

updated 2016-08-07 23:10:20 -0600

I've rewritten the code, the idea is to apply a filter by using a mask and then remove the pixels already accounted. Below the complete program. I have tested the code it works fine for objects having a straight line forms but for others forms like as circular I had some inaccurate results.

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

 using namespace std;
 using namespace cv;

 int main(int, char** argv){
    // Load source image
    Mat imgSource = imread(argv[1]);
    // Check if image is loaded fine
    if(!imgSource.data)
        cerr << "Add file name image !" << endl;
    // Show source image
    imshow("imgSource", imgSource);
    //Transform source image to gray if it is not
    Mat gray;
    if (imgSource.channels() == 3)
    {
        cvtColor(imgSource, gray, CV_BGR2GRAY);
    }
    else
    {
        gray = imgSource;
    }
    Mat imgBin, imgBiFilter;
    //threshold(gray, imgBin,0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
    threshold(gray, imgBin, 100, 255, 1);   
    // count all pixels of binary image
    for (int row = 0; row < imgBin.rows; row++)
    {
        for (int col = 0; col < imgBin.cols ; col++)
        {
            int pixelValue = imgBin.at<uchar>(row,col);
        }
    }
    //Total number of pixels
    int imgResol;
    imgResol = (imgBin.rows * imgBin.cols);
    vector<Point> pixel_contour;   // output, locations of non-zero pixels
    cv::findNonZero(imgBin, pixel_contour);
    //imshow("binary", imgBin);

    vector<Vec4i> hierarchy;
    vector<vector<Point> > contours;
    // extract only the external contour
    findContours(imgBin.clone(), contours, hierarchy, CV_RETR_EXTERNAL,
                 CV_CHAIN_APPROX_NONE);
   // draw the contours as a solid and create a mask of the object
    Mat mask = Mat::zeros(imgBin.size(), CV_8UC1);
    const int arrSize = contours.size();
    double arrArea[arrSize] ;
      for(size_t i = 0; i < contours.size(); i++)    {
       drawContours(mask, contours, i, Scalar(255, 255, 255),
                     CV_FILLED, 8, hierarchy, 0, Point());
    //imshow("mask", mask);
    vector<Point> all_pixels;   // output, locations of non-zero pixels
    cv::findNonZero(mask, all_pixels);
    //count pixel of objects
    int pixelR = pixel_contour.size() - all_pixels.size() ;
    double area = contourArea(contours[i]);

            //Select the range of areas to be considered
            if(area < 5 || 1e4 < area) continue;
            //cout << " pixelR: " << pixelR<< endl;
            drawContours(imgSource, contours, static_cast<int>(i), Scalar(0, 0, 255), 1,
                         8, hierarchy, 0);
            arrArea[i] = pixelR;
    }

    cout << "Ncont" << setw(7) << "Area" << endl;
    for(int j=0; j <contours.size(); j++)
    {
      if (j <=0 )
        {
          cout << j << setw(9) << fabs(arrArea[j] - pixel_contour.size()) << endl;
        }
        else
        {
            cout << j << setw(9) << fabs(arrArea[j] - arrArea[j-1]) <<endl;
        }
    }


    //waitKey(0);
    return 0;
}
edit flag offensive delete link more

Comments

The solution for what problem? Your original code was fine, and now you seem to do a lot of extra operatios for obtaining an alternative result without a clear purpose to me...

LorenaGdL gravatar imageLorenaGdL ( 2016-08-07 12:18:42 -0600 )edit
3

OK, you can remove the "solution" word in your answer, but it is still an answer with no purpose at all. But if you're happy, we're happy

LorenaGdL gravatar imageLorenaGdL ( 2016-08-08 01:59:06 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2016-08-05 05:57:18 -0600

Seen: 1,629 times

Last updated: Aug 07 '16