bwlabel实现(递归、一步法、两步法)

bwlabel的实现方法我这里列举三种(递归、一步法、两步法),其中递归方法和一步法很类似,只不过一步法中用了一个队列实现递归。

主要思路: 
递归:从上至下,从左至右,当搜索到第一个白色点并且其对应的output值没有被标签,然后开始从这个点搜索,在其八邻域内搜索,如果它满足是白色点并且其对应的output值没有被标签这个条件,就将这个点的八邻域继续搜索,这个地方可以使用递归实现. 
但是递归方法没有一步法好,因为递归有着次数限制,当图像不大的时候没有问题,图像很大的时候会栈溢出,报错,此时可以运用一步法,用队列这种数据结构。

一步法:思路和递归一样,从上至下,从左至右,当搜索到第一个白色点并且其对应的output值没有被标签,然后开始从这个点搜索,在其八邻域内搜索,如果它满足是白色点并且其对应的output值没有被标签这个条件,就将这个点添加到待搜索的队列里面,队列移动,直到队列里面没有元素,表示搜索完毕

两步法:应该是这些方法里面最快的方法了,顾名思义Two-pass第一次for循环将图1中4个周围点label先打上,并使用一个数组记录他们的父节点,这个打label的规则如下: 
1. 4个点全是0 处理方法:label+1,并赋值 
2. (至多4个点)全是一样的label 将周围的label赋值给这个点即可 
3. (至多4个点)有两种label label赋值为label小的那个,并将这两个label放到同一个数组里面去 
4. (至多4个点)有三种label,并使最小的值为另外两个值的父节点

第二次for循环,将每个label更新,首先更新为父节点,但是父节点并不一定是连续的,所以需要将不连续的父节点label变成连续的label。 
图像1图1

一步法及两步法相关资料网址: 
https://blog.csdn.net/u012526003/article/details/50970850 
http://www.cnblogs.com/tiandsp/archive/2012/12/06/2805276.html 
https://www.cnblogs.com/evilKing/p/6001654.html 
http://www.cnblogs.com/tiandsp/archive/2012/12/06/2804922.html

递归方法代码:

 
  1. clc;
  2. clear;
  3. %彩色图像转化成灰度再转化成二值图像
  4. global K;
  5. global bw;
  6. K = imread('rice.png');
  7. K = im2bw(K);
  8. imshow(K)
  9. global r;
  10. global c;
  11. [r ,c ] = size(K);
  12. bw = zeros(r,c);
  13. %global count;
  14. count = 1;
  15. global s;
  16. s = 1;%变量s用来控制count,使得一次递归只加一次
  17. %连通
  18. for i = 1:r
  19. for j = 1:c
  20. liantong(i,j,count);
  21. if s == 0;
  22. count = count +1;
  23. s = 1;
  24. end
  25. end
  26. end
  27. count = count - 1;
  28. figure
  29. imshow(bw)

递归函数文件(liantong.m)

 
  1. function liantong(i,j,count)
  2. global K;
  3. global bw;
  4. global r;
  5. global c;
  6. global s;
  7. if(K(i,j) == 1 && bw(i,j) == 0 )
  8. s = 0;
  9. bw(i,j) = count;
  10. if(i>1 )
  11. liantong(i-1,j,count);
  12. if( j > 1)
  13. liantong(i-1,j-1,count);
  14. end
  15. end
  16. if(i>1 && j<c)
  17. liantong(i-1,j+1,count);
  18. end
  19. if(j>1)
  20. liantong(i,j-1,count);
  21. end
  22. if(j<c)
  23. liantong(i,j+1,count);
  24. end
  25. if(i<r)
  26. liantong(i+1,j,count);
  27. if(j>1)
  28. liantong(i+1,j-1,count);
  29. end
  30. end
  31. if(i<r && j<c)
  32. liantong(i+1,j+1,count);
  33. end
  34. end
  35. end

