【问题标题】:OpenCV - how to pass a pattern-matching kernel over binary image?OpenCV - 如何通过二进制图像传递模式匹配内核?
【发布时间】:2021-01-18 12:34:19
【问题描述】:

我正在为二进制图像中的像素宽轮廓实现轮廓查找算法。它需要对删除单个像素(即像素宽的间隙)具有鲁棒性。

对膨胀和腐蚀内核的各种尝试都没有产生可靠的解决方案。

相反,我想要实现的可靠解决方案是在图像上传递一个模式匹配内核,它可以直接根据周围像素填充间隙。例如,当在某个位置观察到左侧的确切模式时,将其替换为右侧(其中 * 表示通配符):

[1 * *]          [1 * *]
[* 0 *]   ==>    [* 1 *]
[* * 1]          [* * 1]

[1 0 *]          [1 0 *]
[* 0 1]   ==>    [* 1 1]
[* * *]          [* * *]

[* 1 *]          [* 1 *]
[* 0 *]   ==>    [* 1 *]
[* 1 *]          [* 1 *]

并定义大约 14 个替换项以填补每个 3x3 窗口中可能存在的空白。

它可以在原始 Python 中实现,但如果没有低级矢量化操作,它可能会非常慢。

这可以通过 OpenCV 或其他一些快速操作来完成吗?

【问题讨论】:

  • 您可以轻松完成每个操作filter2d()。真正的问题是是否可以组合各个过滤器以减少操作次数。
  • @beaker filter2d 应用卷积,但我不确定这是否合适?需要忽略通配符。例如第一个等价于逻辑语句“如果p11 = 1 and p22 = 0 and p33 = 1, then modify p22 := 1”
  • 实际上我得到了这个与精心设计的内核一起工作 - 谢谢你的想法。

标签: opencv image-processing opencv-python opencv-contour


【解决方案1】:

感谢上面的@beaker 评论,我实现了一个解决方案。设计一个内核,其中感兴趣的相邻像素为 0.5,中心为 1,如果缺少,它将用 1 填充中心,尽管其他一些像素将为 2。然后将值剪裁为 1,您将获得所需的结果.

它需要独立应用于每个方向的间隙,虽然不理想但仍然有效。

img_with_gap = np.array(
           [[1,0,0,0,0],
            [0,1,0,0,0],
            [0,0,0,0,0],
            [0,0,0,1,0],
            [0,0,0,0,1]], dtype=np.uint8)


kernel = np.array(
              [[0.5,  0,   0],
               [0  ,  1,   0],
               [0  ,  0, 0.5]])


connected_img = np.minimum(cv2.filter2D(img_with_gap, -1, kernel), 1)
connected_img

更严格的实现是通过惩罚零个、剪切到 {0,1} 并确保没有从原始图像中删除任何内容来进行精确的模式匹配:

kernel = np.array([[0.5,  -10.0,   -10.0],
                   [-10.0  ,  1,   -10.0],
                   [-10.0  ,  -10.0, 0.5]])

connected_img = np.maximum(img, np.clip(cv2.filter2D(img, -1, kernel), 0, 1))

【讨论】:

    猜你喜欢
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 2013-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多