显微镜图像分割:用python进行细菌分割

时间:2014-07-14 12:45:34

标签: python image-processing image-segmentation mahotas ndimage

我试图将显示一些 E的显微镜明视场图像分段。大肠杆菌细菌。 我正在使用的图片类似于这个图片(即使这个图片是通过相位对比获得的):

microscopy bright-field image

我的问题是,在运行我的分割功能(下面的OtsuMask)之后,我无法区分分裂细菌(您可以在样本图像上尝试我的代码)。这意味着我得到一个标记区域,用于一些细菌,它们通过它们的末端连接,而不是两个不同的标记图像。 两个分裂细菌之间的界限太窄,无法通过我在阈值图像上执行的形态学操作突出显示,但我想必须有一种方法来实现我的目标。

有任何想法/建议吗?

import scipy as sp
import numpy as np
from scipy import optimize
import mahotas as mht
from scipy import ndimage
import pylab as plt


def OtsuMask(img,dilation_size=2,erosion_size=1,remove_size=500):

    img_thres=np.asarray(img)
    s=np.shape(img)    
    p0=np.array([0,0,0])

    p0[0]=(img[0,0]-img[0,-1])/512.    
    p0[1]=(img[1,0]-img[1,-1])/512.
    p0[2]=img.mean()

    [x,y]=np.meshgrid(np.arange(s[1]),np.arange(s[0]))

    p=fitplane(img,p0)    
    img=img-myplane(p,x,y)    


    m=img.min()
    img=img-m
    img=abs(img)
    img=img.astype(uint16)

    """perform thresholding with Otsu"""
    T = mht.thresholding.otsu(img,2)
    print T
    img_thres=img
    img_thres[img<T*0.9]=0
    img_thres[img>T*0.9]=1


    img_thres=-img_thres+1  

    """morphological operations"""
    diskD=createDisk(dilation_size)
    diskE=createDisk(erosion_size)

    img_thres=ndimage.morphology.binary_dilation(img_thres,diskD)   

    labeled_im,N=mht.label(img_thres)
    label_sizes=mht.labeled.labeled_size(labeled_im)
    labeled_im=mht.labeled.remove_regions(labeled_im,np.where(label_sizes<remove_size))    


    figure();
    imshow(labeled_im)

    return labeled_im

def myplane(p,x,y):

    return p[0]*x+p[1]*y+p[2] 

def res(p,data,x,y):

    a=(data-myplane(p,x,y));

    return array(np.sum(np.abs(a**2)))

def fitplane(data,p0):

    s=shape(data);

    [x,y]=meshgrid(arange(s[1]),arange(s[0]));
    print shape(x), shape(y)

    p=optimize.fmin(res,p0,args=(data,x,y));
    print p
    return p


def createDisk( size ):
    x, y = np.meshgrid( np.arange( -size, size ), np.arange( -size, size ) )
    diskMask = ( ( x + .5 )**2 + ( y + .5 )**2 < size**2)
    return diskMask

OtsuMask中的第一部分代码包括平面拟合和减法。

3 个答案:

答案 0 :(得分:1)

此处可以使用与this related stackoverflow answer中描述的方法类似的方法。

它基本上是这样的:

  • 为您的图像设定阈值

  • 对阈值图像应用距离变换

  • 阈值距离转换,以便只留下每个细菌的一小部分“种子”部分

  • 标记这些种子,给每个种子一个不同的灰色 (还为背景添加标记的种子)

  • 使用这些种子和距离转换图像执行分水岭算法,以获得细菌的分离轮廓

查看链接的答案,了解一些可以更清晰的图片。

答案 1 :(得分:0)

一些想法:

  1. Otsu可能不是一个好选择,因为你甚至可能使用固定的阈值(你的细菌是黑色的)。
  2. 使用任何方法对图像进行阈值处理将删除大量有用的信息。
  3. 我没有完整的食谱,但即便是这个非常简单的事情似乎也提供了很多有趣的信息:

    import matplotlib.pyplot as plt
    import cv2
    
    # cv2 is only used to read the image into an array, use only green channel
    bact = cv.imread("/tmp/bacteria.png")[:,:,1]
    
    # draw a contour image with fixed threshold 50
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.contourf(bact, levels=[0, 50], colors='k')
    

    这给出了:

    enter image description here

    这表明,如果使用具有固定轮廓的轮廓跟踪技术,您将获得相当漂亮的扩张和侵蚀起点。因此,阈值处理有两个不同之处:

    1. 轮廓使用比简单的黑/白阈值更多的灰度信息。
    2. 固定阈值似乎与这些图像配合良好,如果需要进行光照校正,Otsu不是最佳选择。

答案 2 :(得分:0)

有一天skimage Watershed segmentation对我来说比任何OpenCV样本都更有用。它使用了从Cellprofiler项目借用的一些代码(基于python的工具,用于复杂的细胞图像分析)。提示:使用Euclidean distance transform from opencv,它比scipy实现更快。此外,peak_local_max函数具有 distance 参数,这对于精确的单个细胞区分非常有用。我认为这个函数在查找细胞峰值时比粗糙阈值更稳健(因为细胞强度可能不同)。

您可以找到scipy分水岭实施,但它有奇怪的行为。