边缘检测/角度

时间:2013-09-13 13:10:04

标签: c++ image-processing signal-processing edge-detection

我可以成功阈值图像并在图像中找到边缘。我正在努力的是试图准确地提取黑色边缘的角度。

我目前正在使用黑色边缘的极值点并使用atan2函数计算角度,但由于混叠,根据您选择的点,角度可能会出现一定程度的变化。是否有可靠的可编程方式选择点来计算角度?

示例图片:

Wonky Checker board

例如,Gimp Measure工具角度为3.12°,

Gimp Measurement tool

4 个答案:

答案 0 :(得分:3)

如果你正在编写自己的库,那么为这个问题创建一个强大的解决方案将允许你开发几个独立的代码块,你可以串起来解决其他问题。我假设您想在任意旋转下,在变化的光照条件下,在图像噪声存在的情况下找到棋盘角,有一点非线性枕形/桶形失真,等等。

尽管有一些简单的基于内核的技术可以将整个像素作为边缘像素进行查找,但在使用填充多边形时,您会希望使用能够找到具有亚像素精度的边缘的算法,以便您可以执行准确的线条拟合。即使从黑色方块到白色方块的渐变穿过几个像素," true"边缘将在某个子像素点处找到,很可能不是您通过手动点击猜测的点。

我试图在这篇较旧的SO帖子中提供边缘发现的简单摘要: what is the relationship between image edges and gradient?

对于像你这样的问题,一个强大的解决方案是沿着亚像素精度找到沿暗到光过渡的边缘点,然后将线拟合到边缘点,并使用线角度。如果您正在处理真实的相机图像,并且图像中存在未校正的径向失真,则测量精度存在一些潜在问题,但我们会忽略这些问题。

如果要找到边缘的精确拟合,那么在垂直于该边缘的方向上扫描子像素边缘会很棒。这预先假定我们对边缘方向有一些合理的估计。我们可以首先找到边缘方向的粗略估计,然后执行精确的线拟合。

下面的算法似乎有太多步骤,但我的目的是指出如何提供强大的解决方案。

  1. 对黑色像素执行一些侵蚀迭代,将黑匣子彼此分开。
  2. 运行连通分量算法(blob-finding算法)以找到被侵蚀的黑色方块。
  3. 识别每个被侵蚀的正方形的中心(x,y)点以及定义长轴和短轴的(x,y)终点。
  4. 维护结构中每个方块的数据,该结构具有以像素为单位的总面积,中心(x,y)点,长轴和短轴的(x,y)点等。
  5. 根据需要,消除太小的所有组件(blob)。例如,你想要排除所有的盐和辣椒"噪音斑点。您可能还会暂时忽略被图像边缘切掉的棋盘格 - 我们可以稍后返回。
  6. 然后,您将遍历blob列表并为每个blob执行以下操作:

    1. 确定大致垂直于棋盘方块边缘的方向。如何完成此操作部分取决于运行连接组件算法时计算的数据。在通用图像处理库中,标准连通分量算法将确定每个单独blob的许多属性和测量:面积,圆度,长轴方向,短轴方向,长轴和短轴的端点等。矩形图形,计算最顶部,最左侧,最右侧和最底部的点就足够了,因为它们将定义四个角。
    2. 在大致垂直于边缘的方向上生成边缘扫描。这些必须在原始的,未经修改的图像上执行。这通常假设你已经实现了双线性插值来找到子像素(x,y)点的灰度值,例如(100.35,25.72),因为你的扫描线不会完全落在整个像素上。
    3. 使用子像素边缘点寻找技术。通常,您将在扫描方向上对边缘点执行曲线拟合,然后在最大梯度处找到实值(x,y)点。这是边缘点。
    4. 将所有子像素边缘点存储在列表/数组/集合中。
    5. 为边缘点生成线条拟合。这些可以使用Hough,RANSAC,最小二乘法或其他技术。
    6. 根据四个线条拟合的线方程,计算线条角度。
    7. 该算法独立地为每个黑色棋盘方块找到角度。对于这一个应用程序来说可能有点过分,但是如果你正在开发一个库,那么它可能会给你一些关于要实现哪些子算法以及如何构建它们的想法。例如,该算法将依赖于这些技术的实现:

      • 图像形态(例如侵蚀,扩张,闭合,开放,......)
      • 实现形态的内核操作
      • 对图像进行二值化的阈值处理 - Otsu方法值得一试
      • 连接组件算法(a.k.a blob查找或OpenCV轮廓函数)
      • blob的数据结构
      • blob数据的矩量计算
      • 双线性插值以找到子像素(x,y)值
      • 一种线性射线扫描技术,用于沿特定方向找到(x,y)灰度值(也将依赖于双线性插值)
      • 曲线拟合技术和确定找到边缘点的最陡切线的方法
      • 鲁棒线拟合技术:Hough,RANSAC和/或最小二乘法
      • 线方程的数据结构,相关函数

      所有这一切,如果你愿意接受精确度的轻微损失,并且如果你知道图像没有受到径向扭曲等的影响,并且如果你只是需要找到角度由所有检查板边缘定义的平行线,然后您可以尝试..

      1. 基于内核的简单边缘点寻找技术(高斯平滑图像上的拉普拉斯算子)
      2. Hough线适合边缘点
      3. 选择投票数最多的两行,这应该是一组水平线和另一组垂直线
      4. 还有其他技术不太准确但更容易实现:

        1. 使用基于内核的角点查找运算符
        2. 找到角点之间的角度。
        3. 依此类推。当您正在开发库并创建可靠的独立功能实现时,您可以将它们组合在一起以创建特定于应用程序的解决方案,您可能会发现强大的解决方案依赖于比您猜测的更多的步骤,但是它还会更清楚每个增量步骤的故障模式,以及如何解决该故障模式。

