标记连通分量的意思就是找到二值图中的每一个连通区域,用某种记号标记出来,从而可以确定连通区域的个数,本讲将会介绍关于连通分量的几个函数,从而可以利用matlab找到图中的每一个连通区域。
1. 标记连通分量的函数
[L, n] = bwlabel(bw);
L = bwlabel(bw);
- 其中
bw
代表一张二值图- 返回值
L
是一个和图片的像素大小相同的double型矩阵,bwlabel
会从上到下、从左到右的扫描每一个像素点,将遇到的第一个连通区域的所有像素点对应在矩阵L
上的位置值置为 1 。
依次类推,将第二个连通区域在矩阵上对应的位置的值置为 2 ,最后得到的矩阵就是在连通区域的位置上分布的1,2,3 ······,和其余位置为 0 的矩阵。- 返回值 n 保存图中连通区域的个数,例如下图的箭头图片,返回的 n 的值为 6 。
对下图图片使用该函数得到的矩阵如图:
2. 对图片指定位置做标记
plot(c, r, 'r*');
该函数用来在第 c
列、第 r
行的地方,添加一个红色的 *
,r
代表红色,*
表示用 *
做标记,注意 plot
函数第一个坐标为列值,第二个坐标为行值。
plot
函数使用之前需要加上 hold on;
语句,以保持上一次显示的 figure
,实现在上次显示的 figure
上做标记(详细使用见下例)。
3. 标记箭头
目的:在上面的箭头图的每一个连通区域的重心点处标记红的的 *
思路:首先转换为二值图,然后用 bwlabel
函数作用于二值图,返回关于该图的连通区域坐标矩阵,之后可以用 find
函数分别找到每一个连通区域,使用 plot
函数标记红色的 *
。
步骤:
-
将图片转换为二值图
该步代码为:clear,clc,close all; f=imread('arrow.jpg'); g=rgb2gray(f); bw=imbinarize(g); imshow(bw);
-
用
bwlabel
函数计算图片的连通矩阵,然后这一步用了几个函数用不同的方式显示矩阵。figure,imshow(I, []);
用
imshow
显示矩阵时候,在变量后面加一个参数[ ]
,可以实现将矩阵中的值按比例均匀的转变为0-255
中的值,从而将图片转换为灰度图显示(该句为我的猜测,有了解的老铁可以跟我说说对不对),效果见下图:
新增代码为:[I,n]=bwlabel(bw); figure,imshow(I,[]);
可以在上面的代码后面加入一句
colormap hot;
或colormap cool;
实现给上面邻接的 *figure
中的灰度图加入暖色 或 冷色 伪彩色。下图展示了两种不同的伪彩色。注意,
colormap
是作用于上一个个figure
里的所有图像的,如果用subplot
显示图像,subplot
内的所有图像属于同一个figure
,所有图片均会显示同一种伪彩色。 -
用
for
循环依次查找矩阵中值为 1 到 6 的区域,然后计算出重心的位置,用plot
函数标记。
新增代码为:for i=1:n %for循环的格式 [r,c]=find(I==i); mr=mean(r); %解释见下 mc=mean(c); hold on; %保持上一figure,以使下个函数可以做标记 plot(mc,mr,'r*'); end %for循环的结束
for
循环的格式如上所示,i
是递增变量,初始值为 1 ,每次循环i
加 1 ,循环到值和 n 相同,便结束循环,继续向下执行,每次循环都要执行循环体内的语句。注意,for 循环内的语句需要缩进。
[r,c] = find( I == i ); % 该语句查找矩阵 `I` 中满足值为 `i` 的所有坐标点,然后将横纵坐标相对应保存到 `r` 和 `c` 中
mr = mean(r); %该函数实现从一维矩阵中找到中值,返回给 mr
mc=mean ( c ); %意义同上
hold on; %保持上一figure,以使下个函数 **plot** 可以做标记,可以参考上文的 **plot**函数的解释
本例代码为:
clear,clc,close all; f=imread('arrow.jpg'); g=rgb2gray(f); bw=imbinarize(g); imshow(bw); [I,n]=bwlabel(bw); %显示伪彩色的代码 % figure,imshow(I,[]),title('colormap hot'); % colormap hot; % figure,imshow(I,[]),title('colormap cool'); % colormap cool; for i=1:n [r,c]=find(I==i); mr=mean(r); mc=mean(c); hold on; plot(mc,mr,'r*'); end
4. 数硬币
用红色的 *
在图片的硬币中心标记,然后输出共有多少硬币。
思路:先转化为二值图,然后用 bwlabel
计算出有多少连通区域,用 plot
函数标记,然后在本例中会介绍如何在命令行中输出字符串。
步骤:
-
先把图片转换为二值图
该步代码为:clear,clc,close all; f=imread('coin.jpg'); g=rgb2gray(f); bw=imbinarize(g); imshow(bw);
-
观察上一步的二值图,发现在硬币的中心有许多黑色的小坑洞,这些小坑洞会影响连通区域的标记,因此需要先去除小坑洞。本步介绍一个函数,来去除小坑洞。
bw = imfill(bw, 'holes');
该函数可以去除
bw
图像上白色区域内的小黑洞,让整个连通区域完全连通。该步效果如下:
新增代码为:bw_fill=imfill(bw,'holes'); figure,imshow(bw_fill);
-
用
bwlabel
函数,计算连通区域的矩阵,并获取连通区域的个数,然后用plot
函数标记每个硬币的重心。
本步新增代码为:[I,n]=bwlabel(bw_fill); for i=1:n [r,c]=find(I==i); mr=mean(r); mc=mean(c); hold on; plot(mc,mr,'r*'); end
-
在命令行输出字符串,说明有几个硬币。
s = strcat('str1' , 'str2' , 'str3' ... ); %将参数中的字符串连接为一个,并赋值给 s
display (s); %在命令行中输出字符串 s
s =num2str(n); %该函数的作用为,将数字转换为字符串并返回该字符串
在本例中使用上述函数,输出所得到的图中硬币的个数。
新增代码为:s=strcat('一共有',num2str(n),'个硬币'); %在上面的运行中,n是一个整数,保存的是得到的硬币的个数,因此需要先转换为字符串 display(s);
本例代码为:
clear,clc,close all; f=imread('coin.jpg'); g=rgb2gray(f); bw=imbinarize(g); imshow(bw); bw_fill=imfill(bw,'holes'); figure,imshow(bw_fill); [I,n]=bwlabel(bw_fill); for i=1:n [r,c]=find(I==i); mr=mean(r); mc=mean(c); hold on; plot(mc,mr,'r*'); end s=strcat('一共有',num2str(n),'个硬币'); display(s);