OpenCV:检测缺陷的矩形

4

目前我正在进行一个项目,尝试使用OpenCV(Python、Java或C++)在照片中找到矩形表面的角落。

我通过筛选颜色选择了所需的表面,然后得到了掩码并将其传递给cv2.findContours函数:

cnts, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02*peri, True)
if len(approx) == 4:
    cv2.drawContours(mask, [approx], -1, (255, 0, 0), 2)

这给出了我一个不准确的结果:findContours result 使用cv2.HoughLines,我已经成功得到4条直线来精确描述表面。它们的交点正是我所需要的:
edged = cv2.Canny(mask, 10, 200)
hLines = cv2.HoughLines(edged, 2, np.pi/180, 200)
lines = []
for rho,theta in hLines[0]:
    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(mask, (x1,y1), (x2,y2), (255, 0, 0), 2)
    lines.append([[x1,y1],[x2,y2]])

HoughLines结果

问题是:是否有可能调整findContours

另一个解决方案是找到交点的坐标。欢迎提供有关此方法的线索。

有人能给我提示如何解决这个问题吗?


"它们的交集正是我所需要的" -- 在这种情况下计算它们的交集。 - Dan Mašek
你能给我一个提示,我该怎么做吗? - Aray Karjauv
1
已经有很多线索可用,例如https://dev59.com/pHRB5IYBdhLWcg3wpYmo或https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection或https://dev59.com/QGs05IYBdhLWcg3wGuOd#7448287。 - Dan Mašek
这不是事实。我使用HoughLines检测线条。由于此函数返回rho和theta,因此可以按以下方式找到交点: cos(theta1)*X+sin(theta1)*Y-rho1=0 cos(theta2)*X+sin(theta2)*Y-rho2=0我已经将此解决方案添加到我的问题中。 - Aray Karjauv
当一个问题被标记为重复时,它们不应该参考“原始”问题吗? - Totoro
在我看来,这不是重复的。我需要3个更多的投票来重新打开它 :) - Aray Karjauv
2个回答

1
寻找交点并不是一个看起来轻松的问题,但在寻找交点之前,需要考虑以下问题:
  1. 选择正确的HoughLines参数是最重要的事情之一,因为它可以返回从0到无限条线(我们需要4条平行线)。
  2. 由于我们不知道这些线的顺序,它们需要相互比较。
  3. 由于透视的影响,平行线不再保持平行,因此每条线都会与其他线有一个交点。简单的解决方法是过滤掉位于照片外部的坐标。但是可能会出现不想要的交点在照片内部的情况。
  4. 坐标应该被排序。根据任务的不同,可以用不同的方式完成。
cv2.HoughLines会返回一个包含每条线的rho和theta值的数组。 现在问题变成了成对线条的方程组:

system of equations

def intersections(edged):
  # Height and width of a photo with a contour obtained by Canny
  h, w = edged.shape

  hl = cv2.HoughLines(edged,2,np.pi/180,190)[0]
  # Number of lines. If n!=4, the parameters should be tuned
  n = hl.shape[0]    
        
  # Matrix with the values of cos(theta) and sin(theta) for each line
  T = np.zeros((n,2),dtype=np.float32)
  # Vector with values of rho
  R = np.zeros((n),dtype=np.float32)

  T[:,0] = np.cos(hl[:,1])
  T[:,1] = np.sin(hl[:,1])
  R = hl[:,0]

  # Number of combinations of all lines
  c = n*(n-1)/2
  # Matrix with the obtained intersections (x, y)
  XY = np.zeros((c,2))
  # Finding intersections between all lines
  for i in range(n):
    for j in range(i+1, n):
      XY[i+j-1, :] = np.linalg.inv(T[[i,j],:]).dot(R[[i,j]])

  # filtering out the coordinates outside the photo
  XY = XY[(XY[:,0] > 0) & (XY[:,0] <= w) & (XY[:,1] > 0) & (XY[:,1] <= h)]
  # XY = order_points(XY) # obtained points should be sorted
  return XY

这是结果:

enter image description here


-1

可以实现以下功能:

  1. 选择最长的轮廓
  2. 将其分成段并按梯度分组
  3. 对最大的四个组拟合线条
  4. 找到交点

但是,霍夫变换几乎可以完成相同的事情。有没有特别的原因不使用它?

线的交点非常容易计算。一节高中坐标几何课程就可以为您提供算法。


实际上我使用霍夫变换来检测直线(第二个例子)。 - Aray Karjauv
在这种情况下,最好的解决方案是像您在更新的问题中已经做的那样找到交点。在实际情况下,您需要一种选择四条线的最佳候选方法。 - Totoro
1
我只是使用 while 循环,直到我得到了 4 行。这不是最好的解决方案,但可以工作。 - Aray Karjauv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接