c中opencv中轮廓/对象的质心?

时间:2011-11-15 21:32:21

标签: visual-c++ image-processing opencv

是否有一些更好的方法可以在opencv中找到轮廓质心,而无需使用内置函数?

3 个答案:

答案 0 :(得分:6)

虽然Sonaten的答案是完全正确的,但有一种简单的方法可以做到:使用专用的opencv函数:moment()

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

它不仅会返回质心,还会返回有关您的形状的更多统计信息。您可以发送轮廓或光栅形状(二进制图像),最适合您的需要。

修改

示例(修改)来自“学习OpenCV”,由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); 

答案 1 :(得分:2)

您在当前代码中获得的内容当然是您的边界框的质心。

“如果你有一堆点(2d向量),你应该能够通过平均这些点来获得质心:创建一个点以将所有其他点的位置添加到其中,然后将该点的分量除以积累的总分数。“ - George Profenza提到

这确实是二维空间中任何给定对象的精确质心的正确方法。

在维基百科上,我们有一些查找对象质心的一般表格。 http://en.wikipedia.org/wiki/Centroid

就个人而言,我会问自己这项计划需要什么。我是否需要彻底但性能较重的操作,或者我是否想要进行一些近似操作?我甚至可以找到一个OpenCV函数来正确有效地处理这个问题。

没有一个有效的例子,所以我用伪代码在一个简单的5像素示例上用彻底的方法写这个。

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)

循环x像素

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)

基本上,你有类型

的矢量轮廓
vector<vector<point>>

在OpenCV 2.3中。我相信你在早期版本中有类似的东西,你应该能够通过这个“双向量”的第一个索引遍历你图片上的每个blob,并遍历内部向量中的每个像素。

以下是轮廓功能文档的链接 http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contours#cv.DrawContours

注意:您已将问题标记为c ++ visual。我建议您在OpenCV 2.3中使用c ++语法而不是c。使用2.3的第一个也是很好的理由是它更基于类,在这种情况下意味着类Mat(而不是IplImage)会泄漏内存。一个人不必在所有漫长的一天中编写销毁命令:)

我希望这可以解释你的问题。享受。

答案 2 :(得分:1)

我使用了Joseph O'Rourke优秀的多边形质心算法取得了巨大的成功。

请参阅http://maven.smith.edu/~orourke/Code/centroid.c

本质:

  1. 对于轮廓中的每个点,找到从当前索引多边形xy到下一个2个多边形xy点的三角形区域,例如:Math.Abs​​(((X1-X0)*(Y2-Y0) - (X2-X0 )*(Y1 - Y0))/ 2)
  2. 将此三角形区域添加到列表TriAreas
  3. 对三角形区域求和,并以SumT
  4. 存储
  5. 从当前三角形中找出质心CTx和CTy:CTx =(X0 + X1 + X2)/ 3和CTy =(Y0 + Y1 + Y2)/ 3;
  6. 将这2个质心值存储在另外两个列表CTxs CTys中。
  7. 最后在对轮廓中的所有点执行此操作之后,使用5中的2个三角形x和y列表找到轮廓质心x和y,这是有符号三角形区域的加权和,由每个的质心加权三角:

        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);
        }