简体   繁体   English

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

[英]How to remove noise in binary image?

This is my code, I am trying to delete the mask (noise) from the binary image.这是我的代码,我试图从二进制图像中删除掩码(噪声)。 What I am getting is white lines left around the noise.我得到的是噪音周围留下的白线。 I am aware that there is a contour around that noise creating the final white line in the results.我知道在噪声周围有一个轮廓,在结果中产生了最终的白线。 any help?有什么帮助吗?

Original Image原图

原图

Mask and results掩码和结果

掩码和结果

Code代码

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

Instead of trying to find inner contours and filling those in, may I suggest using cv2.floodFill instead?我可以建议使用cv2.floodFill代替尝试找到内部轮廓并填充它们吗? The flood fill operation is commonly used to fill in holes inside closed objects.泛洪填充操作通常用于填充封闭对象内的孔。 Specifically, if you set the seed pixel to be the top left corner of the image then flood fill the image, what will get filled is the background while closed objects are left alone.具体来说,如果您将种子像素设置为图像的左上角,然后填充图像,则会填充背景,而将关闭的对象单独放置。 If you invert this image, you will find all of the pixels that are interior to the closed objects that have "holes".如果您反转此图像,您将找到具有“孔”的封闭对象内部的所有像素。 If you take this inverted image and use the non-zero locations to directly set the original image, you will thus fill in the holes.如果你拍摄这个倒置图像并使用非零位置直接设置原始图像,你将因此填补空洞。

Therefore:所以:

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

First we read in the image that you've provided which is thresholded and before the "noise filtering", then get the height and width of it.首先,我们读入您提供的经过阈值处理且在“噪声过滤”之前的图像,然后获取其高度和宽度。 We also use an input mask to tell us which pixels to operate on the flood fill.我们还使用输入掩码来告诉我们哪些像素要对洪水填充进行操作。 Using a mask of all zeroes means you will operate on the entire image.使用全零掩码意味着您将对整个图像进行操作。 It's also important to note that the mask needs to have a 1 pixel border surrounding it before using it.同样重要的是要注意,遮罩在使用之前需要有一个 1 像素的边框围绕它。 We flood fill the image using the top left corner as the initial point, invert it, set any "hole" pixels to 255 and show it.我们使用左上角作为初始点填充图像,反转它,将任何“孔”像素设置为 255 并显示它。 Take note that the input image is mutated once the method finishes so you need to pass in a copy to leave the input image untouched.请注意,一旦方法完成,输入图像就会发生变化,因此您需要传入一个副本以保持输入图像不变。 Also, cv2.floodFill (using OpenCV 4) returns a tuple of four elements.此外, cv2.floodFill (使用 OpenCV 4)返回四个元素的元组。 I'll let you look at the documentation but you need the second element of this tuple, which is the filled in image.我会让您查看文档,但您需要此元组的第二个元素,即填充图像。

We thus get:我们因此得到:

在此处输入图片说明

Your code is perfectly fine just make these adjustments and it should work:您的代码非常好,只需进行这些调整,它应该可以工作:

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)

I think using cv2.GaussianBlur() method might help you.我认为使用cv2.GaussianBlur()方法可能会对您有所帮助。 After you convert the image to gray-scale, blur it using this method (as the name suggests, this is a Gaussian filter).将图像转换为灰度后,使用此方法对其进行模糊处理(顾名思义,这是一个高斯滤波器)。 Here is the documentation: https://docs.opencv.org/4.3.0/d4/d86/group__imgproc__filter.html这是文档: https : //docs.opencv.org/4.3.0/d4/d86/group__imgproc__filter.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM