12

我有一张像下面这样的图片,我想计算用 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,这并不是那么糟糕,但我需要让它更准确,我想看到两个。我怎样才能做到这一点?在应用高斯滤波器之前模糊图像是否有帮助?

感谢帮助!

罗恩

4

2 回答 2

13

您的高斯滤波已经很好了,但是您正在考虑比任务所需的半径要大。例如,让我们以半径为 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 个对象。

于 2013-01-26T02:00:01.380 回答
3

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

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


一些要研究的资源:

于 2013-01-25T22:20:09.343 回答