【问题标题】:removing pixels less than n size(noise) in an image - open CV python删除图像中小于 n 大小(噪声)的像素 - 打开 CV python
【发布时间】:2018-02-07 04:12:58
【问题描述】:

我正在尝试减少图像中的噪点,目前正在运行此代码

import numpy as np
import argparse
import cv2
from skimage import morphology

# Construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
    help = "Path to the image")
args = vars(ap.parse_args())

# Load the image, convert it to grayscale, and blur it slightly
image = cv2.imread(args["image"])

cv2.imshow("Image", image)
cv2.imwrite("image.jpg", image)

greenLower = np.array([50, 100, 0], dtype = "uint8")
greenUpper = np.array([120, 255, 120], dtype = "uint8")

green = cv2.inRange(image, greenLower, greenUpper)
#green = cv2.GaussianBlur(green, (3, 3), 0)

cv2.imshow("green", green)
cv2.imwrite("green.jpg", green)

cleaned = morphology.remove_small_objects(green, min_size=64, connectivity=2)

cv2.imshow("cleaned", cleaned)
cv2.imwrite("cleaned.jpg", cleaned)



cv2.waitKey(0)

然而,尽管使用了 remove_small_objects 函数,图像似乎并没有从“绿色”变为“已清理”。为什么会这样,我该如何清理图像?理想情况下,我只想隔离卷心菜的图像。

我的思考过程是在阈值化后去除小于 100 大小的像素,然后用模糊平滑图像并填充被白色包围的黑洞——这就是我在 matlab 中所做的。如果有人可以指导我获得与我的 matlab 实现相同的结果,那将不胜感激。感谢您的帮助。

编辑:更改代码时犯了一些错误,更新到现在的样子并显示 3 张图片

图片:

绿色:

干净:

我的目标是从 matlab 实现中得到如下图所示的内容:

【问题讨论】:

  • 你没有显示“清理”的图像。
  • 是的,抱歉,我在发布之前更改了代码。我把它编辑成我测试时的样子
  • 只是作为一个建议:检测边缘并按照您想要的方式继续前进。在我的观察中,这很容易,因为目标与周围的色差非常好。

标签: python image opencv


【解决方案1】:

虽然,上面的问题是用cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)解决的。但是,如果有人想使用 morphology.remove_small_objects 删除小于指定大小的区域,那么这个答案可能会有所帮助。

我用来去除上图噪声的代码是:

import numpy as np
import cv2
from skimage import morphology
# Load the image, convert it to grayscale, and blur it slightly
image = cv2.imread('im.jpg')
cv2.imshow("Image", image)
#cv2.imwrite("image.jpg", image)
greenLower = np.array([50, 100, 0], dtype = "uint8")
greenUpper = np.array([120, 255, 120], dtype = "uint8")
green = cv2.inRange(image, greenLower, greenUpper)
#green = cv2.GaussianBlur(green, (3, 3), 0)
cv2.imshow("green", green)
cv2.imwrite("green.jpg", green)
imglab = morphology.label(green) # create labels in segmented image
cleaned = morphology.remove_small_objects(imglab, min_size=64, connectivity=2)

img3 = np.zeros((cleaned.shape)) # create array of size cleaned
img3[cleaned > 0] = 255 
img3= np.uint8(img3)
cv2.imshow("cleaned", img3)
cv2.imwrite("cleaned.jpg", img3)
cv2.waitKey(0)

清理后的图像如下所示:

要使用morphology.remove_small_objects,首先标记 blob 是必不可少的。为此,我使用imglab = morphology.label(green)。标记是这样完成的,第一个 blob 的所有像素编号为 1。类似地,第 7 个 blob 的所有像素编号为 7,依此类推。因此,在移除小区域后,剩余 blob 的像素值应设置为 255,以便cv2.imshow() 可以显示这些 blob。为此,我创建了一个与已清理图像大小相同的数组img3。我使用img3[cleaned > 0] = 255线将所有值大于0的像素转换为255。

【讨论】:

  • 很好的补充,展示了如何在 OP 最初使用的库中完成它。同样对于内联代码,您可以在代码周围使用反引号,例如 `variable` 来生成 variable
