在变化的背景强度下检测粒子是否有任何好的算法? 例如,如果我有以下图像:
有没有办法计算小的白色颗粒,即使左下方出现明显不同的背景?
为了更清楚一点,我想标记图像并使用一种算法来计算粒子,这些算法可以发现这些粒子很重要:
我使用PIL
,cv
,scipy
,numpy
等模块尝试了很多内容。
我从this very similar SO question得到了一些提示,乍看之下你可以采取一个简单的阈值:
im = mahotas.imread('particles.jpg')
T = mahotas.thresholding.otsu(im)
labeled, nr_objects = ndimage.label(im>T)
print nr_objects
pylab.imshow(labeled)
但是由于背景的变化你得到了这个:
我还尝试了其他一些想法,比如a technique I found for measuring paws,我用这种方式实现了这个想法:
import numpy as np
import scipy
import pylab
import pymorph
import mahotas
from scipy import ndimage
import cv
def detect_peaks(image):
"""
Takes an image and detect the peaks usingthe local maximum filter.
Returns a boolean mask of the peaks (i.e. 1 when
the pixel's value is the neighborhood maximum, 0 otherwise)
"""
# define an 8-connected neighborhood
neighborhood = ndimage.morphology.generate_binary_structure(2,2)
#apply the local maximum filter; all pixel of maximal value
#in their neighborhood are set to 1
local_max = ndimage.filters.maximum_filter(image, footprint=neighborhood)==image
#local_max is a mask that contains the peaks we are
#looking for, but also the background.
#In order to isolate the peaks we must remove the background from the mask.
#we create the mask of the background
background = (image==0)
#a little technicality: we must erode the background in order to
#successfully subtract it form local_max, otherwise a line will
#appear along the background border (artifact of the local maximum filter)
eroded_background = ndimage.morphology.binary_erosion(background, structure=neighborhood, border_value=1)
#we obtain the final mask, containing only peaks,
#by removing the background from the local_max mask
detected_peaks = local_max - eroded_background
return detected_peaks
im = mahotas.imread('particles.jpg')
imf = ndimage.gaussian_filter(im, 3)
#rmax = pymorph.regmax(imf)
detected_peaks = detect_peaks(imf)
pylab.imshow(pymorph.overlay(im, detected_peaks))
pylab.show()
但这也没有运气,显示了这个结果:
使用区域最大函数,我得到的图像几乎可以给出正确的粒子识别,但根据我的高斯滤波,图像中有太多或太少的粒子在错误的位置(图像的高斯滤波器为2, 3,& 4):
此外,它还需要处理与此类似的图像:
这是上面相同类型的图像,只是粒子密度高得多。
编辑:已解决的解决方案: 我能够使用以下代码为此问题找到一个不错的解决方案:
import cv2
import pylab
from scipy import ndimage
im = cv2.imread('particles.jpg')
pylab.figure(0)
pylab.imshow(im)
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5,5), 0)
maxValue = 255
adaptiveMethod = cv2.ADAPTIVE_THRESH_GAUSSIAN_C#cv2.ADAPTIVE_THRESH_MEAN_C #cv2.ADAPTIVE_THRESH_GAUSSIAN_C
thresholdType = cv2.THRESH_BINARY#cv2.THRESH_BINARY #cv2.THRESH_BINARY_INV
blockSize = 5 #odd number like 3,5,7,9,11
C = -3 # constant to be subtracted
im_thresholded = cv2.adaptiveThreshold(gray, maxValue, adaptiveMethod, thresholdType, blockSize, C)
labelarray, particle_count = ndimage.measurements.label(im_thresholded)
print particle_count
pylab.figure(1)
pylab.imshow(im_thresholded)
pylab.show()
这将显示如下图像:
(这是给定的图像)
和
(这是计算的粒子)
并计算粒子数为60。
答案 0 :(得分:4)
我通过使用称为自适应对比度的技术使用调谐差阈值解决了“背景中的可变亮度”。它的工作原理是将灰度图像与其自身的模糊版本进行线性组合(在这种情况下是差异),然后对其应用阈值。
我使用scipy.ndimage
在浮点域中做得非常成功(比整数图像处理更好的结果),如下所示:
original_grayscale = numpy.asarray(some_PIL_image.convert('L'), dtype=float)
blurred_grayscale = scipy.ndimage.filters.gaussian_filter(original_grayscale, blur_parameter)
difference_image = original_grayscale - (multiplier * blurred_grayscale);
image_to_be_labeled = ((difference_image > threshold) * 255).astype('uint8') # not sure if it is necessary
labelarray, particle_count = scipy.ndimage.measurements.label(image_to_be_labeled)
希望这会有所帮助!!
答案 1 :(得分:3)
我无法给出明确的答案,但这里有几点建议:
函数mahotas.morph.regmax
可能比最大过滤器更好,因为它会删除伪最大值。也许将其与全局阈值,本地阈值(例如窗口上的平均值)或两者结合起来。
如果您有多个图像和相同的不均匀背景,那么您可以计算平均背景并对其进行标准化,或使用空图像作为背景估计。如果你有一台显微镜就是这种情况,就像我看过的每一台显微镜一样,光线不均匀。
类似的东西:
average = average_of_many(images)
# smooth it
average = mahotas.gaussian_filter(average,24)
现在您预处理图像,例如:
preproc = image/average
或类似的东西。