如何使用OpenCV去除小的连通对象

21

我使用OpenCV和Python,并希望从图像中删除小的连通对象。

我有以下二进制图像作为输入:

Input binary image

该图像是以下代码的结果:

dilation = cv2.dilate(dst,kernel,iterations = 2)
erosion = cv2.erode(dilation,kernel,iterations = 3)

我想要移除红色高亮的物体:

图片描述

如何使用OpenCV实现这个功能?


7
你是指在确定要突出哪些物体时使用了什么标准?为什么选择那七个特定的物体,而不是类似大小或更小的其他物体? - Dan Mašek
1
我想要移除所有小的对象,这个7只是一个我想要移除的对象的示例。 - Zahra
1
@DanMašek 我想使用物体表面作为一个标准。 - Zahra
1
@DanMašek 我知道这种方法,但我需要使用一种不需要轮廓的方法 :( - Zahra
1
@Zahra那么为什么你在问题中没有提到这个事实(并指明这个要求)呢? - Dan Mašek
显示剩余3条评论
4个回答

58

使用 connectedComponentsWithStats (文档) 怎么样?

# find all of the connected components (white blobs in your image).
# im_with_separated_blobs is an image where each detected blob has a different pixel value ranging from 1 to nb_blobs - 1.
nb_blobs, im_with_separated_blobs, stats, _ = cv2.connectedComponentsWithStats(im)
# stats (and the silenced output centroids) gives some information about the blobs. See the docs for more information. 
# here, we're interested only in the size of the blobs, contained in the last column of stats.
sizes = stats[:, -1]
# the following lines result in taking out the background which is also considered a component, which I find for most applications to not be the expected output.
# you may also keep the results as they are by commenting out the following lines. You'll have to update the ranges in the for loop below. 
sizes = sizes[1:]
nb_blobs -= 1

# minimum size of particles we want to keep (number of pixels).
# here, it's a fixed value, but you can set it as you want, eg the mean of the sizes or whatever.
min_size = 150  

# output image with only the kept components
im_result = np.zeros_like(im_with_separated_blobs)
# for every component in the image, keep it only if it's above min_size
for blob in range(nb_blobs):
    if sizes[blob] >= min_size:
        # see description of im_with_separated_blobs above
        im_result[im_with_separated_blobs == blob + 1] = 255

输出:在此输入图片描述


2
@sotius 谢谢...我尝试了你的解决方案,但是它给了我一个错误:Build\OpenCV\opencv-3.2.0\modules\imgproc\src\connectedcomponents.cpp:1664: error: (-215) iDepth == CV_8U || iDepth == CV_8S in function cv::connectedComponents_sub1 - Zahra
3
@Zahra ,该函数的输入图像需要是8位。使用“img=img.astype(numpy.uint8)”进行转换。 - Soltius
2
请注意,行im_result = np.zeros(im.shape)总是创建一个dtype为float64的数组,而不是适应输入图像的dtype。在更复杂的图像处理链中更改图像数组的dtype可能会导致意外错误,因此我建议将该行更改为im_result = np.zeros_like(im) - Thomas Fritz
1
@ThomasFritz 你说得对,我已经编辑了代码以考虑到这一点。 - Soltius

1
为了自动删除对象,您需要在图像中定位它们。 从您提供的图像中,我看不出有什么区别7个突出显示的项目与其他项目。 您必须告诉计算机如何识别您不想要的对象。如果它们看起来相同,则无法实现。 如果您有多个图像,其中对象始终看起来像那样,您可以使用模板匹配技术。 此外,闭合操作对我来说没有太多意义。

0

通过面积来移除小的连通组件被称为面积开放。OpenCV没有这个功能,但可以根据其他答案中所示进行实现。但大多数其他图像处理软件包都会有面积开放函数。

例如使用scikit-image

import skimage
import imageio.v3 as iio

img = iio.imread('cQMZm.png')[:,:,0]

out = skimage.morphology.area_opening(img, area_threshold=150, connectivity=2)

例如使用DIPlib
import diplib as dip

out = dip.AreaOpening(img, filterSize=150, connectivity=2)

PS:DIPlib 的实现明显更快。免责声明:我是 DIPlib 的作者。


0
#对于孤立的或不相连的斑点:尝试这个(你可以将noise_removal_threshold设置为任何你喜欢的值,例如相对于最大轮廓的值或一个名义值,如100或25)。
    mask = np.zeros_like(img)
    for contour in contours:
      area = cv2.contourArea(contour)
      if area > noise_removal_threshold:
        cv2.fillPoly(mask, [contour], 255)

轮廓,层次结构 = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) - Priyank Pathak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接