EmguCV粒子分析:C++转C#轮廓面积与质心计算实现求助
Hey there! Since you've already nailed the image reading, thresholding, and contour extraction steps in EmguCV, let's get those area and centroid calculations sorted out—they're actually pretty straightforward once you know the equivalent EmguCV methods.
1. 计算轮廓面积
In your C++ code, you use contourArea() to get each contour's area and store them in a vector<double>. In EmguCV, the equivalent is CvInvoke.ContourArea(), and we can use a List<double> to hold the areas (since it's more flexible than a fixed-size array in C#):
// 存储每个轮廓的面积 List<double> areas = new List<double>(); for (int i = 0; i < contours.Size; i++) { // 获取第i个轮廓的面积 double area = CvInvoke.ContourArea(contours[i]); areas.Add(area); }
2. 计算质心(Mass Centres)
For centroids, your C++ code uses moments() to get the moment values, then calculates (mu.m10/mu.m00, mu.m01/mu.m00). EmguCV has a Moments class and CvInvoke.Moments() method to do the same. Important note: Always check if mu.M00 is not zero before dividing—this avoids division-by-zero errors for tiny or invalid contours.
Here's the C# equivalent:
// 存储每个轮廓的质心 List<PointF> massCentres = new List<PointF>(); for (int i = 0; i < contours.Size; i++) { // 计算当前轮廓的矩 Moments mu = CvInvoke.Moments(contours[i], false); // 避免除以零(当轮廓面积为0时跳过) if (mu.M00 != 0) { double cx = mu.M10 / mu.M00; double cy = mu.M01 / mu.M00; massCentres.Add(new PointF((float)cx, (float)cy)); } else { // 可以选择添加默认点或者跳过,这里用-1标记无效质心 massCentres.Add(new PointF(-1, -1)); } }
完整整合代码
Putting it all together with your existing code:
Mat frame = CvInvoke.Imread(file2, ImreadModes.Grayscale); CvInvoke.Threshold(frame, frame, 127, 255, ThresholdType.Binary); Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint(); Mat hierarchy = new Mat(); CvInvoke.FindContours(frame, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxSimple); // 计算轮廓面积 List<double> areas = new List<double>(); for (int i = 0; i < contours.Size; i++) { areas.Add(CvInvoke.ContourArea(contours[i])); } // 计算质心 List<PointF> massCentres = new List<PointF>(); for (int i = 0; i < contours.Size; i++) { Moments mu = CvInvoke.Moments(contours[i], false); if (mu.M00 != 0) { float cx = (float)(mu.M10 / mu.M00); float cy = (float)(mu.M01 / mu.M00); massCentres.Add(new PointF(cx, cy)); } else { massCentres.Add(new PointF(-1, -1)); // 用-1标记无效质心 } }
A quick breakdown of the mappings from your C++ code:
vector<double> areas→List<double> areascontourArea(contours[i])→CvInvoke.ContourArea(contours[i])moments(contours[i], false)→CvInvoke.Moments(contours[i], false)Point2d(mu.m10/mu.m00, mu.m01/mu.m00)→PointF((float)(mu.M10/mu.M00), (float)(mu.M01/mu.M00))(EmguCV uses PointF for floating-point coordinates)
内容的提问来源于stack exchange,提问作者Haleem Ahmad