一步法:

 
  1. K = imread('rice.png');
  2. tic
  3. K = im2bw(K);
  4. %在最外圈加上一圈
  5. [r,c] = size(K);
  6. K1 = zeros(r+2,c+2);
  7. for i = 2:r+1
  8. for j = 2:c+1
  9. K1(i,j) = K(i-1,j-1);
  10. end
  11. end
  12. output = zeros(r,c);
  13. label = 1;
  14. neighbour = [-1,-1;-1,0;-1,1;0,-1;0,1;1,-1;1,0;1,1];%8 邻域
  15. head = 1;
  16. tail = 1;
  17. %output相对于K1来说 向左上平移了一个单元
  18. for i = 2:r+1
  19. for j = 2:c+1
  20. if (K1(i,j) == 1 && output(i-1,j-1) == 0)%种子点
  21. s{tail} = [i,j];
  22. tail = tail + 1;
  23. while (head ~= tail)
  24. for l = 1:8
  25. q = s{head} + neighbour(l,:);%头指针为K(i,j)这个点,在for循环里面不能改变,而尾指针需要增加
  26. if q(1) > 1 && q(1) < r+2 && q(2) > 1 && q(2) < c+2
  27. if K1(q(1),q(2)) == 1 && output(q(1)-1,q(2)-1) == 0 %满足点条件
  28. output(q(1)-1,q(2)-1) = label;
  29. s{tail} = q ;%加入队列
  30. tail = tail + 1;
  31. end
  32. end
  33. end
  34. head = head + 1;
  35. end
  36. %
  37. clear s;
  38. label = label + 1;%最后一次label+1,但是并没有使用
  39. head = 1;
  40. tail =1;%恢复原状,以便下次循环使用
  41. end
  42. end
  43. end
  44. label = label - 1;%最后一次label+1没有使用,所以需要减一次
  45. toc
  46. figure
  47. imshow(output)

两步法:

 
  1. clear all;
  2. clc;
  3. s=imread('rice.png');
  4. s = im2bw(s);
  5. [r c]=size(s);
  6. output=zeros(r,c);
  7. label=0; %第一遍遍历时标记的标签数量
  8. s1 = zeros(r+2,c+2);
  9. for i = 2:r+1
  10. for j = 2:c+1
  11. s1(i,j) = s(i-1,j-1);
  12. end
  13. end
  14. imtool(s);
  15. output1 = zeros(r+2,c+2);
  16. pre = zeros(1000);
  17. new_label = zeros(1000);
  18. new_label_count = 1;
  19. %第一次for循环得到下面情况
  20. %对于每个点的4周的情况只有三种:
  21. %1. 4个点全是0 处理方法:label+1,并赋值
  22. %2. (至多4个点)全是一样的label 将周围的label赋值给这个点即可
  23. %3. (至多4个点)有两种label
  24. label赋值为label小的那个,并将这两个label放到同一个数组里面去
  25. %4. (至多4个点)有三种label,这种情况我一开始一直以为是不存在的,直到程序跑出来因为漏掉了这种情况有很多黑点
  26. %对于pre数组来说,pre[label] = label的时候是根节点
  27. for i = 2:r+1 % y
  28. for j = 2:c+1 % x
  29. if s1(i,j) == 1
  30. %查找周围4个点的情况
  31. m = [];%将4个点对应的label值存起来
  32. m = [output1(i-1,j),output1(i-1,j-1),output1(i,j-1),output1(i-1,j+1)];
  33. m = unique(m);
  34. %先去重复,看有没有全是0的情况,没有的话再去0
  35. if length(m) == 1 && m(1) == 0
  36. label = label + 1;
  37. output1(i,j) = label;
  38. pre(label) = label;
  39. else
  40. m(find(m == 0)) = [];
  41. m = sort(m);
  42. %去除数组中的0元素,并讨论是一种label,还是两种label,并将数组排序,方便将两个label放到同一个数组里面
  43. if length(m) == 1
  44. output1(i,j) = m(1);
  45. elseif length(m) == 2
  46. output1(i,j) = m(1);
  47. pre(m(2)) = m(1);%m(2)是子节点 m(1)是父节点
  48. elseif length(m) == 3
  49. output1(i,j) = m(1);
  50. pre(m(2)) = m(1);
  51. pre(m(3)) = m(1);
  52. end
  53. end
  54. end
  55. end
  56. end
  57. for i = 2:r+1
  58. for j = 2:c+1
  59. output(i-1,j-1) = output1(i,j);
  60. end
  61. end
  62. %处理pre数组,new_label给根节点重新编号
  63. for i = 1:1000
  64. if pre(i) ~= 0
  65. %当pre数组的内容不为0的时候
  66. %1.pre[label] = label label为根节点
  67. %2.pre[label] = a labela的父节点,需要寻找a的根节点
  68. if pre(i) ~= i
  69. tmp = i;
  70. while(pre(tmp) ~= tmp)
  71. tmp = pre(tmp);
  72. end
  73. pre(i) = tmp;
  74. else
  75. new_label(i) = new_label_count;
  76. new_label_count = new_label_count + 1;
  77. end
  78. end
  79. end
  80. %需要重新将label编号
  81. for i = 1:r
  82. for j = 1:c
  83. if output(i,j) ~= 0
  84. output(i,j) = new_label(pre(output(i,j)));
  85. end
  86. end
  87. end
  88. imtool (output);
  89. new_label_count = new_label_count - 1;
  90. new_label_count