【解决方案2】:

预处理

过滤图像时的一个好主意是低通图像或稍微模糊一下;这样一来,相邻像素的颜色就会变得更加均匀,因此可以缓解图像上较亮和较暗的点,并避免蒙版出现孔洞。

img = cv2.imread('image.jpg')
blur = cv2.GaussianBlur(img, (15, 15), 2)
lower_green = np.array([50, 100, 0])
upper_green = np.array([120, 255, 120])
mask = cv2.inRange(blur, lower_green, upper_green)
masked_img = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('', masked_img)
cv2.waitKey()

色彩空间

目前,您正试图通过一系列具有不同亮度的颜色来包含图像——您需要绿色像素,无论它们是暗还是亮。这在 HSV 颜色空间中更容易实现。查看我的回答 here 深入了解 HSV 颜色空间。

img = cv2.imread('image.jpg')
blur = cv2.GaussianBlur(img, (15, 15), 2)
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
lower_green = np.array([37, 0, 0])
upper_green = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
masked_img = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('', masked_img)
cv2.waitKey()

去除二值图像/掩码中的噪声

ngalstyan 提供的answer 展示了如何用形态学很好地做到这一点。你想要做的叫做opening,它是侵蚀(或多或少只是删除一定半径内的所有东西)然后膨胀(它会添加回任何剩余的对象,无论多少是删除)。在 OpenCV 中,这是通过 cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) 完成的。该页面上的教程显示了它是如何工作的。

img = cv2.imread('image.jpg')
blur = cv2.GaussianBlur(img, (15, 15), 2)
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
lower_green = np.array([37, 0, 0])
upper_green = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
opened_mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
masked_img = cv2.bitwise_and(img, img, mask=opened_mask)
cv2.imshow('', masked_img)
cv2.waitKey()

填补空白

在上面,打开显示为从二进制掩码中删除少量白色的方法。 关闭是相反的操作——从你的图像中去除被白色包围的黑色块。您可以使用与上述相同的想法来执行此操作,但使用cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)。在您的情况下,在上述情况之后甚至没有必要这样做,因为面罩没有任何孔。但如果是这样,您可以通过关闭来关闭它们。你会注意到我的打开步骤实际上移除了底部的一小部分植物。实际上,您可以先关闭 来填补这些空白,然后再打开以删除其他地方的虚假位,但这张图片可能没有必要。

尝试新的阈值值

您可能希望更轻松地使用不同的色彩空间和阈值级别,以了解最适合特定图像的方法。它还没有完成,界面有点不稳定,但我有一个工具,你可以在线使用它来尝试不同色彩空间中的不同阈值;如果您愿意,请查看here。这就是我快速为您的图片找到价值的方法。

【讨论】:

  • 太棒了!!!!在对验证码图像中的像素进行 48 小时操作后,你救了我的命……这是唯一对我来说很有吸引力的 cv2 代码。谢谢
【解决方案3】:

看来您要删除的是一组不连贯的小斑点。 我认为 erode() 会用正确的内核很好地删除它们。

给定一个 nxn 内核,erode 在图像中移动内核,并用内核中的最小像素替换中心像素。 然后你可以dilate()得到的图像来恢复绿色部分被侵蚀的边缘。

另一种选择是使用fastndenoising

#####  option 1
kernel_size = (5,5) # should roughly have the size of the elements you want to remove
kernel_el = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
eroded =   cv2.erode(green, kernel_el, (-1, -1))
cleaned = cv2.dilate(eroded, kernel_el, (-1, -1))

##### option 2
cleaned = cv2.fastNlMeansDenoisingColored(green, h=10)

【讨论】:

  • 应该注意,如果你想erode 然后dilate,你应该使用一个奇数大小的内核(就像你正在使用的那样),否则如果它是偶数,你最终会转移区域向下和向右。这个先腐蚀再膨胀的过程叫做opening,你可以直接用cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel).
猜你喜欢
  • 2015-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 2021-08-02
  • 1970-01-01
相关资源
最近更新 更多