【问题标题】:Choosing Lines From Hough Lines从霍夫线中选择线
【发布时间】:2014-10-07 19:55:27
【问题描述】:

我正在使用霍夫线对此图像进行角点检测。我打算找到线的交点作为拐角。 这是图像。

不幸的是,霍夫为我期望的每一行返回了很多行

如何调整霍夫线,以便只有四条线对应于图像上的实际线?

【问题讨论】:

    标签: opencv computer-vision hough-transform


    【解决方案1】:

    OpenCV 的霍夫变换确实可以使用更好的非极大值抑制。没有它,你会得到这种重复行的现象。不幸的是,除了重新实现您自己的霍夫变换之外,我知道没有简单的方法来调整它。 (这是一个有效的选项。霍夫变换相当简单)

    幸运的是,在后期处理中很容易修复:

    对于非概率霍夫变换,OpenCv 将按照置信度的顺序返回线条,最强的线条在前。因此,只需取前四行在 rho 或 theta 上有很大差异。

    • 所以,将 HoughLines 找到的第一行添加到新列表中:strong_lines
    • 对于 HoughLines 找到的每一行:
      • 测试其 rho theta 是否接近任何 strong_line(例如 rho 在 50 像素以内,而 theta 在另一条线的 10° 以内)
      • 如果没有,则将其放入 strong_lines 列表中
      • 如果您找到了 4 个strong_lines,则中断

    【讨论】:

      【解决方案2】:

      我实现了 HugoRune 描述的方法,尽管我会分享我的代码作为我如何实现它的示例。我使用了 5 度和 10 像素的容差。

      strong_lines = np.zeros([4,1,2])
      
      minLineLength = 2
      maxLineGap = 10
      lines = cv2.HoughLines(edged,1,np.pi/180,10, minLineLength, maxLineGap)
      
      n2 = 0
      for n1 in range(0,len(lines)):
          for rho,theta in lines[n1]:
              if n1 == 0:
                  strong_lines[n2] = lines[n1]
                  n2 = n2 + 1
              else:
                  if rho < 0:
                     rho*=-1
                     theta-=np.pi
                  closeness_rho = np.isclose(rho,strong_lines[0:n2,0,0],atol = 10)
                  closeness_theta = np.isclose(theta,strong_lines[0:n2,0,1],atol = np.pi/36)
                  closeness = np.all([closeness_rho,closeness_theta],axis=0)
                  if not any(closeness) and n2 < 4:
                      strong_lines[n2] = lines[n1]
                      n2 = n2 + 1
      

      编辑:代码已更新以反映有关负 rho 值的评论

      【讨论】:

      • 如果您不规范已经存储在 strong_lines 中的行(包括第一个行),该错误是否会持续存在?无论如何,感谢这段代码,它真的很有帮助!
      【解决方案3】:

      收集所有线的交点

      for (int i = 0; i < lines.size(); i++)
      {
          for (int j = i + 1; j < lines.size(); j++)
          {       
              cv::Point2f pt = computeIntersectionOfTwoLine(lines[i], lines[j]);
              if (pt.x >= 0 && pt.y >= 0 && pt.x < image.cols && pt.y < image.rows)
              {
                  corners.push_back(pt);
              }
          }
      }
      

      你可以谷歌算法找到两条线的交点。 收集所有交点后,您可以轻松确定最小最大值,这将为您提供左上角和右下角点。从这两点可以很容易的得到矩形。

      这里Sorting 2d point array to find out four corners & http://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/ 参考这两个链接。

      【讨论】:

      • 第二个链接坏了。
      【解决方案4】:

      这是使用 OpenCV 2.4 用 python 2.7.x 编写的完整解决方案。 它基于此线程的想法。

      方法:检测所有行。假设 Hough 函数首先返回排名最高的行。过滤线以保留那些以最小距离和/或角度分开的线。

      所有霍夫线的图像: https://i.ibb.co/t3JFncJ/all-lines.jpg

      过滤的行: https://i.ibb.co/yQLNxXT/filtered-lines.jpg

      代码: http://codepad.org/J57oVIzs

      """
      Detect the best 4 lines for a rounded rectangle.
      """
      
      import numpy as np
      import cv2
      
      input_image = cv2.imread("image.jpg")
      
      def drawLines(img, lines):
          """
          Draw lines on an image
          """
          for line in lines:
              for rho,theta in line:
                  a = np.cos(theta)
                  b = np.sin(theta)
                  x0 = a*rho
                  y0 = b*rho
                  x1 = int(x0 + 1000*(-b))
                  y1 = int(y0 + 1000*(a))
                  x2 = int(x0 - 1000*(-b))
                  y2 = int(y0 - 1000*(a))
                  cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
      
      input_image_grey = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
      edged = input_image_grey
      
      rho = 1 # 1 pixel
      theta = 1.0*0.017 # 1 degree
      threshold = 100
      lines = cv2.HoughLines(edged, rho, theta, threshold)
      
      # Fix negative angles
      num_lines = lines.shape[1]
      for i in range(0, num_lines):
          line = lines[0,i,:]
          rho = line[0]
          theta = line[1]
          if rho < 0:
              rho *= -1.0
              theta -= np.pi
              line[0] = rho
              line[1] = theta
      
      # Draw all Hough lines in red
      img_with_all_lines = np.copy(input_image)
      drawLines(img_with_all_lines, lines)
      cv2.imshow("Hough lines", img_with_all_lines)
      cv2.waitKey()
      cv2.imwrite("all_lines.jpg", img_with_all_lines)
      
      # Find 4 lines with unique rho & theta:
      num_lines_to_find = 4
      filtered_lines = np.zeros([1, num_lines_to_find, 2])
      
      if lines.shape[1] < num_lines_to_find:
          print("ERROR: Not enough lines detected!")
      
      # Save the first line
      filtered_lines[0,0,:] = lines[0,0,:]
      print("Line 1: rho = %.1f theta = %.3f" % (filtered_lines[0,0,0], filtered_lines[0,0,1]))
      idx = 1 # Index to store the next unique line
      # Initialize all rows the same
      for i in range(1,num_lines_to_find):
          filtered_lines[0,i,:] = filtered_lines[0,0,:]
      
      # Filter the lines
      num_lines = lines.shape[1]
      for i in range(0, num_lines):
          line = lines[0,i,:]
          rho = line[0]
          theta = line[1]
      
          # For this line, check which of the existing 4 it is similar to.
          closeness_rho   = np.isclose(rho,   filtered_lines[0,:,0], atol = 10.0) # 10 pixels
          closeness_theta = np.isclose(theta, filtered_lines[0,:,1], atol = np.pi/36.0) # 10 degrees
      
          similar_rho = np.any(closeness_rho)
          similar_theta = np.any(closeness_theta)
          similar = (similar_rho and similar_theta)
      
          if not similar:
              print("Found a unique line: %d rho = %.1f theta = %.3f" % (i, rho, theta))
              filtered_lines[0,idx,:] = lines[0,i,:]
              idx += 1
         
          if idx >= num_lines_to_find:
              print("Found %d unique lines!" % (num_lines_to_find))
              break
      
      # Draw filtered lines
      img_with_filtered_lines = np.copy(input_image)
      drawLines(img_with_filtered_lines, filtered_lines)
      cv2.imshow("Filtered lines", img_with_filtered_lines)
      cv2.waitKey()
      cv2.imwrite("filtered_lines.jpg", img_with_filtered_lines)
      

      【讨论】:

        【解决方案5】:

        上述方法(由@HugoRune's 提出并由@Onamission21 实现)是正确的,但有一个小错误。 cv2.HoughLines 可能会返回负 rho 和 theta 到 pi。请注意,例如,线 (r0,0) 非常靠近线 (-r0,pi-epsilon),但在上述紧密度测试中找不到它们。 我只是通过在计算接近度之前应用rho*=-1, theta-=pi 来处理负 rhos。

        【讨论】:

        • “上述方法”是什么?您能否将此作为评论添加到正确答案中?
        • 我不能。评论需要一个我还没有的最低信誉分数:(我指的是由 Onamission21 实现的@HugoRune 的解决方案。该解决方案原则上是正确的,但错过了这个重要的错误。
        猜你喜欢
        • 2013-03-09
        • 2023-02-08
        • 2016-02-06
        • 1970-01-01
        • 2012-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-11
        相关资源
        最近更新 更多