在二值图像中查找曲线的交点

计算科学 图像处理
2021-12-21 07:14:22

我正在尝试在下面发布的图像中找到交点。我试图找到的交叉点在下图中用红色圈出。

二元曲线 标记的路口

我最成功的方法:

  1. 使图像变薄
  2. 执行霍夫变换、峰值识别和反向投影
  3. 识别反投影中的峰并选择它们作为交点
  4. 如果峰值太多(我说 4 太多了),转到图像的较小部分并重复上述步骤

显然,这里的一个大问题是用于检测线的霍夫变换不应该检测曲线。我认为放大兴趣点可能会解决这个问题,但事实并非如此。有些曲线仍然太尖锐,如果你放大得太远,变换没有足够的数据来准确计算线条的位置。

我还尝试了一些局部特征检测,例如角点检测,以找到交叉点。局部特征惨遭失败,并且有一些图像也可以解释为什么会这样(尽管我目前正在尝试使用渐变的另一种方法;将在我实施后更新帖子)。

本地不起作用

白色曲线不是交叉点,但蓝色和黄色曲线显然形成了一个交叉点。然而,当转换为二值图像时,这些曲线具有几乎相同的局部特征部分。任何关于如何找到这些交叉点的​​建议将不胜感激!

2个回答

您还可以查看检测与本地 Hessian 矩阵的交叉:https ://dsp.stackexchange.com/questions/10579/how-hessian-feature-detector-works 它可以检测“角”(两条线的交点) ,但也许限制将是在锐曲线(例如,如果它转为 90° 角)和 2 条独立曲线的实际交点之间确定。

我仍在寻找更好的答案,但我找到了一种平滑线条的解决方案,几乎没有噪音(所以仍然相当无用)。事实证明,当对上述二值图像进行细化时,在交叉点处会发生以下两种情况之一:连接的组件被破坏,或者一般区域中的一个像素连接到 2 个像素而不是 1 个。解决方案:修改连接成分

//PLEASE NOTE: THE IMAGE MUST BE THINNED FIRST!! Read above paragraph
int width = img.length;
int height = img[0].length;
int intersections = 0;
for (int i = 1; i < width - 2; i++){
  for (int j = 1; j < height - 2; j++){
    if (img[i,j] > 50){
      //initialize a queue for this connected component
      ArrayList<Integer[]> queue = new ArrayList<>();
      queue.add({i, j});
      img[i, j] = 0;
      while (!queue.isEmpty()){
        Integer[] c = queue.remove(0);
        int count = 0;
        for (int x = -1; x < 2; x++){
          for (int y = -1; y < 2; y++){
            if (img[c[0]+ x, c[1] + y] > 50){
              queue.add({c[0] + x, c[1] + y});
              img[c[0] + x, c[1] + y] = 0
              //count the number of pixels connected to this one
              count += 1;
            }
          }
        }
        if (count > 1){
          //if more than 1 pixel was connected, it's at an intersection
          intersections += 1;
        }
      }
    }
    //add 1 intersection for every connected component found
    intersections += 1;
  }
}
//correct for the original number of connected components in the image
//minus 1; helps offset against tendency for false negatives
intersections -= original_number_of_connected_components - 1
return intersections / 2;

上面是用 Java 编写的以公开逻辑,但我在 IDL 中实现了它,所以我没有调试过这个(即没有承诺这个代码在放入实际方法时编译。事实上,如果你不这样做,它肯定不会'不要将数组作为图像和original_number_of_connected_components参数传入)。

编辑:正如人们所预料的那样,这在锯齿状或嘈杂的图像上做了一项可怕的工作。仍在寻找更好的解决方案。

编辑:我有一个做得很好的解决方案。它将在 10 月 19 日在 GitHub 上发布,那时我会变得不那么忙。它在一些不太薄的图像上关闭,但通常在同一个球场,并且目前不适用于自相交图像。这个答案将在 19 日完全改变,除非到那时我收到一个相当简单的解决方案,否则我将修改这个答案并接受它为正确的。