如何去除二进制图像中的噪声?

5

这是我的代码,我试图从二进制图像中删除掩模(噪声)。但我得到的结果是在噪声周围留下了白线。我知道这个噪声周围有一个轮廓,导致最终结果中出现了白色线条。需要帮助吗?

原始图像

Original Image

掩模和结果

Mask and results

代码

import numpy as np
import cv2
from skimage import util

img = cv2.imread('11_otsu.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#cv2.drawContours(img, contours, -1, (0,255,0), 2)

# create an empty mask
mask = np.zeros(img.shape[:2], dtype=np.uint8)

# loop through the contours
for i, cnt in enumerate(contours):
    # if the contour has no other contours inside of it
    if hierarchy[0][i][2] == -1:
        # if the size of the contour is greater than a threshold
        if cv2.contourArea(cnt) <70:
            cv2.drawContours(mask, [cnt], 0, (255), -1)
            # display result

cv2.imshow("Mask", mask)

cv2.imshow("Img", img)
image = cv2.bitwise_not(img, img, mask=mask)
cv2.imshow("Mask", mask)
cv2.imshow("After", image)

cv2.waitKey()
cv2.destroyAllWindows()


只需在命令中添加形态学,即可填补白色区域内的黑洞。然后获取外部轮廓。请参见https://docs.opencv.org/4.1.1/d4/d86/group__imgproc__filter.html#ga67493776e3ad1a3df63883829375201f - fmw42
3个回答

4

建议使用 cv2.floodFill 替代查找内部轮廓并填充的方法。洪水填充操作通常用于填充封闭对象内部的空洞。具体来说,如果将种子像素设置为图像左上角,然后对图像进行洪水填充,则会填充背景而保留封闭对象。如果反转此图像,您将找到具有“孔”的封闭对象内部的所有像素。如果使用这个反转的图像并直接将非零位置设置为原始图像,那么就可以填补孔洞。

因此:

im = cv2.imread('8AdUp.png', 0)
h, w = im.shape[:2]
mask = np.zeros((h+2, w+2), dtype=np.uint8)
holes = cv2.floodFill(im.copy(), mask, (0, 0), 255)[1]
holes = ~holes
im[holes == 255] = 255
cv2.imshow('Holes Filled', im)
cv2.waitKey(0)
cv2.destroyAllWindows()

首先,我们读取你提供的阈值化图像,在进行“噪声过滤”之前,获取其高度和宽度。我们还使用输入掩码来告诉我们要操作洪水填充的像素。使用全零掩码意味着您将在整个图像上操作。还要注意,使用掩码之前,掩码需要具有1像素的边框。我们使用左上角作为初始点进行洪水填充,反转它,将任何“空洞”像素设置为255并显示它。请注意,一旦方法完成,输入图像会发生变化,因此您需要传入一个副本以保留输入图像不变。此外,cv2.floodFill (使用OpenCV 4)返回包含四个元素的元组。我让您查看文档,但您需要这个元组的第二个元素,即填充的图像。
因此,我们得到以下结果:

enter image description here


1
你的解决方案是有效的,但缺少一个非常重要的细节 - 噪声的大小。在某些情况下,可能会出现一些细菌(我假设这些是细菌图像,但我可能错了)具有孔洞更大的形态,但并不是噪声的一部分。因此,应该对孔洞进行大小过滤以在一定程度上减轻这个问题。 - Knight Forked
1
@KnightForked 谢谢。以前没有处理过这些图像,也没有注意到这一点。 - rayryeng
1
感谢您的回答,正如@KnightForked所提到的,我的问题有些微妙。我肯定会在需要时使用您的答案。 - Vincent Liow

3

您的代码完全没问题,只需进行以下调整即可使其正常工作:

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) # Use cv2.CCOMP for two level hierarchy
if hierarchy[0][i][3] != -1: # basically look for holes
    # if the size of the contour is less than a threshold (noise)
    if cv2.contourArea(cnt) < 70:
        # Fill the holes in the original image
        cv2.drawContours(img, [cnt], 0, (255), -1)

完美地运作,正是我所需要的。你很敏锐,我需要填充噪点而不是谷之间的空隙。我调整了代码cv2.drawContours(img, [cnt], 0, (255,255,255), -1),因为你的代码会以蓝色(0,0,255)填充它,原因不明。 - Vincent Liow

0

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