关于 OpenCV 算法 contourArea想法
程序员文章站
2022-05-17 21:03:24
...
一 :问题提出
最近使用OpenCV做图像处理 使用 contourArea算法来计算, 通过findContours 获取的轮廓的面积
findContours(img_edge, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
sort(contours.begin(), contours.end(), Contour_Area);
vector<Spot>spotProperty(((int)contours.size()) - 1);
for (int i = 0; i < ((int)contours.size()); i++)
{
int area = contourArea(contours[i]);
}
通过数据显示发现得到的 area有值为0的情况,但是轮廓的最小外接矩形的长、 宽又不为0 很是奇怪,而且明显不符合对面积的筛选实际。
具体解析可以参考 博客:https://blog.csdn.net/yiqiudream/article/details/51858421 的解释说明。
二:解决方式
通过在网上查询及探讨 发现可以通过 countNonZero算法来获取非0 数值的面积
具体解决算法如下 方式一:
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img_edge, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
sort(contours.begin(), contours.end(), Contour_Area);
vector<Spot>spotProperty(((int)contours.size()) - 1);
for (int i = 0; i < ((int)contours.size()); i++)
{
RotatedRect minRect = minAreaRect(contours[i]);
//int area = contourArea(contours[i]);
Rect rect = boundingRect(contours[i]);
Mat rectImg = Mat(curImg, rect);
int area = countNonZero(rectImg);
int width = minRect.size.width;
int height = minRect.size.height;
result += to_string(area) + "," + to_string(minRect.center.x) + "," + to_string(minRect.center.y) + "," + to_string(minRect.center.x - imgWidth / 2) + "," + to_string(minRect.center.y - imgHeight / 2) + "," + to_string(width) + "," + to_string(height) + ";";
}
通过 boundingRect 算法获取轮廓的外接矩形 并在原图像上进行截取,然后使用 countNonZero算法获取非0值作为轮廓面积。
方式二 :通过轮廓的特征矩获取 轮廓的面积和轮廓的重心
针对一幅图像,我们把像素的坐标看成是一个二维随机变量(X, Y),那么一副灰度图可以用二维灰度图密度函数来表示,因此可以用矩来描述灰度图像的特征。
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img_edge, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
sort(contours.begin(), contours.end(), Contour_Area);
/// 计算矩
///vector<Moments> mu(contours.size() );
///for( int i = 0; i < contours.size(); i++ )
/// { mu[i] = moments( contours[i], false ); }
/// 计算中心矩:
/// 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 ); }
vector<Spot>spotProperty(((int)contours.size()) - 1);
for (int i = 0; i < ((int)contours.size()); i++)
{
RotatedRect minRect = minAreaRect(contours[i]);
//int area = contourArea(contours[i]);
Moments mu= moments( contours[i], false );
double centerX=mu.m10/mu.m00;
double centerY=mu.m01/mu.m00;
int area=mu.m00;
int width = minRect.size.width;
int height = minRect.size.height;
result += to_string(area) + "," + to_string(centerX) + "," + to_string(centerY) + "," + to_string(centerX - imgWidth / 2) + "," + to_string(centerY - imgHeight / 2) + "," + to_string(width) + "," + to_string(height) + ";";
}
令Xc,Yc表示区域重心的坐标,则:
Xc = M10/M00;
Yc = M01/M00;
在二值图像的情况下,M00表示区域的面积
下一篇: vuecli3路由传参的方式