2014-10-13 43 views
6

我一直在试图找到所有连接的组件使用八个二进制图像中的邻居,而不使用函数“bwlabel”。如何在Matlab中找到二进制图像中的所有连接组件?

例如,我输入矩阵是:

a = 

    1  1  0  0  0  0  0 
    1  1  0  0  1  1  0 
    1  1  0  0  0  1  0 
    1  1  0  0  0  0  0 
    0  0  0  0  0  1  0 
    0  0  0  0  0  0  0 

我想有这样的事情:

a = 

    1  1  0  0  0  0  0 
    1  1  0  0  2  2  0 
    1  1  0  0  0  2  0 
    1  1  0  0  0  0  0 
    0  0  0  0  0  3  0 
    0  0  0  0  0  0  0 

有此图像中3级连接的对象。

回答

11

这是图像处理中的常见问题。有很多变化,例如洪水填充图像中的区域,或查找属于同一区域的像素。一种常用的方法是使用depth first search。这个想法是,你从左到右和从上到下遍历你的图像,遇到的任何像素等于1,你将它们添加到堆栈。对于堆栈中的每个像素,从堆栈弹出,然后查看该像素周围的相邻像素。您添加到堆栈的任何像素都是1。您需要保留一个额外的变量,其中任何像素已经访问,您不需要将这些添加到堆栈中。当堆栈为空时,我们发现这些像素是整个区域,因此您使用唯一的ID标记这些像素。然后重复此过程,直到图像中的区域用完。

这样,因为你的基质储存在在A,这是基本的算法:

  1. 初始化一个数组,是相同大小Alogical。这将记录我们已检查或访问的像素。同时将输出数组B初始化为全零,为您提供所需的所有连接组件。任何零到最后的位置都不属于任何连接的组件。同时初始化一个ID计数器,记录每个连接组件的标签。

  2. 对于每个在我们的矩阵位置:

    一个。如果位置为0,请将此位置标记为已访问并继续。

    b。如果我们已经访问过这个位置,然后继续。

    c。如果我们还没有访问过这个位置......请转到第3步。

  3. 将此未访问位置添加到堆栈。

    a。虽然这个堆栈不是空的...

    b。从堆栈中弹出此位置

    c。如果我们访问过这个位置,然后继续。 d)。否则,将此位置标记为已访问,并使用连接的组件标识标记此位置。

    e。给定这个位置,看看8个相邻像素。

    f。删除已经访问过的列表中的那些像素,不等于1或超出矩阵的范围

    g。无论位置是什么,将这些添加到堆栈中。

  4. 堆栈清空后,增加计数器,然后回到步骤#2。

  5. 继续前进,直到我们访问了我们阵列中的所有位置。

不用再说了,这里是代码。


%// Step #1 
visited = false(size(A)); 
[rows,cols] = size(A); 
B = zeros(rows,cols); 
ID_counter = 1; 

%// Step 2 
%// For each location in your matrix... 
for row = 1 : rows 
    for col = 1 : cols 
     %// Step 2a 
     %// If this location is not 1, mark as visited and continue 
     if A(row,col) == 0 
      visited(row,col) = true; 

     %// Step 2b 
     %// If we have visited, then continue 
     elseif visited(row,col) 
      continue; 

     %// Step 2c 
     %// Else... 
     else 
      %// Step 3 
      %// Initialize your stack with this location 
      stack = [row col]; 

      %// Step 3a 
      %// While your stack isn't empty... 
      while ~isempty(stack) 
       %// Step 3b 
       %// Pop off the stack 
       loc = stack(1,:); 
       stack(1,:) = []; 

       %// Step 3c 
       %// If we have visited this location, continue 
       if visited(loc(1),loc(2)) 
        continue; 
       end 

       %// Step 3d 
       %// Mark location as true and mark this location to be 
       %// its unique ID 
       visited(loc(1),loc(2)) = true; 
       B(loc(1),loc(2)) = ID_counter; 

       %// Step 3e 
       %// Look at the 8 neighbouring locations 
       [locs_y, locs_x] = meshgrid(loc(2)-1:loc(2)+1, loc(1)-1:loc(1)+1); 
       locs_y = locs_y(:); 
       locs_x = locs_x(:); 

       %%%% USE BELOW IF YOU WANT 4-CONNECTEDNESS 
       % See bottom of answer for explanation 
       %// Look at the 4 neighbouring locations 
       % locs_y = [loc(2)-1; loc(2)+1; loc(2); loc(2)]; 
       % locs_x = [loc(1); loc(1); loc(1)-1; loc(1)+1]; 

       %// Get rid of those locations out of bounds 
       out_of_bounds = locs_x < 1 | locs_x > rows | locs_y < 1 | locs_y > cols; 

       locs_y(out_of_bounds) = []; 
       locs_x(out_of_bounds) = []; 

       %// Step 3f 
       %// Get rid of those locations already visited 
       is_visited = visited(sub2ind([rows cols], locs_x, locs_y)); 

       locs_y(is_visited) = []; 
       locs_x(is_visited) = []; 

       %// Get rid of those locations that are zero. 
       is_1 = A(sub2ind([rows cols], locs_x, locs_y)); 
       locs_y(~is_1) = []; 
       locs_x(~is_1) = []; 

       %// Step 3g 
       %// Add remaining locations to the stack 
       stack = [stack; [locs_x locs_y]]; 
      end 

      %// Step 4 
      %// Increment counter once complete region has been examined 
      ID_counter = ID_counter + 1; 
     end 
    end %// Step 5 
end 

你的榜样矩阵,这是我得到B

B = 

    1  1  0  0  0  0  0 
    1  1  0  0  2  2  0 
    1  1  0  0  0  2  0 
    1  1  0  0  0  0  0 
    0  0  0  0  0  3  0 
    0  0  0  0  0  0  0 

要在4连接附近

搜索要修改代码搜索4连通区域,即仅北部,东部,西部和南部,您看到的部分%// Look at the 8 neighbouring locations,那就是:

%// Look at the 8 neighbouring locations 
[locs_y, locs_x] = meshgrid(loc(2)-1:loc(2)+1, loc(1)-1:loc(1)+1); 
locs_y = locs_y(:); 
locs_x = locs_x(:); 

要在4连接的方式进行搜索,你只需要修改这个代码,只给那些主要的方向:

%// Look at the 4 neighbouring locations 
locs_y = [loc(2)-1; loc(2)+1; loc(2); loc(2)]; 
locs_x = [loc(1); loc(1); loc(1)-1; loc(1)+1]; 

代码的其余部分保持不变。

要如果你想MATLAB的bwlabel函数的输出,bwlabel搜索栏主要还是为了FORTRAN连接的部件匹配匹配MATLAB的bwlabel功能

。上面的代码以行主或C顺序搜索。因此,您只需要首先搜索列而不是按照上面的代码所做的操作,然后通过交换两个for循环的顺序来执行此操作。

具体,而不是做:

for row = 1 : rows 
    for col = 1 : cols 
     .... 
     .... 

你会做:

for col = 1 : cols 
    for row = 1 : rows 
     .... 
     .... 

这个现在应该复制的bwlabel输出。

+1

你的代码是惊人的,它做我真正想要的。这有点难以理解,但我明白了,你是一位优秀的程序员,再次感谢你。 –

+0

不错的代码。您能否告诉我如何在数组中显示图表中的所有路径。例如:路径将如下所示:path_1 = [3,2,6,7,4,8,5]; – kgk

+0

@kgk我不知道你在问什么。请使用我在上面的答案中给出的示例给我预期的输出。 – rayryeng

相关问题