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_TREECV_RETR_EXTERNAL. 我还解决了其他一些小问题,但结果很好:

在此处输入图像描述

不知道我是应该在这里写这个还是打开新线程....但是现在我需要一些帮助来处理组件标签和提取参数,例如中心点和面积。:)

4

4 回答 4

6

看看我在这个主题中的其他答案。编译该代码并记住激活被注释掉的代码。

结果

在此处输入图像描述

于 2013-02-06T16:57:32.060 回答
5

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

所以我要做的第一件事是对阈值图像进行一些形态学操作来过滤所有噪声:做一些打开和关闭,这两者都是膨胀和腐蚀的组合。

在您的情况下,类似于 cvDilate(2 次);cvErode(4次);cvDilate(2次)

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

于 2013-02-06T16:20:30.650 回答
1

在找到轮廓之前,您应该应用形态过滤器,例如erodedilate。之后,您可以通过计算其大小或边界框的高度和高度来找到轮廓并忽略小的轮廓。最后,您可以使用层次结构消除其他轮廓内的那些。

于 2013-02-06T16:21:55.220 回答
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;

}
于 2013-02-06T16:47:24.167 回答