欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于 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表示区域的面积