【问题标题】:How to Count bugs in an image?如何计算图像中的错误?
【发布时间】:2013-01-25 22:05:11
【问题描述】:

我有一张像下面这样的图片,我想计算一下 Python 上出现的错误(颜色/灰色的连续斑点)的数量。我怎样才能做到最好?

到目前为止,我已经看过 ImageChops、SciPy 和 PIL,但我不确定我可以/应该使用什么...

我想我可以使用ndimage.gaussian_filter(),然后使用scipy.ndimage.measurements.label(),但我还不确定如何使用后者来计算高斯化图像中的蓝点……它看起来像


好的,

有了上面的图片,我现在得到了这个代码:

#! /usr/bin/python

import numpy as np
import scipy
import pylab
import pymorph
import mahotas
from PIL import Image
import PIL.ImageOps
from scipy import ndimage

image = Image.open('bugs.jpg')   
inverted_image = PIL.ImageOps.invert(image)    
inverted_image.save('in_bugs.jpg')
dna = mahotas.imread('in_bugs.jpg')
#pylab.imshow(dna)
pylab.gray()
#pylab.show()
T = mahotas.thresholding.otsu(dna)
pylab.imshow(dna > T)
#pylab.show()
dnaf = ndimage.gaussian_filter(dna, 8)
T = mahotas.thresholding.otsu(dnaf)
pylab.imshow(dnaf > T)
#pylab.show()
labeled,nr_objects = ndimage.label(dnaf > T)
print nr_objects
pylab.imshow(labeled)
pylab.jet()
pylab.show()

问题是,这会返回一个数字 5,这还不错,但我需要让它更准确,我想看到两个。我怎样才能做到这一点?在应用高斯滤镜之前模糊图像是否有帮助?

感谢您的帮助!

罗恩

【问题讨论】:

    标签: python image-processing computer-vision


    【解决方案1】:

    您的高斯过滤已经很好了,但是您正在考虑使用比任务所需更大的半径方式。例如,让我们以半径为 15 的内核为例。这是我们得到的结果:

    有两个清晰的谷(是的,显示为峰值),过滤图像的直方图显示大部分可用数据现在接近可能的最大值。

    仅考虑直方图的一部分,我们可以更好地看到我们感兴趣的数据部分:较暗的点。

    因此,在0.5 处设置一个简单的阈值,这就是结果(与错误所在的位置相匹配):

    根据您实现(或您使用的库实现)相关功能的方式,此阈值会有所不同。但是通过查看直方图,您将能够发现一个好的阈值。现在,如果您不想通过查看直方图来猜测这个阈值,那么您需要在高斯滤波之外对图像进行预处理。通过以良好的方式执行此步骤,您的图像变得足够简单,以至于像 Otsu 给出的方法可以自动找到您所追求的阈值。执行形态闭合,然后执行形态开,然后通过 Otsu 进行二值化,这是我们得到的结果:

    形状更接近最初的形状,因为我们没有依赖线性低通滤波器,它充其量只会模糊轮廓。

    编辑:

    由于问题现在包含一些代码,我觉得有必要解释为什么使用 Otsu 作为代码是错误的。 Otsu 给出的阈值方法实际上期望数据是双峰的,但正如上面的直方图所示,这里的情况并非如此。 Otsu 将提供一个太接近右侧巨大峰值的阈值,而 0.5 的好点则离那里很远。要复制此答案中显示的第一个结果,这里是一些基本代码:

    import sys
    import numpy
    from PIL import Image
    from scipy.ndimage import gaussian_filter, label
    
    img = Image.open(sys.argv[1]).convert('L')
    im = numpy.array(img)
    
    im_g = gaussian_filter(im, 3)
    im_norm = (im_g - im_g.min()) / (float(im_g.max()) - im_g.min())
    im_norm[im_norm < 0.5] = 0
    im_norm[im_norm >= 0.5] = 1
    
    result = 255 - (im_norm * 255).astype(numpy.uint8)
    print u"Objects: %d" % label(result)[1]
    
    Image.fromarray(result).save(sys.argv[2])
    

    请注意,此代码使用 sigma = 3(最初使用 7.5)作为高斯内核,scipy 在内部构建了一个半径比它大 4 倍的窗口。对于这个特定的图像,sigma 的很大范围也可以正常工作,从 2 到 10 应该会给出相同的结果——检测到 2 个对象。

    【讨论】:

    • 伟大的 MMGP,谢谢你,现在你是如何获得内核半径的?我在 scipy.ndimage 中找不到匹配函数。你推荐使用哪个库?谢谢!
    • @cerr 在这个具体示例中,我使用了 Mathematica,它允许指定半径 r,然后假定为 sigma = r / 2(但我也可以指定 sigma)。 scipy 中的 ready 函数只允许您定义 sigma 并且在内部它将构造一个半径为 sigma 4 倍的掩码。因此,要获得半径为 15 的高斯,您需要指定 sigma = 3.5(但我所做的实际上使用了 sigma = 7.5)。对于您的示例,这并不太重要,因为有许多单独的掩码会产生同样好的结果。
    • @cerr 查看更新答案,我现在添加了一些基本代码以使其更清晰。
    【解决方案2】:

    这是一项计算机视觉任务,您可以使用流行的OpenCV 来解决。

    您可能需要考虑使用一些形态学操作(例如opening)来处理图像以去除噪点。也许你可以计算面积超过某个阈值的连续斑点的数量。


    需要研究的一些资源:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-23
      • 2018-06-06
      • 2020-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 2018-05-09
      相关资源
      最近更新 更多