改进 Canny 边缘检测和轮廓图像分割

信息处理 图像处理 图像分割
2022-01-26 18:35:08

我正在做一个图像分割项目,以识别不同背景的扑克牌。对于我的用例,我最关心的是我准确地提取了图像中的所有卡片;误报是不方便的,但不是致命的。我还关心我可以在没有用户交互的情况下运行分割(即,像 GrabCut 这样的算法对我不起作用)。

到目前为止,我有以下基于 Canny 边缘检测和轮廓选择的简单算法:

# Pre-processing: Convert frame to standard size, 1024x768
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 9)
edges = cv2.Canny(gray, 10, 25)
_, contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
    rect = cv2.minAreaRect(c)
    box = cv2.boxPoints(rect)
    area = cv2.contourArea(box)
    ratio = area / size
    if ratio < 0.015: # Any contour large enough is a candidate
        continue
    # Mark this box as possible card

对于一些(许多)输入,它工作得很好,甚至非常好:

好例子

然而,对于其他输入,轮廓检测无法成功消除卡片的歧义。轮廓以链接卡片或导致不需要的边界框的方式分组:

不好的例子

作为记录,以下是我考虑过的其他一些事情:

  • 使用双边滤波器而不是中值模糊。可能会稍微改善结果,例如,在上面的第一列第三行卡的坏示例中,现在已正确分段。
  • 使用直方图均衡来增强对比度。通常会遮挡一些必要的边缘。
  • 尝试根据中值自动确定每个图像的 Canny 阈值。通常,这种方法忽略了我们需要考虑的许多嘈杂的卡片边缘。

    def auto_canny(图像,sigma=0.5):
        v = np.中位数(图像)
        较低 = int(max(0, (1.0 - sigma) * v))
        上 = int(min(255, (1.0 + sigma) * v))
        返回 cv2.Canny(图像,下,上)

  • 尝试使用分水岭分割。基本问题是自动确定初始分割标记,这大致相当于首先识别卡片。找到“白色”特别困难,因为它的颜色随环境照明条件而变化。

  • 尝试使用均值偏移过滤/分割。我预计它可能会通过简化图像结构来降噪边缘检测过程,但它似乎具有更多的“模糊”效果,尤其是在反射周围。

作为参考(或者,更好的是,如果你想在家一起玩)我有一组示例输入和我当前算法的输出:专辑

1个回答

您可以在您的精明检测而不是轮廓检测之后尝试霍夫变换。(假设您没有太多的透视失真,即卡片是矩形而不是梯形)。

看看这个相关的问题和其中的链接。