如何为此微观图像高效创建BW蒙版?

时间:2015-07-17 23:06:15

标签: image matlab image-processing image-segmentation watershed

所以有些背景知识。我的任务是编写一个matlab程序来计算可见光显微图像中酵母细胞的数量。为此,我认为第一步将是细胞分割。在我得到真正的实验图像集之前,我开发了一个使用分水岭的测试图像集的算法。看起来像这样:

Original Image

分水岭的第一步是为细胞生成BW掩模。然后我将生成一个bwdist图像,该图像具有从BW蒙版生成的强制局部最小值。有了这个,我就可以轻松地产生分水岭。

BW mask local minimum mask generated from BW mask enter image description here

正如您所看到的,我的算法依赖于BW掩码的成功生成。因为我需要从中生成bwdist图像和标记。最初,我按照以下步骤生成BW掩码:

  1. 生成图像的局部标准差 sdImage = stdfilt(grayImage,ones(9))
  2. std filter

    1. 使用BW阈值生成初始BW掩码 binaryImage = sdImage< 8;
    2. initial BW filter

      1. 使用 imclearborder 清除背景。使用其他一些代码在边框上添加单元格。
      2. final BW mask

        后台已完成。这是我的问题

        但是今天我收到了新的真实数据集。图像分辨率小得多,光照条件与测试图像集不同。颜色深度也小得多。这些使我的算法无用。这是它:

        New image set

        使用 stdfilt 无法生成干净的图像。而是生成这样的东西(注意:我已经调整了 stdfilt 函数的参数和BW阈值,以下是我能得到的最好结果):

        new stdfilt result

        正如您所看到的,细胞中心的光像素不必比膜更暗。哪个引导bw阈值产生这样的东西:

        new bw thresholding

        bw阈值处理后的新bw图像具有不完整的膜或分段的细胞中心,并使它们不适合其他步骤。

        我最近才开始进行图像处理,不知道该怎么办。如果您有任何想法请帮助我!谢谢!

        为了您的方便,我在Dropbox上附加了subset of the images

        的链接

1 个答案:

答案 0 :(得分:4)

我认为你的方法存在根本问题。您的算法使用stdfilt来对图像进行二值化。但这实际上意味着你假设在单元格中的背景中存在低“纹理”。这适用于您的第一张图片。但是,在第二个图像中,单元格内部存在“纹理”,因此该假设被破坏。

我认为更强的假设是每个单元格周围都有一个“响铃”(对于你发布的两个图像都有效)。所以我采取了检测此环的方法。

所以我的方法基本上是:

  1. 检测这些响铃(我使用'日志'过滤器,然后根据正值进行二值化。但是,这会产生很多“喋喋不休”
  2. 最初通过过滤掉非常小且非常大的区域来尝试删除一些“喋喋不休”
  3. 现在,填写这些戒指。但是,在单元格之间仍然存在一些“喋喋不休”和填充区域
  4. 同样,删除小区域和大区域,但由于单元格已填满,请增加可接受范围的界限。
  5. 仍然存在一些不良区域,大多数不良区域将成为细胞之间的区域。通过观察区域边界周围的曲率可以检测细胞之间的区域。它们“向内弯曲”很多,这在数学上表示为具有负曲率的边界的大部分。此外,为了消除“颤振”的其余部分,这些区域的边界曲率将具有较大的标准偏差,因此也要去除具有较大标准偏差的边界。
  6. 总的来说,最困难的部分是在不移除实际细胞的情况下去除细胞之间的区域和“颤动”。

    无论如何,这里是代码(请注意,有很多启发式方法,并且它非常粗糙,并且基于旧项目,homeworks和stackoverflow答案的代码,所以它肯定远未完成):

    cell = im2double(imread('cell1.png'));
    if (size(cell,3) == 3) 
        cell = rgb2gray(cell);
    end
    
    figure(1), subplot(3,2,1)
    imshow(cell,[]);
    
    % Detect edges
    hw = 5;
    cell_filt = imfilter(cell, fspecial('log',2*hw+1,1));
    
    subplot(3,2,2)
    imshow(cell_filt,[]);
    
    % First remove hw and filter out noncell hws
    mask = cell_filt > 0;
    hw = 5;
    mask = mask(hw:end-hw-1,hw:end-hw-1);
    
    subplot(3,2,3)
    imshow(mask,[]);
    
    rp = regionprops(mask, 'PixelIdxList', 'Area');
    rp = rp(vertcat(rp.Area) > 50 & vertcat(rp.Area) < 2000);
    
    mask(:) = false;
    mask(vertcat(rp.PixelIdxList)) = true;
    
    subplot(3,2,4)
    imshow(mask,[]);
    
    % Now fill objects
    mask1 = true(size(mask) + hw);
    mask1(hw+1:end, hw+1:end) = mask;
    mask1 = imfill(mask1,'holes');
    mask1 = mask1(hw+1:end, hw+1:end);
    
    mask2 = true(size(mask) + hw);
    mask2(hw+1:end, 1:end-hw) = mask;
    mask2 = imfill(mask2,'holes');
    mask2 = mask2(hw+1:end, 1:end-hw);
    
    mask3 = true(size(mask) + hw);
    mask3(1:end-hw, 1:end-hw) = mask;
    mask3 = imfill(mask3,'holes');
    mask3 = mask3(1:end-hw, 1:end-hw);
    
    mask4 = true(size(mask) + hw);
    mask4(1:end-hw, hw+1:end) = mask;
    mask4 = imfill(mask4,'holes');
    mask4 = mask4(1:end-hw, hw+1:end);
    
    mask = mask1 | mask2 | mask3 | mask4;
    
    % Filter out large and small regions again
    rp = regionprops(mask, 'PixelIdxList', 'Area');
    rp = rp(vertcat(rp.Area) > 100 & vertcat(rp.Area) < 5000);
    
    mask(:) = false;
    mask(vertcat(rp.PixelIdxList)) = true;
    
    subplot(3,2,5)
    imshow(mask);
    
    % Filter out regions with lots of positive concavity
    
    % Get boundaries
    [B,L] = bwboundaries(mask);
    
    % Cycle over boundarys
    for i = 1:length(B)
        b = B{i};
    
        % Filter boundary - use circular convolution
        b(:,1) = cconv(b(:,1),fspecial('gaussian',[1 7],1)',size(b,1));
        b(:,2) = cconv(b(:,2),fspecial('gaussian',[1 7],1)',size(b,1));
    
        % Find curvature
        curv_vec = zeros(size(b,1),1);
        for j = 1:size(b,1)
            p_b = b(mod(j-2,size(b,1))+1,:);  % p_b = point before
            p_m = b(mod(j,size(b,1))+1,:);    % p_m = point middle
            p_a = b(mod(j+2,size(b,1))+1,:);  % p_a = point after
    
            dx_ds = p_a(1)-p_m(1);              % First derivative
            dy_ds = p_a(2)-p_m(2);              % First derivative
            ddx_ds = p_a(1)-2*p_m(1)+p_b(1);    % Second derivative
            ddy_ds = p_a(2)-2*p_m(2)+p_b(2);    % Second derivative
            curv_vec(j+1) = dx_ds*ddy_ds-dy_ds*ddx_ds;
        end
    
    
        if (sum(curv_vec > 0)/length(curv_vec) > 0.4 || std(curv_vec) > 2.0)
            L(L == i) = 0;
        end
    end
    
    mask = L ~= 0;
    
    subplot(3,2,6)
    imshow(mask,[])
    

    输出1:

    enter image description here

    输出2:

    enter image description here