使用python中的图像处理对粒子进行计数 [英] Counting particles using image processing in python

查看:561
本文介绍了使用python中的图像处理对粒子进行计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否存在用于检测背景强度变化的好的算法? 例如,如果我有以下图像:

即使在左下角出现明显不同的背景,有没有办法计数白色小颗粒?

为了更加清楚一点,我想标记图像并使用一种算法来对粒子进行计数,该算法会发现这些粒子很重要:

我已经尝试过使用PILcvscipynumpy等模块进行许多操作. 我从这个非常相似的SO问题中得到了一些提示,它首先出现一眼便可以采用一个简单的阈值,如下所示:

im = mahotas.imread('particles.jpg')
T = mahotas.thresholding.otsu(im)

labeled, nr_objects = ndimage.label(im>T)
print nr_objects
pylab.imshow(labeled)

但是由于背景的变化,您会得到以下信息:

我还尝试了其他想法,例如我发现的用于测量爪子的技术,我是通过这种方式实现的:

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.

解决方案

我通过使用一种称为自适应对比度"的技术,通过使用调整后的差异阈值解决了背景中的可变亮度"问题.它通过对灰度图像与自身的模糊版本进行线性组合(在某些情况下有所不同),然后对其施加阈值来工作.

  1. 使用合适的统计运算符对图像进行卷积.
  2. 从卷积图像中减去原稿,必要时校正强度比例/伽玛.
  3. 以恒定的阈值表示差异图像.

(原始论文)

我在浮点域中使用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)

希望这会有所帮助!

Is there any good algorithm for detecting particles on a changing background intensity? For example, if I have the following image:

Is there a way to count the small white particles, even with the clearly different background that appears towards the lower left?

To be a little more clear, I would like to label the image and count the particles with an algorithm that finds these particles to be significant:

I have tried many things with the PIL, cv , scipy , numpy , etc. modules. I got some hints from this very similar SO question, and it appears at first glance that you could take a simple threshold like so:

im = mahotas.imread('particles.jpg')
T = mahotas.thresholding.otsu(im)

labeled, nr_objects = ndimage.label(im>T)
print nr_objects
pylab.imshow(labeled)

but because of the changing background you get this:

I have also tried other ideas, such as a technique I found for measuring paws, which I implemented in this way:

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

but this gives no luck either, showing this result:

Using the regional max function, I get images which almost appear to be giving correct particle identification, but there are either too many, or too few particles in the wrong spots depending on my gaussian filtering (images have gaussian filter of 2,3, & 4):

Also, it would need to work on images similar to this as well:

This is the same type of image above, just at a much higher density of particles.

EDIT: Solved solution: I was able to get a decent working solution to this problem using the following code:

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

This will show the images like this:

(which is the given image)

and

(which is the counted particles)

and calculate the particle count as 60.

解决方案

I had solved the "variable brightness in background" by using a tuned difference threshold with a technique called Adaptive Contrast. It works by performing a linear combination (a difference, in the case) of a grayscale image with a blurred version of itself, then applying a threshold to it.

  1. Convolve the image with a suitable statistical operator.
  2. Subtract the original from the convolved image, correcting intensity scale/gamma if necessary.
  3. Threshold the difference image with a constant.

(original paper)

I did this very successfully with scipy.ndimage, in the floating-point domain (way better results than integer image processing), like this:

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)

Hope this helps!!

这篇关于使用python中的图像处理对粒子进行计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