显微镜图像分割:使用Python进行细菌分割
我正在尝试对一些显微镜下的明场图像进行分割,这些图像中显示了一些E. coli细菌。
我正在处理的图片看起来像这个(虽然这个是用相位对比法获得的):
我的问题是,在运行我的分割函数(下面的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 个回答
有一天,我发现 skimage的分水岭分割 对我来说比任何OpenCV的示例都要有用。它使用了一些从 Cellprofiler 项目借来的代码(这是一个基于Python的工具,用于复杂的细胞图像分析)。小提示:使用 OpenCV的欧几里得距离变换,它比scipy的实现要快。此外,peak_local_max
函数有一个 distance 参数,这对精确区分单个细胞非常有用。我觉得这个函数在寻找细胞峰值方面比简单的阈值方法更可靠(因为细胞的强度可能会有所不同)。
你可以找到scipy的分水岭实现,但它的表现有点奇怪。
这里有几点想法:
- Otsu方法可能不太合适,因为你可以直接用一个固定的阈值(你的细菌是黑色的)。
- 用任何方法对图像进行阈值处理都会丢失很多有用的信息。
我没有完整的解决方案给你,但即使是这个非常简单的操作,也能提供很多有趣的信息:
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')
这样做会得到:
这表明,如果你使用固定轮廓的轮廓追踪技术,你会得到相当不错的膨胀和腐蚀的起始点。所以,在阈值处理方面有两个不同之处:
- 轮廓处理比简单的黑白阈值处理使用了更多的灰度信息。
- 固定阈值在这些图像上效果不错,如果需要进行光照校正,Otsu方法就不是最佳选择。
可以用一种和这个相关的StackOverflow回答类似的方法来解决这个问题。
大致步骤如下:
先对你的图像进行阈值处理,就像你之前做的那样。
在处理过的图像上应用距离变换。
对距离变换的结果再进行阈值处理,这样每个细菌只会留下一个小的“种子”部分。
给这些种子打上标签,每个种子用不同的灰度值表示
(还要给背景也加一个标签种子)用这些种子和距离变换后的图像执行分水岭算法,这样就能得到细菌的分离轮廓。
可以查看链接中的回答,里面有一些图片会让这个过程更清晰。