【问题标题】:How to remove noise in binary image? [duplicate]如何去除二值图像中的噪声?
【发布时间】:2021-02-28 10:13:11
【问题描述】:

这是我的代码,我正在尝试从二进制图像中删除掩码(噪声)。我得到的是噪音周围留下的白线。我知道该噪声周围有一个轮廓,会在结果中产生最终的白线。有什么帮助吗?

原图

面具和结果

代码

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()

【问题讨论】:

标签: python python-3.x opencv image-processing cv2


【解决方案1】:

您的代码非常好,只需进行这些调整,它应该可以工作:

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)。
  • @VincentLiow,为此道歉,我刚刚从您的代码中复制了那篇文章。它只需要 255 而不是 (255) 就可以了。如果您认为它回答了您的问题,请考虑接受和投票,以便其他人可以找到它。 :)
【解决方案2】:

我可以建议使用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)返回四个元素的元组。我会让你看一下文档,但你需要这个元组的第二个元素,即填充的图像。

因此我们得到:

【讨论】:

  • 您的解决方案有效,但忽略了一个非常重要的细微之处 - 噪音的大小。在某些情况下,可能会发生这样的情况,其中一些细菌(我假设这些是细菌图像,但我可能错了)可能会形成孔较大但不属于噪声的结构。因此,应该以某种方式对孔进行尺寸过滤以在一定程度上缓解该问题。
  • @KnightForked 谢谢。之前没有处理过这些图片,也没有注意到这一点。
  • 欣赏答案,正如@KnightForked 提到的,我的问题有一个微妙之处。我一定会在需要时在某个地方使用您的答案。
【解决方案3】:

我认为使用cv2.GaussianBlur() 方法可能会对您有所帮助。将图像转换为灰度后,使用此方法对其进行模糊处理(顾名思义,这是一个高斯滤镜)。这是文档: https://docs.opencv.org/4.3.0/d4/d86/group__imgproc__filter.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    相关资源
    最近更新 更多