答案 1 :(得分:0)

我可以问一下,您使用什么C ++库来编写代码?

Jerry是对的,如果你真的对图像应用了一个阈值,它将是2位,黑色或白色。你应用的是一种限制器。

您可以通过应用您可能使用的限制器然后将所有非白色像素变为黑色来制作阈值功能(如果您自己编码图像处理)。如果你有正确的设置,应该隔离正方形,你就可以计算出角度。

完成此操作后,您可以使用路径查找算法查找某些边缘,任何边缘都可以。如果您找到一个或多或少的直线路径,您可以像现在一样使用极值点来确定角度。由于棋盘旋转仅在90度内相关,因此您的角度应为模90度或pi超过2弧度。

答案 2 :(得分:0)

我不确定它(接近任何地方) 正确的答案,但我的立即反应将是两次阈值:一次除了黑色之外的任何东西都被视为白色,一次除外白色被视为黑色。

找出每个角度,然后在两个角度之间进行插值。

答案 3 :(得分:0)

你的问题很少有解决方案,但都有一个非常重要的问题你似乎忽略了。注意:当您尝试在图像中进行几何计算时,您使用的点必须尽可能远离另一个。你在一个方格内拿2分。这些点彼此非常接近,因此点的像素位置的轻微误差导致角度的大误差。当图像中有多个正方形时,为什么只使用一个正方形? 以下是一些解决方案:

  1. 找到每个方格的线角度。图像中至少有9个正方形,每个正方形有4行,总共有36个角度(18个大致为3°,18个为~93°)。移除90 [度],您将获得36个不同的角度测量值。对它们进行排序并取中间30的平均值(忽略较低的3和更高的3个测量值)。这将为您提供准确的结果
  2. 第二个解决方案,找到最左边方块的左极点和最右边方块的右极点。现在计算它们之间的角度。结果会更准确,因为这些点很远。
  3. 第三种算法,它可以为您提供准确的结果,因为它不涉及找到任何点,也不需要阈值处理。只需平滑图像,计算X和Y方向的渐变(gx,gy),计算每个像素atan(gy,gx)中的渐变角度,并制作角度的直方图。在3°和93°附近将有2个显着的峰值。只需在直方图中搜索最大值即可找到峰值。即使您在图像中有很多噪点,即使使用了防眩光和jpg瑕疵,即使图像上有其他图形,这也会起作用。但请记住,在计算导数之前,必须对图像进行平滑处理。