如何计算图像中一组笔划的粗细?

时间:2015-03-04 22:02:47

标签: image matlab image-processing

如何计算附图中每个笔划的粗细?

我对图像中的所有神经进行了分割,并在图像中标记了每个对象。我想知道如何计算每个神经的厚度?另外,如果任何神经出现充气,我怎样才能突出神经的特定部位呢?

非常感谢您在这方面的帮助。

2 个答案:

答案 0 :(得分:7)

我想指出以下帖子:Measuring the average thickness of traces in an image。基本上,图像中存在单个笔划,目标是确定该笔划的平均厚度。我们只需针对图像中存在的每个笔划重新应用此算法。

基本算法如下(并且非常巧妙):

  1. 对于图像中的笔划,将distance transform应用于图像转换的图像,以便所有背景像素变为白色,对象像素变为黑色。因此,我们在图像的上应用距离变换。

    距离变换找到图像中的点与最接近的非零像素之间的距离。因此,通过将距离变换应用于逆,对于每个笔划点,这将确定从该特定点到笔划上的最接近的边界点的距离。我们在这方面需要距离变换的原因将在下一步中明确说明。

  2. 在距离变换中共享最大距离的笔划上的点定义笔划的中间。您可以将此视为中风之间的中途点。由于浮点运算,将所有这些距离值收集在该最大距离的某个容差范围内。

  3. 找出所有这些距离的平均值或中位数,这决定了一半中风的宽度....所以如果你想要完整厚度,只需将结果乘以2.

  4. 在继续之前,我将假设您可以访问图像处理工具箱,因为距离变换是在工具箱中的bwdist函数中实现的。如果你没有这个工具箱,那么不幸的是我写的不会起作用。这是算法所需的唯一依赖项(当然,除了使用imreadim2bw之外)。

    由于某种原因,当您以RGB格式上传图像时,我不得不将图像转换为二进制,因此我将其转换为单通道二进制图像。因此,您的代码可能如下所示:

    %// Read the image from StackOverflow and convert to binary
    im = im2bw(imread('http://i.stack.imgur.com/DggWW.jpg'));
    
    %// Find all unique contours and assign them a unique ID.  Also determine how many there are
    [lbl,N] = bwlabel(im);
    
    %// Initialize an array that determines the thickness of each stroke
    thickness = zeros(N,1);
    
    %// Tolerance to collect distances
    tol = 1;
    
    %// For each stroke...
    for idx = 1 : N
    
        %// Step #1
        cntr = lbl == idx; %// Get a mask that segments out that stroke only
        d = bwdist(~cntr); %// Find distance transform on inverse
    
        %// Step #2
        max_dist = max(d(:)); %// Get the maximum distance from stroke to edge
        dists = d(abs(d - max_dist) <= tol); %// Collect those distances within a tolerance
    
        %// Step #3
        thickness(idx) = 2*mean(dists);  %// Find the average width and multiply by 2 for full width
    end
    

    thickness是一个元素数组,它告诉您图像中每个笔划的宽度或粗细。每个元素i都会告诉您i结果中标签bwlabel指定的轮廓粗细。因此,对于i中的每个元素thickness,这会记录描绘的笔划的粗细:

    cntr = lbl == i;
    

    使用您的图片,我得到以下结果:

    thickness =
    
        3.3555
        3.2494
        3.1545
        3.1773
        3.3282
        3.2607
        3.2710
        3.2772
        3.2948
        3.1607
    

    至于确定神经是否发炎,您需要知道每个中风的真实厚度是多少,并确定是否有增加。我没有这样的信息,所以我要把它作为练习留给你。我们计算了每个笔划的厚度,从那里写出一些代码来检测增加并相应地采取行动。


    作为额外奖励,让我们制作一个新的输出图像,我们在其中找到每个笔划的质心,将该笔划放在此输出图像中,并在笔划的质心处打印出其厚度。像这样:

    imshow(im); hold on;
    for idx = 1 : N
        [y,x]= find(lbl == idx);
        cen = mean([x y]);
        text(cen(1), cen(2), ['T = ' num2str(thickness(idx))], 'color', 'red');
    end
    

    我们得到:

    enter image description here

答案 1 :(得分:2)

我的方法使用以下

解决了这个问题

思想:

对于图片中的每一个笔划:

  1. 计算中风区域
  2. 计算行程长度
  3. 计算平均厚度作为面积除以行程长度
  4. 区域:

    计算区域很容易。人们可以简单地计算像素数。

    笔划长度:

    行程长度更难。人们可以使用图像bwmorph(BW,'skel',Inf)的骨架来做到这一点,但我使用了不同的方法。我找到了笔划的周长,并使用一些数学来找到一个等效面积和周长的矩形,其边长应与笔划长度和平均厚度相对应。

    计算这种中风的周长,必须密切注意coastline paradox。测量由像素轮廓定义的笔划的实际周长将得到不准确的结果:对角笔划的周长将被测量为向右1个像素宽度,1个像素宽度向上,1个像素宽度向右,1个像素宽度向上,。 ..而不是:sqrt(2)对角线像素宽度,...

    我们可以通过使用alpha shapes对我们的中风进行三角测量来解决这个问题。我在文件交换中使用 Jonas Lundgren 的实现:alphavol

    最终代码:

    image = im2bw(imread('http://i.stack.imgur.com/DggWW.jpg'));    
    alphaRadius = 2; %// Could be chosen larger than 2 to get better results, but must not affect the overall area of the triangulation.
    %%
    [Labeled,N] = bwlabel(image);
    thicknesses = zeros(1,N);
    lengths = @(Points) sqrt(sum(Points.^2,2));                           
    
    %// Formula for finding an equivalent rectangle:
    %// Assume rectangle: Area = a*b, Perimeter = 2*(a+b),
    %// solve for a and b, return minimum as thickness
    solveForThickness = @(P,A) min(P/4 + (P^2/4 - 4*A)^(1/2)/2, ...
                                   P/4 - (P^2/4 - 4*A)^(1/2)/2);
    for idx = 1:N
        %// Get current stroke
        stroke = (Labeled == idx);
        [Y,X] = find(stroke);
        %// Get corners of pixels and generate alpha shape
        P = [X-1, Y-1; ...
             X,   Y-1;
             X-1, Y;
             X,   Y];
        [area,S] = alphavol(P,alphaRadius);
        area = nnz(stroke); %// Seems to give better results than triangulated area above
        %// Compute perimeter and thickness
        perimeter = sum(lengths(P(S.bnd(:,1),:)-P(S.bnd(:,2),:)));
        thicknesses(idx) = solveForThickness(perimeter, area);
    end
    

    后果:

    请记住,此解决方案在很大程度上取决于三角测量与中风数据的匹配程度。通过选择均匀变化陡度的笔划,可以看到由于海岸线悖论引起的该算法的问题。可能有更好的方法来计算笔划的长度以获得更准确的结果。它似乎工作得很好。

    使用alpha形状的替代方法可能是:

    perimeter = getfield(regionprops(stroke,'perimeter'),'Perimeter');
    

    其结果也非常准确。