是否有一些更好的方法可以在opencv中找到轮廓质心,而无需使用内置函数?
答案 0 :(得分:6)
虽然Sonaten的答案是完全正确的,但有一种简单的方法可以做到:使用专用的opencv函数:moment()
它不仅会返回质心,还会返回有关您的形状的更多统计信息。您可以发送轮廓或光栅形状(二进制图像),最适合您的需要。
修改强>
示例(修改)来自“学习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,并遍历内部向量中的每个像素。
注意:您已将问题标记为c ++ visual。我建议您在OpenCV 2.3中使用c ++语法而不是c。使用2.3的第一个也是很好的理由是它更基于类,在这种情况下意味着类Mat(而不是IplImage)会泄漏内存。一个人不必在所有漫长的一天中编写销毁命令:)
我希望这可以解释你的问题。享受。
答案 2 :(得分:1)
我使用了Joseph O'Rourke优秀的多边形质心算法取得了巨大的成功。
请参阅http://maven.smith.edu/~orourke/Code/centroid.c
本质:
最后在对轮廓中的所有点执行此操作之后,使用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);
}