我正在寻找一种使用OpenCV从二进制图像中删除孤立白色像素的方法。一个类似的问题(OpenCV get rid of isolated pixels)有一堆“答案”,但似乎没有一个对我有用。我已经尝试过各种开合方式,但也没有成功。
这篇文章:
https://homepages.inf.ed.ac.uk/rbf/HIPR2/hitmiss.htm
建议我可以使用命中或未命中操作来实现此目的:
1 用于定位二进制图像中的孤立点
原因是0s的解释与直接使用侵蚀/扩张时的解释不同(其中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)
删除像这样的孤立像素的正确方法是什么?
更新:亚历山大的答案就像一个魅力,是最快的解决方案。另一个答案也提供了一个解决方案,即使用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
答案 0 :(得分:4)
我相信OpenCV的实施已被打破。有一个相关的issue on OpenCV's GitHub似乎合并了一个拉取请求来修复;我认为它被添加到pull request中引用的OpenCV 3.3-rc中,所以希望下次更新OpenCV时应该修复它。我不确定问题是否是由同一件事引起的。
所选答案中的创意解决方案非常棒,但我同意您的观点:必须有更好的方式,尽管实施方法有所不足。
在他们所说的OpenCV Hit-or-miss tutorial上:
因此,命中或未命中操作包括三个步骤:
- 使用结构元素 B1 侵蚀图像 A 。
- 使用结构元素 B2 侵蚀图像 A ( A_c )的补充。
- 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()
然后删除,就像反转hitormiss
一样简单,并将其mask
与cv2.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()
注意:正如评论中所讨论的,在这种特定情况下kernel1
的侵蚀与输入二进制图像相同,因此不需要进行此计算,这也引入了一些其他不必要的步骤。具体案例。但是,你可能有不同的内核,而不是中间的一个1,所以我将保持代码原样,以保持它对任何内核的通用。
答案 1 :(得分:2)