边缘检测/角度

ill*_*umi 1 c++ signal-processing image-processing edge-detection

我可以成功地对图像进行阈值处理并在图像中找到边缘。我正在努力尝试准确提取黑边的角度。

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

示例图像:

摇摇欲坠的棋盘

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

Gimp 测量工具

Ret*_*unk 5

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

尽管有一些简单的基于内核的技术可以将整个像素作为边缘像素来查找,但在处理填充多边形时,您会希望使用能够以亚像素精度查找边缘的算法,以便您可以执行精确的线拟合。即使从暗方块到白色方块的渐变跨越了几个像素,“真实”边缘仍会在某个子像素点处找到,而且很可能不是您手动点击所猜测的点。

我试图在这篇较旧的 SO 帖子中提供边缘查找的简单摘要: 图像边缘和梯度之间的关系是什么?

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

如果您想找到边缘的精确拟合,那么最好在垂直于该边缘的方向上扫描子像素边缘。这假设我们开始时对边缘方向有一些合理的估计。我们可以先找到边缘方向的粗略估计,然后进行精确的线拟合。

下面的算法可能看起来步骤太多,但我的目的是指出如何提供稳健的解决方案。

  1. 对黑色像素执行几次腐蚀迭代以将黑框彼此分开。
  2. 运行连通分量算法(blob-finding algorithm)来找到被侵蚀的黑色方块。
  3. 确定每个侵蚀正方形的中心 (x,y) 点以及定义长轴和短轴的 (x,y) 端点。
  4. 维护结构中每个正方形的数据,该结构具有以像素为单位的总面积、中心 (x,y) 点、长轴和短轴的 (x,y) 点等。
  5. 根据需要,消除所有太小的组件(斑点)。例如,您可能希望排除所有“盐和胡椒”噪声 blob。您也可以暂时忽略被图像边缘截断的棋盘格——我们可以稍后再返回。

然后,您将遍历 blob 列表并对每个 blob 执行以下操作:

  1. 确定大致垂直于棋盘格边缘的方向。您如何实现这一点部分取决于您在运行连通分量算法时计算的数据。在通用图像处理库中,标准的连通分量算法将为每个单独的 blob 确定数十个属性和测量值:面积、圆度、长轴方向、短轴方向、长轴和短轴的端点等。对于矩形图形,计算最顶部、最左侧、最右侧和最底部的点就足够了,因为它们将定义四个角。
  2. 在大致垂直于边缘的方向上生成边缘扫描。这些必须在原始的、未修改的图像上执行。这通常假设您实施了双线性插值来查找子像素 (x,y) 点的灰度值,例如 (100.35, 25.72),因为您的扫描线不会完全落在整个像素上。
  3. 使用亚像素边缘点查找技术。通常,您将对扫描方向上的边缘点执行曲线拟合,然后找到最大梯度处的实值 (x,y) 点。这就是边缘点。
  4. 将所有子像素边缘点存储在列表/数组/集合中。
  5. 为边缘点生成线拟合。这些可以使用 Hough、RANSAC、最小二乘法或其他技术。
  6. 从四个直线拟合的直线方程中,计算直线角度。

该算法为每个黑色棋盘格独立地找到角度。对于这个应用程序来说可能有点过头了,但是如果您正在开发一个库,它可能会给您一些关于要实现哪些子算法以及如何构建它们的想法。例如,该算法将依赖于这些技术的实现:

  • 图像形态(例如侵蚀、膨胀、闭合、打开……)
  • 实现形态学的内核操作
  • 阈值化图像二值化——Otsu 方法值得一试
  • 连通分量算法(又名 blob 查找,或 OpenCV 轮廓函数)
  • blob 的数据结构
  • blob 数据的矩计算
  • 用于查找子像素 (x,y) 值的双线性插值
  • 一种沿特定方向查找 (x,y) 灰度值的线性射线扫描技术(这也将依赖于双线性插值)
  • 确定最陡切线以找到边缘点的曲线拟合技术和方法
  • 稳健的线拟合技术:Hough、RANSAC 和/或最小二乘法
  • 线方程的数据结构,相关函数

综上所述,如果您愿意接受精度的轻微损失,并且您知道图像不会受到径向失真等的影响,并且您只需要找到由 定义的平行线的角度所有棋盘边缘,然后你可以尝试..

  1. 简单的基于内核的边缘点查找技术(高斯平滑图像上的拉普拉斯算子)
  2. 霍夫线适合边缘点
  3. 选择得票最多的两条线拟合,应该是一组水平线和另一组垂直线

还有其他一些不太准确但更容易实现的技术:

  1. 使用基于内核的寻角运算符
  2. 找到角点之间的角度。

等等等等。当您开发库并创建独立函数的稳健实现时,您可以将它们串在一起以创建特定于应用程序的解决方案,您可能会发现稳健的解决方案依赖的步骤比您想象的要多,但它也会更清楚每个增量步骤的故障模式是什么,以及如何解决该故障模式。