使用OpenCV删除孤立的像素

Tom*_*Tom 3 python opencv computer-vision

我正在寻找一种使用OpenCV从二进制图像中删除孤立的白色像素的方法。一个类似的问题(OpenCV摆脱了孤立的像素)也有很多“答案”,但似乎没有一个对我有用。我也尝试过打开和关闭的各种组合,但都没有成功。

这里的文章:

https://homepages.inf.ed.ac.uk/rbf/HIPR2/hitmiss.htm

建议我可以完全出于此目的使用“命中或失败”操作:

结构元素

1用于定位二进制图像中的孤立点

这就是为什么0的解释与直接与侵蚀/膨胀配合使用时的解释不同(其中0解释为“不在乎”而不是“不是白色”,这基本上就是我所追求的)。但是,使用此内核仅渲染原始图像。

我的输入图像是这样的:

计算输入图像

您会注意到,在图像的左侧附近有一些白色像素,我想将其消除。

这是代码:

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

hitormiss = cv2.morphologyEx(input_image, cv2.MORPH_HITMISS, kernel)

cv2.imshow('hitormiss', hitormiss)
Run Code Online (Sandbox Code Playgroud)

删除像这样的孤立像素的正确方法是什么?

更新:亚历山大的答案就像一个魅力,是最快的解决方案。另一个答案也提供了一个解决方案,即使用cv2.connectedComponents函数,但是它占用大量处理器资源。这是使用此方法的函数:

def remove_isolated_pixels(self, image):
    connectivity = 8

    output = cv2.connectedComponentsWithStats(image, connectivity, cv2.CV_32S)

    num_stats = output[0]
    labels = output[1]
    stats = output[2]

    new_image = image.copy()

    for label in range(num_stats):
        if stats[label,cv2.CC_STAT_AREA] == 1:
            new_image[labels == label] = 0

    return new_image
Run Code Online (Sandbox Code Playgroud)

alk*_*asm 6

我相信OpenCV的实现已被破坏。OpenCV的GitHub上存在一个相关问题,该问题似乎合并了一个pull请求进行修复;我认为它已作为pull请求中的参考添加到OpenCV 3.3-rc中,因此希望在下次更新OpenCV时可以解决。我不确定问题是否是由同一件事引起的。

所选答案中的创造性解决方案很棒,但我同意您的意见:尽管实施失败,但必须有更好的方法

OpenCV命中或失败教程中,他们指出:

因此,命中或失败操作包括三个步骤:

  1. 侵蚀图像与结构元素B1
  2. 用结构元素B2 腐蚀图像AA_c)的补数。
  3. AND是步骤1和步骤2的结果。

然后继续说,这可以通过“命中或失败”转换中的单个内核来完成,但是众所周知,它是坏的。因此,让我们执行这些步骤。

import cv2
import numpy as np

# load image, ensure binary, remove bar on the left
input_image = cv2.imread('calc.png', 0)
input_image = cv2.threshold(input_image, 254, 255, cv2.THRESH_BINARY)[1]
input_image_comp = cv2.bitwise_not(input_image)  # could just use 255-img

kernel1 = np.array([[0, 0, 0],
                    [0, 1, 0],
                    [0, 0, 0]], np.uint8)
kernel2 = np.array([[1, 1, 1],
                    [1, 0, 1],
                    [1, 1, 1]], np.uint8)

hitormiss1 = cv2.morphologyEx(input_image, cv2.MORPH_ERODE, kernel1)
hitormiss2 = cv2.morphologyEx(input_image_comp, cv2.MORPH_ERODE, kernel2)
hitormiss = cv2.bitwise_and(hitormiss1, hitormiss2)

cv2.imshow('isolated.png', hitormiss)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)

孤立像素

然后去掉,它的那样简单颠倒hitormiss,并将它作为一个maskcv2.bitwise_and()input_image

hitormiss_comp = cv2.bitwise_not(hitormiss)  # could just use 255-img
del_isolated = cv2.bitwise_and(input_image, input_image, mask=hitormiss_comp)
cv2.imshow('removed.png', del_isolated)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)

删除了孤立的像素


注意:如评论中所述,kernel1在这种特定情况下的腐蚀与输入二进制图像相同,因此无需进行此计算,并且在此特定情况下也引入了一些其他不必要的步骤。但是,您可能有不同的内核,而中间没有一个内核,因此我将按原样保留代码,以使其对所有内核通用。