【问题标题】:How do I efficiently created a BW mask for this microscopic image?如何有效地为该显微图像创建 BW 蒙版?
【发布时间】:2015-10-07 18:34:25
【问题描述】:

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

分水岭的第一步是为单元格生成 BW 掩码。然后我会生成一个 bwdist 图像,其中包含从 BW 掩码生成的强加局部最小值。这样我就可以轻松生成分水岭了。

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

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

  1. 使用 BW 阈值生成初始 BW 掩码binaryImage = sdImage

  1. 使用 imclearborder 清除背景。使用其他一些代码将边框上的单元格添加回来。


背景完成。这是我的问题


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

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

如您所见,细胞中心的亮像素不一定比膜更暗。这导致 bw 阈值生成如下内容:

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

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

为了您的方便,我附上了一个来自 Dropbox 的链接 subset of the images

【问题讨论】:

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


    【解决方案1】:

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

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

    所以我的方法本质上是:

    1. 检测这些环(我使用“对数”过滤器,然后根据正值进行二值化。但是,这会导致很多“喋喋不休”
    2. 最初尝试通过过滤掉非常小和非常大的区域来消除一些“喋喋不休”
    3. 现在,填上这些环。但是,单元格之间仍然存在一些“颤动”和填充区域
    4. 同样,删除大小区域,但由于单元格已填充,因此应增加可接受的范围。
    5. 仍有一些坏区域,大部分坏区域将是单元格之间的区域。通过观察区域边界周围的曲率可以检测细胞之间的区域。它们“向内弯曲”很多,这在数学上表示为边界的大部分具有负曲率。此外,为了消除其余的“颤动”,这些区域的边界曲率会有很大的标准偏差,因此也要删除标准偏差较大的边界。

    总的来说,最困难的部分是在不删除实际单元格的情况下删除单元格之间的区域和“chatter”。

    无论如何,这是代码(请注意,有很多启发式方法,而且非常粗糙,并且基于旧项目、家庭作业和 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:

    输出2:

    【讨论】:

    • 抱歉重播晚了。我花了一些时间来消化这些信息。这教会了我很多!
    猜你喜欢
    • 2022-11-23
    • 2013-10-23
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多