centroid of contour/object in opencv in c?

后端 未结 3 1232
既然无缘
既然无缘 2021-01-13 07:46

is there some good and better way to find centroid of contour in opencv, without using built in functions? <

相关标签:
3条回答
  • 2021-01-13 08:45

    While Sonaten's answer is perfectly correct, there is a simple way to do it: Use the dedicated opencv function for that: moments()

    http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=moments#moments

    It does not only returns the centroid, but some more statistics about your shape. And you can send it a contour or a raster shape (binary image), whatever best fits your need.

    EDIT

    example (modified) from "Learning OpenCV", by gary bradsky

    CvMoments moments; 
    double M00, M01, M10;
    
    cvMoments(contour,&moments); 
    M00 = cvGetSpatialMoment(&moments,0,0); 
    M10 = cvGetSpatialMoment(&moments,1,0); 
    M01 = cvGetSpatialMoment(&moments,0,1); 
    centers[i].x = (int)(M10/M00); 
    centers[i].y = (int)(M01/M00); 
    
    0 讨论(0)
  • 2021-01-13 08:51

    I've used Joseph O'Rourke excellent polygon centroid algorithm to great success.

    See http://maven.smith.edu/~orourke/Code/centroid.c

    Essentially:

    1. For each point in the contour, find the triangle area from the current index polygon xy to the next 2 polygon xy points e.g.: Math.Abs(((X1 - X0) * (Y2 - Y0) - (X2 - X0) * (Y1 - Y0)) / 2)
    2. Add this triangle area to a list TriAreas
    3. Sum the triangle area, and store in SumT
    4. Find the centroid CTx and CTy from this current triangle: CTx = (X0 + X1 + X2) / 3 and CTy = (Y0 + Y1 + Y2) / 3;
    5. Store these 2 centroid values in 2 other lists CTxs CTys.
    6. Finally after performing this with all points in the contour, find the contours centroid x and y using the 2 triangle x and y lists in 5 which is a weighted sum of signed triangle areas, weighted by the centroid of each triangle:

          for (Int32 Index = 0; Index < CTxs.Count; Index++)
          {
              CentroidPointRet.X += CTxs[Index] * (TriAreas[Index] / SumT);
          } 
          // now find centroid Y value
          for (Int32 Index = 0; Index < CTys.Count; Index++)
          {
              CentroidPointRet.Y += CTys[Index] * (TriAreas[Index] / SumT);
          }
      
    0 讨论(0)
  • 2021-01-13 08:52

    What you get in your current piece of code is of course the centroid of your bounding box.

    "If you have a bunch of points(2d vectors), you should be able to get the centroid by averaging those points: create a point to add all the other points' positions into and then divide the components of that point with accumulated positions by the total number of points." - George Profenza mentions

    This is indeed the right approach for the exact centroid of any given object in two-dimentionalspace.

    On wikipedia we have some general forms for finding the centroid of an object. http://en.wikipedia.org/wiki/Centroid

    Personally, I would ask myself what I needed from this program. Do I want a thorough but performance heavy operation, or do I want to make some approximations? I might even be able to find an OpenCV function that deals with this correct and efficiently.

    Don't have a working example, so I'm writing this in pseudocode on a simple 5 pixel example on a thorough method.

    x_centroid = (pixel1_x + pixel2_x + pixel3_x + pixel4_x +pixel5_x)/5
    y_centroid = (pixel1_y + pixel2_y + pixel3_y + pixel4_y +pixel5_y)/5
    
    centroidPoint(x_centroid, y_centroid)
    

    Looped for x pixels

    Loop j times *sample (for (int i=0, i < j, i++))*
    {
        x_centroid = pixel[j]_x + x_centroid
        y_centroid = pixel[j]_x + x_centroid
    }
    x_centroid = x_centroid/j
    y_centroid = y_centroid/j
    
    centroidPoint(x_centroid, y_centroid)
    

    Essentially, you have the vector contours of the type

    vector<vector<point>>
    

    in OpenCV 2.3. I believe you have something similar in earlier versions, and you should be able to go through each blob on your picture with the first index of this "double vector", and go through each pixel in the inner vector.

    Here is a link to documentation on the contour function http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contours#cv.DrawContours

    note: you've tagged your question as c++ visual. I'd suggest that you use the c++ syntax in OpenCV 2.3 instead of c. The first and good reason to use 2.3 is that it is more class based, which in this case means that the class Mat (instead of IplImage) does leak memory. One does not have to write destroy commands all the live long day :)

    I hope this shed some light on your problem. Enjoy.

    0 讨论(0)
提交回复
热议问题