C++ OpenCV 2 质心
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9074202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
OpenCV 2 Centroid
提问by keshavdv
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?
我试图找到轮廓的质心,但在 C++ (OpenCV 2.3.1) 中实现示例代码时遇到问题。谁能帮我吗?
回答by Abid Rahman K
To find the centroid of a contour, you can use the method of moments. And functions are implemented OpenCV.
要找到轮廓的质心,可以使用矩量法。并且功能是实现OpenCV的。
Check out these moments function (central and spatial moments).
查看这些矩函数(中心矩和空间矩)。
Below code is taken from OpenCV 2.3 docs tutorial. Full code here.
下面的代码取自 OpenCV 2.3 文档教程。完整代码在这里。
/// 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.
回答by Alexey
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.
当有遮罩但没有轮廓时,这种方法很有用。在这种情况下,与使用cv::findContours(...)
然后找到质心相比,上述方法在计算上更有效。
回答by Antonio
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 toPoint2f
orPoint2d
, and to add a cast tofloat
ordouble
to the denominator in the return statement.
- 此公式适用于以顺时针和逆时针顺序给出的顶点。
- 如果点具有整数坐标,则将
p
返回值的类型和类型调整为Point2f
orPoint2d
,并在 return 语句中向分母添加强制转换float
或添加double
到分母可能会很方便。
回答by Rui Marques
You can also use the following algorithms to find a centroid:
您还可以使用以下算法来查找质心:
sumX = 0; sumY = 0;
size = array_points.size;
if(size > 0){
foreach(point in array_points){
sumX += point.x;
sumY += point.y;
}
centroid.x = sumX/size;
centroid.y = sumY/size;
}
Or with the help of Opencv's boundingRect:
或者借助 Opencv 的 boundingRect:
//pseudo-code:
Rect bRect = Imgproc.boundingRect(array_points);
centroid.x = bRect.x + (bRect.width / 2);
centroid.y = bRect.y + (bRect.height / 2);