我可以成功地阈值图像并找到图像中的边缘。我正在努力尝试准确地提取黑边的角度。
我目前正在取黑边的极值点并使用 atan2 函数计算角度,但由于混叠,根据您选择的点,角度可能会出现一定程度的变化。是否有可靠的可编程方式来选择计算角度的点?
示例图片:
例如,Gimp Measure 工具角度为 3.12°,
我可以成功地阈值图像并找到图像中的边缘。我正在努力尝试准确地提取黑边的角度。
我目前正在取黑边的极值点并使用 atan2 函数计算角度,但由于混叠,根据您选择的点,角度可能会出现一定程度的变化。是否有可靠的可编程方式来选择计算角度的点?
示例图片:
例如,Gimp Measure 工具角度为 3.12°,
如果您正在编写自己的库,那么为这个问题创建一个强大的解决方案将允许您开发几个独立的代码块,您可以将它们串在一起以解决其他问题。我假设您想在任意旋转、不同照明条件下、存在图像噪声、带有一点非线性枕形/桶形失真等情况下找到棋盘的角。
尽管有简单的基于内核的技术可以将整个像素查找为边缘像素,但在处理填充多边形时,您会希望使用能够以亚像素精度查找边缘的算法,以便您可以执行准确的线拟合。即使从深色方块到白色方块的渐变跨越了几个像素,“真正的”边缘也会出现在某个子像素点上,而且很可能不是您通过手动点击猜测的点。
我试图在这个较早的 SO 帖子中提供边缘查找的简单总结: 图像边缘和梯度之间的关系是什么?
对于像您这样的问题,一个稳健的解决方案是沿着从暗到亮的过渡以亚像素精度找到边缘点,然后将线条拟合到边缘点,并使用线条角度。如果您正在处理真实的相机图像,并且图像中存在未经校正的径向失真,则测量精度存在一些潜在问题,但我们将忽略这些问题。
如果您想找到边缘的精确拟合,那么最好在垂直于该边缘的方向上扫描亚像素边缘。这假设我们对边缘方向有一些合理的估计。我们可以先找到边缘方向的粗略估计,然后进行精确的线拟合。
下面的算法可能看起来有太多的步骤,但我的目的是指出如何提供一个健壮的解决方案。
然后,您将遍历您的 blob 列表并对每个 blob 执行以下操作:
该算法独立地找到每个黑色棋盘格的角度。对于这个应用程序来说这可能有点过头了,但如果你正在开发一个库,它可能会给你一些关于要实现哪些子算法以及如何构建它们的想法。例如,该算法将依赖于这些技术的实现:
综上所述,如果您愿意接受轻微的精度损失,并且您知道图像不会遭受径向失真等问题,并且您只需要找到由定义的平行线的角度所有棋盘边缘,那么您可以尝试..
还有其他一些不太准确但更容易实现的技术:
等等等等。当您开发库并创建独立函数的健壮实现时,您可以将这些函数串在一起创建特定于应用程序的解决方案,您可能会发现健壮的解决方案依赖于比您想象的更多的步骤,但它也会更清楚每个增量步骤的故障模式是什么,以及如何解决该故障模式。
我不确定它是否(任何接近)正确答案,但我的直接反应是两次阈值:一次将除黑色之外的任何东西视为白色,一次将除白色之外的任何东西视为黑色。
找到每个角度,然后在两个角度之间进行插值。
您的问题几乎没有解决方案,但都有一个您似乎忽略的非常重要的问题。注意:当您尝试在图像中进行几何计算时,您使用的点必须尽可能远离另一个。您在一个正方形内获得 2 分。这些点彼此非常接近,因此点的像素位置的微小误差会导致角度的较大误差。当图像中有很多正方形时,为什么只使用一个正方形?这里有几个解决方案:
(gx,gy)
的梯度,计算每个像素的梯度角度atan(gy,gx)
并制作角度直方图。您将在 3° 和 93° 附近有 2 个显着峰值。只需通过搜索直方图中的最大值即可找到峰值。即使图像中有很多噪点,即使有抗锯齿和 jpg 伪影,即使图像上有其他图形,这也将起作用。但请记住,在计算导数之前,您必须对图像进行大量平滑处理。 请问,你用什么 C++ 库来编写这个代码?
Jerry 是对的,如果您实际上对图像应用阈值,它将是 2 位、黑色或白色。您可能应用的是一种限制器。
您可以通过应用您可能一直在使用的限制器然后将所有非白色像素变为黑色来制作阈值函数(如果您自己编码图像处理)。如果你有正确的设置,正方形应该是孤立的,你将能够计算角度。
完成此操作后,您可以使用路径查找算法来查找某些边缘,任何边缘都可以。如果您发现一条或多或少的直线路径,您可以像现在一样使用极值点来确定角度。由于棋盘旋转仅在 90 度范围内相关,因此您的角度应为模 90 度或 pi 超过 2 弧度。