OpenCV边界框

3
我正在使用C++环境中的OpenCV软件。目标是检测拳击手套并在手套轮廓周围绘制一个边界框。 我遇到的问题是,实际上绘制了多个边界框,而不仅仅是一个。过去几天我一直在尝试找到方法,以便减少绘制的边界框数量,并只绘制一个大的边界框。
我正在研究一些填充对象的技术,我相信这将在这种情况下非常有帮助。
以下是我用于实现图像中显示结果的代码:
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
vector<Vec3f> vecCircles;               
vector<Vec3f>::iterator itrCircles;

while(1)
{
    Mat frame;
    cap >> frame; // get a new frame from camera
    /////////////////////
    Mat imgHSV;
    cvtColor( frame, imgHSV, CV_BGR2HSV );
    ////////////////////
    Mat blur_out;
    GaussianBlur(imgHSV, blur_out, Size(1,1),2.0,2.0);
    ////////////////////
    Mat range_out;
    inRange(blur_out, Scalar(100, 100, 100), Scalar(120, 255, 255), range_out);
    ////////////////////
    findContours(range_out, contours, hierarchy, CV_RETR_TREE,  CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

     /// Approximate contours to polygons + get bounding rects and circles
     vector<vector<Point> > contours_poly( contours.size() );
     vector<Rect> boundRect( contours.size() );
     vector<Point2f>center( contours.size() );
     vector<float>radius( contours.size() );

     for( int i = 0; i < contours.size(); i++ )
     { 
         approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
         boundRect[i] = boundingRect( Mat(contours_poly[i]) );
     }

     /// Draw polygonal contour + bonding rects
     Mat drawing = Mat::zeros( range_out.size(), CV_8UC3 );
     for( int i = 0; i< contours.size(); i++ )
     {
         Scalar color = Scalar(255,0,255);
         drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
         rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );          
     }

输入图像描述

如果有人可以提供一些提示或提供一些信息来源,让我找到解决问题的答案。

编辑(快速更新):

我成功地逐步改善了输出图像,直到达到一个我很满意的结果。关键是在我的findContours()函数中使用侵蚀和膨胀。我将CV_RETR_TREE更改为CV_RETR_EXTERNAL。我还处理了一些其他小事情,但结果很好:

输入图像描述

不知道是否应该在这里写这个问题还是开启新主题...但现在我需要一些组件标记和提取参数(如中心点和区域)的帮助。 :)


1
请随意为帮助您的答案点赞。 - karlphillip
4个回答

6

5

您目前在每个轮廓周围绘制一个边界框,并且findContour将找到与图片中的每个连接的白色或黑色组件周围的轮廓,其中有许多。

因此,我首先要做的是使用一些形态学操作过滤所有噪声,对阈值图像进行开运算和闭运算,两者都是膨胀和腐蚀的组合。

在您的情况下,可以尝试cvDilate(2次); cvErode(4次); cvDilate(2次)

这应该将所有白色斑点合并为一个平滑的斑点,但中间的黑洞仍然存在。 您可以通过大小找到正确的黑洞,但更容易调用CV_RETR_EXTERNAL而不是CV_RETR_TREE的findContours,然后它只会返回最外层轮廓。


感谢您的建议,当您在代码中使用cvDilate(2次); cvErode(4次); cvDilate(2次)时,它看起来像这样...?:Mat dilate; Mat element(7,7,CV_8U,Scalar(1)); cv :: dilate(range_out,dilate,element,Point(-1,-1),2);Mat erode; Mat element2(7,7,CV_8U,Scalar(1)); cv :: erode(dilate,erode,element2,Point(-1,-1),4);Mat dilate2; Mat element3(7,7,CV_8U,Scalar(1)); cv :: dilate(range_out,dilate2,element3,Point(-1,-1),2); - Tomazi

1
在查找轮廓之前,您应该应用形态学滤波器,例如腐蚀膨胀。之后,您可以通过计算其大小或边界框的宽度和高度来找到轮廓并省略小轮廓。最后,您可以使用层次结构消除其他轮廓内部的轮廓。

0

正如 b_m 所提到的,您需要应用形态学操作。然后我会在图像中找到最大的轮廓,并仅在该轮廓周围绘制边界框。我为我的一个项目创建了以下函数,如果以正确的方式使用,我认为它会对您有所帮助。

CvSeq* findLargestContour(CvSeq* contours){

  CvSeq* current_contour = contours;
  double largestArea = 0;
  CvSeq* largest_contour = NULL;

  // check we at least have some contours

  if (contours == NULL){return NULL;}

  while (current_contour != NULL){

      double area = fabs(cvContourArea(current_contour));

      if(area > largestArea){
          largestArea = area;
          largest_contour = current_contour;
      }

      current_contour = current_contour->h_next;
  }

  // return pointer to largest

  return largest_contour;

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接