Matlab实现bwlabel函数(区域标记)功能

算法分析

  1. 图像预处理。对二值图进行形态学开操作,开操作能去掉细小的块,平滑目标区域边界且保持面积不变

  2. 遍历二值图矩阵,寻找目标区域且未被标记的点,若当前像素未标记且当前位置像素点为1(二值图的目标区域)

  3. 将该目标点入队,并标上区域编号label

  4. BFS,对步骤1中的求得8邻域的像素点,如果该点未越界,是目标点(灰度值为1)并且未被标记过则入队,并且标上当前编号label,队列中每个点的8领域判断完则出队,当队列为空时一个连通区域标记完成,label+1

  5. 回到步骤1,直到二值图遍历完成

  6. 输出,将标记矩阵以彩色标记的形式输出,循环结束时label的值多加了1,退出循环时,label的值减1才是该图中的连通区域的个数

伪代码

function [conn,num] = mybwlabel( I )
% 使用BFS对二值图区域标记
% 输入:I是二值图矩阵
% 输出:tmp是标记矩阵,num是连通区域个数

[m n] = 计算二值图的大小
conn = 开辟一个和二值图同样大小的标记矩阵
label = 给区域编号设初值1
queue = 定义二维数组用于存放一个连通区域的点的坐标(模拟队列)
neighbour = 8邻域(坐标无序) 

遍历二值图
        如果当前点属于目标区域且未标记    
            queue = 当前点坐标入队
            conn(i,j) = 给该点赋值区域编号
            队列不空
                index = 取出队首坐标 
                8邻域搜索              
                    cur_index = 当前点邻域坐标
                    如果当前坐标未越界
                        如果当前像素邻域像素为1并且标记图像的这个邻域像素没有被标记
                            标记当前点
                            当前坐标入队(矩阵合并)  
               队首坐标出 
            label = 区域编号加1          
num = 连通区域的个数为label-1
end

代码

function [conn,num] = mybwlabel( I )
% 对二值图区域标记
% 输入:I是二值图矩阵
% 输出:tmp是标记矩阵,num是连通区域个数

[m n] = size(I);
conn = zeros(m,n);     %标记矩阵
label = 1;
queue = [];  %用二维数组模拟队列
%和当前像素坐标相加得到八个邻域坐标(坐标无序)
neighbour = [-1 -1;-1 0;-1 1;0 -1;0 1;1 -1;1 0;1 1]; 

for i = 2 : m-1 
    for j = 2 : n-1
        if I(i,j) == 1 && conn(i,j) == 0 %属于目标区域且未标记才处理          
            conn(i,j) = label;
            queue = [i;j];  %记录当前点坐标
            while ~isempty(queue) %队列不空,这里没有出队操作,队列中的每一个元素的8领域都判断一遍
                index = [queue(1,1),queue(2,1)];                
                for k = 1 : 8               %8邻域搜索
                    cur_index = index + neighbour(k,:);  %加上每一行的坐标得到周围8邻域的坐标点
                    if cur_index(1) >= 2 && cur_index(1) <= m - 1 && cur_index(2) >= 2 && cur_index(2) <= n - 1 %防止坐标越界
                        if I(cur_index(1),cur_index(2)) == 1 && conn(cur_index(1),cur_index(2)) ==0  %如果当前像素邻域像素为1并且标记图像的这个邻域像素没有被标记,那么标记
                            conn(cur_index(1),cur_index(2)) = label;
                            queue = [queue [cur_index(1);cur_index(2)]];
                        end  
                    end              
                end
               queue(:,1) = []; %队列中第一列的坐标出队
            end    
            label = label+1;            
        end
    end
end
num = label - 1; %连通区域的个数(减去背景这个连通区域)
end

实验结果

% 调用示例:
I = imread('rice.png');
Ib = im2bw(I);
[B,num] = mybwlabel(Ib);
subplot(1,3,1),imshow(I),title('原图');
subplot(1,3,2),imshow(Ib),title('二值图');
subplot(1,3,3),imshow(label2rgb(B)),title('区域标记');

连通区域个数:

图像预处理去噪,由上图中二值化之后,二值图中有很多噪声点,可以通过形态学开操作去除这些点

SE = strel('disk',3);  %定义一个圆形结构元
Ib = imopen(Ib,SE);  %开操作去除噪声

开操作之后的效果

连通区域个数:

开操作之后去除噪声,连通区域个数明显减少

实验分析

  • 在标记连通区域之前可以通过形态学操作,去除噪声点

  • 对二值图中每一个像素点的8邻域,都遍历一遍,将8邻域中属于目标区域的点的坐标都入队,对于当前满足条件的像素点判断结束时,就会标记完一个连通区域

  • 在遍历8领域时为避免重复标记,需要多次判断当前是否已经标记

原文地址:https://www.cnblogs.com/Vicky1361/p/13936349.html