【问题标题】:Find rectangles without corners using opencv使用opencv查找没有角的矩形
【发布时间】:2011-04-26 17:54:42
【问题描述】:

我有一张图像,我想在其中找到轮廓,但图像中的“轮廓”没有角。我可以使用一些技巧来帮助找到此图像中线条所隐含的矩形吗?我考虑过延伸所有线条以形成角落,但我担心线条与其他轮廓相交以及如何确定我感兴趣的交叉点。我对 opencv 很陌生,对图像处理知之甚少。感谢您提供的任何帮助。

【问题讨论】:

    标签: opencv


    【解决方案1】:

    使用Hough transform 拟合二进制图像中的线条,并将矩形拟合到正交相交的线条。

    【讨论】:

    • 雅各布,感谢您的快速回复。我对 houghlines2 很熟悉,但实际上我使用 cvFindContours 来处理具有 2 个点的轮廓。 Houghlines 并不总是能给出好的结果,我不得不把阈值弄得太乱。我相信问题的真正症结在于拟合矩形,我想不出一个好的方法,但我确实做了一些我会发布的东西。
    【解决方案2】:

    我最终实现了自己的解决方案。它不是很优雅,但它完成了工作。我有兴趣听到有关改进的信息。 HoughLines2 在寻找线段方面并不总是给我很好的结果,而且我不得不在不同的场景中大量使用阈值。相反,我选择了 FindCountours,我用两个元素获取轮廓,我应该保证 1 像素宽的线条。找到线条后,我遍历它们并追踪它们以找到矩形。

    其中点是线端点的*CvSeq

    while(points->total>0){
      if(p1.x==-1&&p1.y==-1){
         cvSeqPopFront(points,&p1);
         cvSeqPopFront(points,&p2);
      }
    
      if((pos=findClosestPoint(&p1,&p2, points,maxDist))>=0){  
         p3 = (CvPoint*)cvGetSeqElem( points,pos );
         pos2 = (pos%2==0)?pos+1:pos-1; //lines are in pairs of points
         p4 = (CvPoint*)cvGetSeqElem( points,pos2 );
    
         if(isVertical(&p1,&p2) && isHorizontal(p3,p4)){
            printf("found Corner %d %d\n",p2.x,p3->y);
         } else if(isHorizontal(&p1,&p2) && isVertical(p3,p4) ){
            printf("found Corner %d %d\n",p3->x,p2.y);
         }
    
         memcpy(&p1,p3,sizeof(CvPoint));
         memcpy(&p2,p4,sizeof(CvPoint));
         cvSeqRemove(points, (pos>pos2)?pos:pos2);
         cvSeqRemove(points, (pos>pos2)?pos2:pos);
      } else {
         p1.x=-1;
         p1.y=-1;
      }
    }
    
    int findClosestPoint (CvPoint *p1, CvPoint *p2, CvSeq *points, int maxDist) {  
       int ret = -1,i;
       float dist, minDist = maxDist;
       CvPoint* test;
       int (*dirTest)(CvPoint *,CvPoint *);
    
       if(isVertical(p1,p2)){ //vertical line
          if(p2->y > p1->y) {//going down
             dirTest = isBelow;
          } else { // going up
             dirTest = isAbove;
          }
       } else if (isHorizontal(p1,p2)){ //horizontal line
          if(p2->x > p1->x) {//going right
             dirTest = isRight;
          } else { //going left
             dirTest = isLeft;
          }
       }
    
       for( i = 0; i < points->total; i++ )
       {
          test = (CvPoint*)cvGetSeqElem( points, i );
          if(dirTest(p2,test)){ //only test points in the region we care about
             dist = sqrt(pow(test->x - p2->x,2)+pow(test->y - p2->y,2));
             if(dist<minDist){
                minDist = dist;
                ret = i;
             }
          }
       } 
       return ret;
    }
    
    int isVertical(CvPoint *p1, CvPoint *p2){
       return p1->x == p2->x;
    }
    int isHorizontal(CvPoint *p1, CvPoint *p2){
       return p1->y == p2->y;
    }
    int isRight(CvPoint *pt1, CvPoint *pt2){
       return pt2->x > pt1->x;
    }
    int isLeft(CvPoint *pt1, CvPoint *pt2){
       return pt2->x < pt1->x;
    }
    int isBelow(CvPoint *pt1, CvPoint *pt2){
       return pt2->y > pt1->y;
    }
    int isAbove(CvPoint *pt1, CvPoint *pt2){
       return pt2->y < pt1->y;
    }
    

    【讨论】:

    • 这是如何工作的?我猜它会找到最近的点并将它们链接起来。并使用 isVertical/etc 函数,检查它是否为垂直线。
    • 基本上我遍历 FindContours 找到的行。对于第一行,我确定它的方向,所以可以说它从左到右。然后,我在剩余的行中寻找最接近的点,即我的第一行最右边的点。最近的点将是一条线的一个端点,我找到另一个,然后确定这条新线的方向。如果新线垂直于我的第一条线,我会找到一个角,如果不是,那么我只会继续寻找更多线,这些线不可避免地会更向右。当我找到行时,我将它们从列表中删除。
    • 在上面的例子中,一旦我找到一条垂直线,我就会朝不同的方向移动。所以我可能会从左到右然后从下到上移动,在那里我只能找到我的线上方的点等。最终 findClosest 将不再找到点,因为我指定了最大距离,我将移动到从 FindContours 找到的另一个起始线段
    【解决方案3】:

    您也可以尝试将其视为优化问题。矩形定义为 4D 状态向量 (x,w,width,height) 或 5D 向量,如果包含旋转 (x,y,width,height,rotation)。对于您当前的状态,您可以对霍夫线的结果进行梯度下降以收敛到最佳状态。其他选项是使用线性最小二乘:http://people.inf.ethz.ch/arbenz/MatlabKurs/node88.html

    【讨论】:

      【解决方案4】:

      使用hough transform,您将能够提取行。然后你可以计算这些线的交点来估计矩形的位置。

      【讨论】:

      • 我考虑过将线条延伸出来并找到交叉点,但这给我留下了一些我必须剔除的假矩形。更多的矩形会变得更糟。我做了一个不是很优雅的自定义解决方案,但我会发布。
      猜你喜欢
      • 1970-01-01
      • 2018-03-11
      • 2011-12-15
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      • 2013-07-04
      • 2014-06-07
      相关资源
      最近更新 更多