gpt4 book ai didi

image - 如何在 Matlab 中找到二值图像中的所有连通分量?

转载 作者:太空宇宙 更新时间:2023-11-03 19:26:40 26 4
gpt4 key购买 nike

我一直试图在不使用“bwlabel”函数的情况下使用二值图像中的 8 个邻居来查找所有连通分量。

比如我的输入矩阵是:

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 个连接的对象。

最佳答案

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

因此,鉴于您的矩阵存储在 A 中,这是基本算法:

  1. 初始化一个与A 大小相同的逻辑 数组。这将记录我们检查或访问过的像素。还将输出数组 B 初始化为全零,从而为您提供您正在寻找的所有连接组件。最后为零的任何位置都不属于任何连接的组件。同时初始化一个 ID 计数器,用于跟踪每个连接组件的标签。

  2. 对于矩阵中的每个位置:

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

    如果我们已经访问过该位置,则继续。

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

  3. 将这个未访问的位置添加到堆栈中。

    一个。虽然这个堆栈不为空......

    从堆栈中弹出这个位置

    如果我们访问过此位置,则继续。

    否则,将此位置标记为已访问并使用连接的组件 ID 标记此位置。

    给定此位置,查看 8 个相邻像素。

    移除这个列表中那些已经被访问过,不等于1或者超出矩阵边界的像素

    无论剩余的位置是什么,都将它们添加到堆栈中。

  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-connected 邻域中搜索

要修改代码以在 4-connected 区域中搜索,即仅北、东、西和南,您看到的部分 %//Look at the 8 neighboring 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-connected 方式搜索,您只需修改此代码以仅提供这些主要方向:

 %// 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函数

如果你想匹配MATLAB的bwlabel的输出函数,bwlabel 按主列或 FORTRAN 顺序搜索连通分量。上面的代码按行主要或 C 顺序搜索。因此,您只需要先按列搜索,而不是像上面的代码那样按行搜索,您可以通过交换两个 for 循环的顺序来完成此操作。

具体来说,而不是做:

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

你会这样做:

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

现在应该复制 bwlabel 的输出。

关于image - 如何在 Matlab 中找到二值图像中的所有连通分量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26332883/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com