【问题标题】:Circle Detection - Reliability Assessment圆检测 - 可靠性评估
【发布时间】:2013-11-23 17:47:18
【问题描述】:

我正在编写一个基于 OpenCV 的 C++ 应用程序。该应用程序主要分析手写图像并识别符号(不要指望字母数字符号,它是deaf-specific writing system)。

我的输入图像包含形状非常不同的符号,但我想专注于圆圈。 下图展示了我目前正在处理的一些圆形符号(降噪和二值化之后)。

为了识别圆形符号,我使用了Hough Circle Transform,它的工作做得很好。在应用中值滤波器以减少噪声和阈值以对图像进行二值化之后应用变换。

我的问题是,有时霍夫圆变换会检测到没有圆的圆(见下图)。

现在,我一直在为检测到的圆圈寻找一些“可靠性评估”。但我运气不佳。 有什么方法可以查看检测到的圆圈是否与真实的圆圈有关?

我开始自己考虑一些解决方案,但也许有人想出了更聪明的方法,我可以:

  • 用实际符号评估检测到的圆的每个点的 Husdorff 距离,并将其用作某种测量值
  • 使用检测到的中心坐标,我可以将图像分成 4 个扇区(见下图),并查看霍夫圆变换是否在每个(或大多数)扇区中检测到某些东西。

记住:我正在处理手写(即非常粗略地绘制)的符号。

【问题讨论】:

  • 一个想法是,一旦你得到了圆的方程,就在图像上进行测试。也就是说,对于较小的 theta 增量,检查由 x,y 坐标给出的像素是否实际着色。您可以设置正确点的最小数量的阈值。
  • 我可以,会试试看。我想知道我是否缺少有关此主题的一些参考资料或以前的工作。

标签: c++ opencv detection geometry reliability


【解决方案1】:

我认为某种形式的评估你的圆点到符号的距离是可行的方法 - 我怀疑是否有更复杂的替代方案也是实用的。

然而,进行距离评估的复杂和有效方法越来越少。

由于您的符号图像已经二值化,我建议如下:计算二值图像上的Distance Transform;有efficient algorithms 这样做。然后你只需要在圆点处对距离图像进行采样,并将距离相加(可能相对于圆的周长进行归一化,以获得一定的尺度不变性)即可得到误差分数。

如果您的图片中碰巧有很多小杂物,但您发布的图片看起来很干净,这将失败。

【讨论】:

    【解决方案2】:

    我解决了设计基于@Abhishek 思想的函数的问题。

    这是伪代码及其 C++ 实现。

    checkCircleSectors(imagePoints, circle, circleExpansionFactor, theta, acceptThreshold)
    
      Divide the circle in n sectors, using angle theta (so n = 2*PI /theta)
    
      (Optional) Slightly expand or reduce the radius of the circle by circleExpansionFactor, if needed.
    
      for each point "curPoint" within the image (imagePoints){
    
        if the distance between curPoint and center.circle is lesser/equal to circle.radius{
    
          let "curAngle" be the angle between circle.center and curPoint, calculated using curPoint as origin.
          let "curSector" be the sector of circle which contains curAngle
              upgrade the ranking of curSector by one.
        }
      }
    
      if there are more than acceptThreshold sectors whose rank is zero
        the circle is not acceptable
      else
        the circle is acceptable
    

    注意事项:

    我发现稍微扩大圆的半径非常有用(我使用 1.25 的扩大系数),因为有时(特别是在手写圆的情况下)检测可能不准确。 p>

    这是我对该概念的 C++ 实现:

    boolean ImgCheck::checkCircleSectors(vector<Point> tgtPoints, Point tgtCenter, int tgtRadius, float tgtRadiusExp, int tgtStep, int tgtThreshold){
    
      vector<int> circleData( 360 / tgtStep, 0);
      int detectionReliability = 0;
    
      tgtRadius = tgtRadius * tgtRadiusExp;
    
      /* Analyze the sectors.                               */
      for(size_t i=0; i<tgtPoints.size(); i++){
    
        Point curCartesianPoint = getCartesianCoordinates(tgtCenter, tgtPoints[i]);
    
        float angleRad = arctangent2(curCartesianPoint);
        int   angleDeg = angleRad * (180/M_PI);
    
        if(distance(tgtPoints[i],tgtCenter) <= tgtRadius){
          circleData.at(angleDeg / tgtStep) += 1;
        }
    
      }
    
      /* Count the postive-ranked sectors.                 */
      for(size_t i = 0; i< circleData.size(); i++){
        if(circleData[i] > 0)
          detectionReliability += 100.0/(360/tgtStep);
      }
    
      if(detectionReliability >= tgtThreshold)
        return true;
      }
      return false;
    }
    

    注意事项:

    我对最后三个参数的偏好如下:

    • tgtRadiusExp = 1.25(半径扩大四分之一长度)
    • tgtStep = 5(theta = 5 度 -> 圆分为 72 个扇区)
    • tgtTreshold = 75(至少需要 75 个非零扇区才能通过测试)

    getCartesianCoordinates 函数(以下源代码)将 OpenCV 坐标转换为笛卡尔坐标。它需要两个参数:

    • Point tgtOrigin 是该点的 openCV 坐标,必须是 用作原点。
    • 点 tgtPoint 是另一个点的 openCV 坐标。

    函数返回tgtPoint的坐标,以tgtOrigin为原点进行转换。

    Point getCartesianCoordinates(Point tgtOrigin, Point tgtPoint){
    
      Point resPoint = tgtPoint - tgtOrigin;
    
      return Point(resPoint.x, -resPoint.y);
    }
    

    【讨论】:

      【解决方案3】:

      花了一些时间对椭圆检测器进行手动编码后,我在检测“椭圆”方面遵循了类似的路径(拟合优度是一个指南)。但是,最终,手动编码这样的检测器是一项脆弱的工作,因为您的输入确实没有那么明确;您可能会发现人类读者将成功识别出许多“圆”,这些“圆”将无法对“圆”进行任何合理的数学定义。因此接受你的角色的实际操作定义不是圆的方程。

      我建议您考虑一种完全不同的方法; 训练它们,而不是手动编码检测器。这是最先进的手写识别方法,您可以选择流行的经过充分验证的算法 (the MNIST dataset of hand-written arabic numerals is a popular bench-mark)。与其编写检测器,不如为自己构建一个非常好的训练集;您不必为每个字符手动编码检测器,并且您将构建一些非常强大且经过良好测试的东西,可以应对非常草率的笔迹、污迹、涂鸦等(例如您可以在 MNIST 数据集中找到)。

      【讨论】:

        猜你喜欢
        • 2019-10-22
        • 1970-01-01
        • 2010-09-21
        • 1970-01-01
        • 2020-04-05
        • 2018-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多