### 回答1: MATLAB中的bwlabel函数用于将值图像中的连通区域标记为不同的整数值。该函数的语如下: [L, num] = bwlabel(BW, n) 其中,BW值图像,n是可选参数,表示连接方式。默认情况下,n为8,表示8连通。如果n为4,则表示4连通。 函数的输出包括: L:标记后的图像,每个连通区域的像素值都被标记为不同的整数值。 num:连通区域的数量。 例如,下面的代码将对一个值图像进行标记,并输出标记后的图像和连通区域的数量: BW = imread('binary_image.png'); [L, num] = bwlabel(BW); imshow(L); disp(num); 该函数在图像处理中常用于分割图像中的不同区域,或者提取图像中的特定目标。 ### 回答2: Matlab的bwlabel函数是一个值图像处理函数,主要用于获取进制图像中像素连通区域的标签。该函数可以将值图像分割为不同的连通区域,每个连通区域都赋予唯一的标签,标签的值从1开始,依次递增。bwlabel函数的完整语格式如下: [L, num] = bwlabel(BW, N) 其中,BW表示值图像矩阵,N表示像素连通时采用的连接模式,取值范围为4或8。L是一个与BW大小相同的矩阵,存储每个像素的标签,num表示图像中像素连通区域的数量。 bwlabel函数的实现原理是遍历图像中的每个像素,并将像素与其周围的相邻像素进行比较,根据像素值的变化将属于同一连通区域的像素进行标记。标记的方式可以采用广度优先搜索或深度优先搜索。 使用bwlabel函数时,需要注意以下几点: 1.输入图像必须是值图像,即像素值只有0或1,如果是灰度图像需要先进行值化处理; 2.连接模式的选择必须与图像的实际情况相符,通常情况下采用8连通模式进行像素连接; 3.bwlabel函数返回的标签矩阵L是整数类型,每个像素的值对应于其所属连通区域的标签值; 4.如果图像中存在孤立的像素(即像素值为1但未与其他像素相连通),则会将其单独标记为一个连通区域,标签值为2; 总之,Matlab的bwlabel函数在图像分割、目标检测、物体识别等领域有着广泛的应用,可以方便地进行像素连通区域的标记和计数。在使用bwlabel函数时,需要灵活选择连接模式,避免因不正确的连接模式导致分割结果错误。 ### 回答3: MATLAB中bwlabel函数主要用于进制图像中像素连通分量的标记,即将一张值图像中的每个连通区域用不同的数码进行标记,相同的数码表示同属于一个连通分量。 该函数的语格式为: [L, num] = bwlabel(BW, n) 其中,BW表示要进行标记的值图像,n是可选的操作参数,表示要识别的相邻像素的连接性,n可以取值为4或8。L是输出矩阵,它与输入图像大小相同,每个像素与相应地标记连接。num表示值图像中连通分量的数量。 该函数的实现步骤如下: 1. 对于输入的值图像BW,设定标记值count为0,创建一个标记矩阵L,其大小与BW相同。 2. 对于BW中的每个像素点,如果其值为1且其未被标记,则将其视为该连通分量的起始像素,将count+1,并以该count值对该连通分量进行标记。 3. 对于起始像素,使用递归方式进行像素的四向或八向查找,将相邻的像素标记为相同的标记值。在标记完该连通分量后,返回到上一个起始像素,进行下一个连通分量的标记。 4. 返回标记矩阵L和连通分量数量num。 bwlabel函数的使用可以帮助我们进行目标识别、形态分析等操作,是图像处理中非常常用的函数之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值