检测具有模糊边缘和不同背景的卡片边缘

Ale*_*oft 3 python opencv computer-vision

这是我的测试照片

在此输入图像描述

我正在尝试找到卡片的边缘。然而,正如您所看到的,边缘有些模糊。

为了找到边缘,我首先增强图像的对比度,因此希望模糊的边缘不会那么模糊并且更容易找到: 在此输入图像描述 然后我使用高斯模糊对其进行平滑处理(我尝试消除高斯模糊,但边缘检测器在背景+卡片中发现了许多细节)。

然后我使用带有“动态阈值”的 canny 并得到以下结果: 在此输入图像描述 正如你所看到的,我大麦找到了卡片的任何边缘(除了左边的边缘,因为黑色背景,这很容易)。是否有一种强大的(我不想在该图像上“过度拟合”)方法来找到直线模糊边缘?

在这里找到了一些建议: 模糊边缘检测 如何从 python 中的模糊图像中找到扭曲矩形的准确角位置?,但都没有产生令人满意的边缘。

完整代码:

def auto_canny(image, sigma=0.5):
    v = np.median(image)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    return cv2.Canny(image, lower, upper)

def add_contrast(img, contrast_level=8):
    lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

    l, a, b = cv2.split(lab)

    clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(contrast_level, contrast_level))
    cl = clahe.apply(l)

    limg = cv2.merge((cl, a, b))

    final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)

    return final

# ------------------------------------------ #
# FIND EDGES
# ------------------------------------------ #
img = add_contrast(img=img, contrast_level=8)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)

kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)

edges = auto_canny(image=blur_gray) 

# Show images for testing
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)

ilk*_*444 5

这也不是一个完整的解决方案,但如果红色部分有问题,您可以先使用cv2.inpaint()函数修复这些部分。然后您可以应用其余的方法来找到卡片边缘。

# create an inpainting mask with "red-enough" pixels
mask = cv2.inRange(img_src_rgb, np.array([200,0,0]), np.array([255,50,50]))
# enlarge the mask to cover the borders
kernel = np.ones((3,3),np.uint8)
mask = cv2.dilate(mask,kernel,iterations = 1)
# inpaint the red parts using Navier-Stokes based approach
img_dst = cv2.inpaint(img_src, mask,50,cv2.INPAINT_NS)
cv2.imshow("no_red", img_dst)
Run Code Online (Sandbox Code Playgroud)

结果图像如下。

在此输入图像描述

编辑:现在我们知道您在问什么,下面是一个完整的解决方案。

修复后,您可以应用霍夫变换来查找图像中的强直线。

gray = cv2.cvtColor(img_dst, cv2.COLOR_RGB2GRAY)
edges = auto_canny(gray) # your auto_canny function, WITHOUT blur
lines = cv2.HoughLines(edges, 1, np.pi/90, 50)
for line in lines:
    rho,theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 10000*(-b))
    y1 = int(y0 + 10000*(a))
    x2 = int(x0 - 10000*(-b))
    y2 = int(y0 - 10000*(a))
    cv2.line(img_dst,(x1,y1),(x2,y2),(0,255,0),1)

cv2.imwrite('linesDetected.jpg', img_dst)
Run Code Online (Sandbox Code Playgroud)

同样,结果行如下所示。

在此输入图像描述

  • 在您的示例中,模糊边缘主要是红色区域边界,因此我建议将此解决方案作为预处理步骤。您应该通过提及红色部分不在原始图像中来纠正您的问题,并根据原始图像生成示例输出,以便我们可以提供帮助。 (2认同)
  • @AlexGoft,请参阅上面的完整答案。 (2认同)
  • 您实际上需要边缘和角落,高斯模糊会平滑它们,因此您也会丢失卡片边缘。如果您想要一些边缘感知平滑,您可以尝试双边过滤。此外,增加对比度会引入新的边缘,这些新的边缘对噪声的贡献大于对您所寻找的边缘的贡献。对于这种情况,您应该利用数据中的假设:卡片边缘是直线。 (2认同)