Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV 2 Centroid

I am trying to find the centroid of a contour but am having trouble implementing the example code in C++ (OpenCV 2.3.1). Can anyone help me out?

like image 544
keshavdv Avatar asked Jan 31 '12 04:01

keshavdv


People also ask

What does cv2 contourArea do?

To get the area of the contours, we can implement the function cv2. contourArea() . Why don't we try several contours here? If you input the first, second and third contours, you'll get the decreasing values as shown below.

What is cv2 boundingRect?

The cv2. boundingRect() function of OpenCV is used to draw an approximate rectangle around the binary image. This function is used mainly to highlight the region of interest after obtaining contours from an image. As per the documentation there are two types of bounding rectangles: Straight Bounding Rectangle.

What is cv2 approxPolyDP?

The function cv2.approxPolyDP() approximates a contour shape to another shape with less number of vertices. It accepts the following arguments − cnt − The array of the contour points. epsilon − Maximum distance from contour to approximated contour. A wise selection of epsilon is needed to get the correct output.


3 Answers

If you have the mask of the contour area, you can find the centroid location as follows:

cv::Point computeCentroid(const cv::Mat &mask) {
    cv::Moments m = moments(mask, true);
    cv::Point center(m.m10/m.m00, m.m01/m.m00);
    return center;
}

This approach is useful when one has the mask but not the contour. In that case the above method is computationally more efficient vs. using cv::findContours(...) and then finding mass center.

Here's the source

like image 167
Alexey Avatar answered Sep 30 '22 15:09

Alexey


Given the contour points, and the formula from Wikipedia, the centroid can be efficiently computed like this:

template <typename T> 
cv::Point_<T> computeCentroid(const std::vector<cv::Point_<T> >& in) {
    if (in.size() > 2) {
         T doubleArea = 0;
         cv::Point_<T> p(0,0);
         cv::Point_<T> p0 = in->back();
         for (const cv::Point_<T>& p1 : in) {//C++11
             T a = p0.x * p1.y - p0.y * p1.x; //cross product, (signed) double area of triangle of vertices (origin,p0,p1)
             p += (p0 + p1) * a;
             doubleArea += a;
             p0 = p1;
         }

         if (doubleArea != 0)
             return p * (1 / (3 * doubleArea) ); //Operator / does not exist for cv::Point
    }

    ///If we get here,
    ///All points lies on one line, you can compute a fallback value,
    ///e.g. the average of the input vertices
    [...]
}

Note:

  • This formula works with vertices given both in clockwise and counterclockwise order.
  • If the points have integer coordinates, it might be convenient to adapt the type of p and of the return value to Point2f or Point2d, and to add a cast to float or double to the denominator in the return statement.
like image 35
Antonio Avatar answered Sep 30 '22 13:09

Antonio


To find the centroid of a contour, you can use the method of moments. And functions are implemented OpenCV.

Check out these moments function (central and spatial moments).

Below code is taken from OpenCV 2.3 docs tutorial. Full code here.


/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

/// Get the moments
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
 { mu[i] = moments( contours[i], false ); }

///  Get the mass centers:
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
 { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); } 

Also check out this SOF, although it is in Python, it would be useful. It finds all parameters of a contour.

like image 26
Abid Rahman K Avatar answered Sep 30 '22 14:09

Abid Rahman K