形态学操作

http://www.cnblogs.com/tornadomeet/archive/2012/03/20/2408086.html

关于形态学的实验需要对二值图像进行减噪处理,图像形态学中的腐蚀和膨胀能很好的解决此问题。如果在腐蚀和膨胀操作前,对灰度图像做一次滤波,减噪效果将更明显。
腐蚀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。膨胀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。
腐蚀的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点;膨胀的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的空洞。
开运算是先腐蚀后膨胀的过程,可以消除图像上细小的噪声,并平滑物体边界。
闭运算时先膨胀后腐蚀的过程,可以填充物体内细小的空洞,并平滑物体边界。

MATLAB中基本知识点:

1.对二值化图像进行形态学处理(bwmorph)

函数调用格式:

BW=bwmorph(I,operation);

BW=bwmorph(I,operation,n);

Operation:

‘bothat’:闭包运算,即先腐蚀,在膨胀,然后减去原图像;

‘branchpoints’:找出骨架的分支结点

‘endpoints’:找出骨架端点
‘bridge’:做连接运算;

‘clean’:去除孤立的亮点;

‘close’:进行二值闭运算(先膨胀后腐蚀);

‘diag’:采用对角线填充来去除8邻域的背景;

‘dilate’:采用结构元素ones(3)做膨胀运算;

‘erode’:采用结构元素ones(3)作腐蚀运算; 
‘fill’:填充孤立的黑点;     imfill

‘hbreak’:断开H形连接;

‘Majority’:若像素的8邻域中有大于或等于5的元素为1,则像素为1,否则为0; 
‘open’:执行二值开运算(先腐蚀后膨胀); 
‘remove’:去掉内点,即若像素的4邻域都为1,则像素为0;

‘shrink’n=inf:做收缩运算,这样没有孔的物体收缩为一个点,而含孔的物体收缩为一个相连的环,环的位置在孔和物体外边缘的中间,收缩运算保持欧拉数不变,

‘skel’n=inf: 提取物体的骨架,即去除物体外边缘的点,但是保持物体不发生断裂,它也保持欧拉数不变。 

‘spur’:去除物体小的分支; 
‘thicken’n=inf;对物体进行粗化,即对物体的外边缘增加像素,知道原来为连接的物体按照8邻域被连接起来。粗化保持欧拉数不变。 
‘thin’n=inf:对物体进行细化,使得没有孔的物体收缩为最小连接棒,而含有孔的物体收缩为一个连接的环,同样细化保持欧拉数不变。

‘tophat’:用原图减去开运算后的图像;

2. matlab函数bwareaopen──删除小面积对象
格式:BW2 bwareaopen(BW,P,conn)
作用:删除二值图像BW中面积小于P的对象,默认情况下使用8邻域。

算法
(1)Determine the connected components.
  bwlabeln(BW, conn); %标记连通域
(2)Compute the area of each component.
  regionprops(L, 'Area');  %计算连通域面积
(3)Remove small objects.
  bw2 ismember(L, find([S.Area] >= P)); %删除面积大于等于p的连通域

3.matlab函数bwarea──计算对象面积
格式:total bwarea(BW)
作用:估计二值图像中对象的面积。
注:该面积和二值图像中对象的像素数目不一定相等。

3、matlab函数imclearborder──边界对象抑制
格式:IM2 imclearborder(IM,conn)
作用:抑制和图像边界相连的亮对象。若IM是二值图,imclearborder将删除和图像边界相连的对象。默认情况conn=8。
注:For grayscale images, imclearborder tends to reduce the overall intensity level in addition to suppressing border structures.
算法:
(1)Mask image is the input image.
(2)Marker image is zero everywhere except along the border, where it equals the mask image.
4、matlab函数bwboundaries──获取对象轮廓
格式:B bwboundaries(BW,conn)(基本格式)
作用:获取二值图中对象的轮廓,和OpenCV中cvFindContours函数功能类似。B是一个P×1的cell数组,P为对象个数,每个cell 是Q×2的矩阵,对应于对象轮廓像素的坐标。
5、matlab函数imregionalmin──获取极小值区域
格式:BW imregionalmin(I,conn)
作用:寻找图像I的极小值区域(regional maxima),默认情况conn=8。
Regional minima are connected components of pixels with constant intensity value, and whose external boundary pixels all have higher value.
6、matlab函数bwulterode──距离变换的极大值
格式:BW2 bwulterode(BW,method,conn)
作用:终极腐蚀。寻找二值图像BW的距离变换图的区域极大值(regional maxima)。用于距离变换的距离默认为euclidean,连通性为8邻域。
7、regionprops统计被标记的区域的面积分布,显示区域总数。
函数regionprops语法规则为:STATS regionprops(L,properties)
该函数用来测量标注矩阵L中每一个标注区域的一系列属性。
L中不同的正整数元素对应不同的区域,例如:L中等于整数1的元素对应区域1;L中等于整数2的元素对应区域2;以此类推。
返回值STATS是一个 长度为max(L(:))的结构数组,结构数组的相应域定义了每一个区域相应属性下的度量。
Properties可以是由逗号分割的字符串列表、包含字符 串的单元数组、单个字符串'all'或者'basic'。如果properties等于字符串'all',则表4.1中的度量数据都将被计算;如果properties等于字符串'basic',则属性:'Area','Centroid'和'BoundingBox'将被计算。表1就是所有有效的属性字符串。
属性字符串列表----度量图像区域的属性或功能
'Area' 图像各个区域中像素总个数
'BoundingBox'  包含相应区域的最小矩形
'Centroid' 每个区域的质心(重心)
'MajorAxisLength' 与区域具有相同标准二阶中心矩的椭圆的长轴长度(像素意义下)
'MinorAxisLength' 与区域具有相同标准二阶中心矩的椭圆的短轴长度(像素意义下)
'Eccentricity' 与区域具有相同标准二阶中心矩的椭圆的离心率(可作为特征)
'Orientation' 与区域具有相同标准二阶中心矩的椭圆的长轴与x轴的交角(度)
'Image' 与某区域具有相同大小的逻辑矩阵
'FilledImage' 与某区域具有相同大小的填充逻辑矩阵
'FilledArea' 填充区域图像中的on像素个数
'ConvexHull' 包含某区域的最小凸多边形
'ConvexImage' 画出上述区域最小凸多边形
'ConvexArea'   填充区域凸多边形图像中的on像素个数
'EulerNumber' 几何拓扑中的一个拓扑不变量——欧拉数
'Extrema' 八方向区域极值点
'EquivDiameter' 与区域具有相同面积的圆的直径
'Solidity' 同时在区域和其最小凸多边形中的像素比例
'Extent' 同时在区域和其最小边界矩形中的像素比例
'PixelIdxList' 存储区域像素的索引下标
'PixelList' 存储上述索引对应的像素坐标

提醒

使用逗号分割列表语法:当你基于regionprops函数的输出作算法设计时,使用逗号分割列表语法就凸显出其非常的价值。例如:对于一个存储标量的属性,可以利用此语法创建一个包含图像中不同区域内此属性值的向量。例如以下两句是等价的:

stats(1).Area, stats(2).Area, ..., stats(end).Area

stats.Area

因此,可以使用下面的方法创建相应的向量:

regionprops(L,'Area'); allArea [stats.Area];

allArea 就是一个与结构数组 stats 具备相同长度的向量。

基于特定原则的区域选择:当你要基于特定准则条件选择某个区域时,将函数 ismember 和 regionprops 联合使用是很有用处的。例如:创建一个只包含面积大于80的二值图像,用以下命令

idx find([stats.Area] 80); BW2 ismember(L,idx);

计算性能考虑:大多数的属性测量计算时间都非常地少,除了那些非常依赖于图像L中区域个数和像素个数的属性。例如:

'ConvexHull' 'ConvexImage' 'ConvexArea' 'FilledImage'

另外建议一次性计算所有属性值,因为分开计算和一起计算时间相差无几!

使用二值图像工作:在调用regionprops之前必须将二值图像转变为标注矩阵。两个函数可以做到:

bwlabel(BW); double(BW);

注意:虽然这两个函数从同一二值图像产生不同的标注矩阵,但是它们是等效的!例如:给出如下的二值矩阵BW,

1

bwlabel 创建一个包含两个分别由整数1和2标注的连续区域标注矩阵

mylabel bwlabel(BW)

 mylabel 2

double 创建一个包含一个由整数1标注的不连续区域标注矩阵。

mylabel2 double(BW) 

mylabel2 1

regionprops 并不负责自动转换二值图像数据类型,而是由你自己决定使用何种数据转换方法来存储自己想要的数据。

regionprops函数的扩展思路:在regionprops函数的基础上,你可以使用它提供的基本数据来扩展它的功能,将区域的曲率数据和骨架数据作为它的另外属性值来开发,从而希望

它能用来做更细致的特征提取。

%% imdilate膨胀
clc
clear

A1=imread('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif');
info=imfinfo('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif')
B=[0 1 0
   1 1 1
   0 1 0];
A2=imdilate(A1,B);%图像A1被结构元素B膨胀
A3=imdilate(A2,B);
A4=imdilate(A3,B);

subplot(221),imshow(A1);
title('imdilate膨胀原始图像');

subplot(222),imshow(A2);
title('使用B后1次膨胀后的图像');

subplot(223),imshow(A3);
title('使用B后2次膨胀后的图像');

subplot(224),imshow(A4);
title('使用B后3次膨胀后的图像');
%imdilate图像膨胀处理过程运行结果如下:
<img src="https://img-blog.csdn.net/20150511101157664?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% imerode腐蚀
clc
clear
A1=imread('.\images\dipum_images_ch09\Fig0908(a)(wirebond-mask).tif');
subplot(221),imshow(A1);
title('腐蚀原始图像');

%strel函数的功能是运用各种形状和大小构造结构元素
se1=strel('disk',5);%这里是创建一个半径为5的平坦型圆盘结构元素
A2=imerode(A1,se1);
subplot(222),imshow(A2);
title('使用结构原始disk(5)腐蚀后的图像');

se2=strel('disk',10);
A3=imerode(A1,se2);
subplot(223),imshow(A3);
title('使用结构原始disk(10)腐蚀后的图像');

se3=strel('disk',20);
A4=imerode(A1,se3);
subplot(224),imshow(A4);
title('使用结构原始disk(20)腐蚀后的图像');
%图像腐蚀处理过程运行结果如下:
<img src="https://img-blog.csdn.net/20150511101025028?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% 开运算和闭运算
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0910(a)(shapes).tif');
%se=strel('square',5');%方型结构元素
se=strel('disk',5');%圆盘型结构元素
imshow(f);%原图像
title('开闭运算原始图像')
%运行结果如下:
<img src="https://img-blog.csdn.net/20150511101045230?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%开运算数学上是先腐蚀后膨胀的结果
%开运算的物理结果为完全删除了不能包含结构元素的对象区域,平滑
%了对象的轮廓,断开了狭窄的连接,去掉了细小的突出部分
fo=imopen(f,se);%直接开运算
figure,subplot(221),imshow(fo);
title('直接开运算');

%闭运算在数学上是先膨胀再腐蚀的结果
%闭运算的物理结果也是会平滑对象的轮廓,但是与开运算不同的是,闭运算
%一般会将狭窄的缺口连接起来形成细长的弯口,并填充比结构元素小的洞
fc=imclose(f,se);%直接闭运算
subplot(222),imshow(fc);
title('直接闭运算');

foc=imclose(fo,se);%先开后闭运算
subplot(223),imshow(foc);
title('先开后闭运算');

fco=imopen(fc,se);%先闭后开运算
subplot(224),imshow(fco);
title('先闭后开运算');
%开闭运算结果如下:
<img src="https://img-blog.csdn.net/20150511101101345?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%先膨胀再腐蚀
fse=imdilate(f,se);%膨胀

%gcf为得到当前图像的句柄,当前图像是指例如PLOT,TITLE,SURF等
%get函数为得到物体的属性,get(0,'screensize')为返回所有物体screensize属性值
%set函数为设置物体的属性
figure,set(gcf,'outerposition',get(0,'screensize'));%具体目的是设置当前窗口的大小
subplot(211),imshow(fse);
title('使用disk(5)先膨胀后的图像');

fes=imerode(fse,se);
subplot(212),imshow(fes);
title('使用disk(5)先膨胀再腐蚀后的图像');
%先膨胀后腐蚀图像如下:
<img src="https://img-blog.csdn.net/20150511101316569?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%先腐蚀再膨胀
fse=imerode(f,se);
figure,set(gcf,'outerposition',get(0,'screensize'))
subplot(211),imshow(fse);
title('使用disk(5)先腐蚀后的图像');

fes=imdilate(fse,se);
subplot(212),imshow(fes);
title('使用disk(5)先腐蚀再膨胀后的图像');
%先腐蚀后膨胀的图像如下:
<img src="https://img-blog.csdn.net/20150511101331576?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% imopen imclose在指纹上的应用
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');
se=strel('square',3);%边长为3的方形结构元素
subplot(121),imshow(f);
title('指纹原始图像');

A=imerode(f,se);%腐蚀
subplot(122),imshow(A);
title('腐蚀后的指纹原始图像');
%指纹原始图像和腐蚀后的图像结果如下:
<img src="https://img-blog.csdn.net/20150511101349765?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
fo=imopen(f,se);
figure,subplot(221),imshow(fo);
title('使用square(3)开操作后的图像');

fc=imclose(f,se);
subplot(222),imshow(fc);
title('使用square闭操作后的图像');

foc=imclose(fo,se);
subplot(223),imshow(foc);
title('使用square(3)先开后闭操作后的图像')

fco=imopen(fc,se);
subplot(224),imshow(fco);
title('使用square(3)先闭后开操作后的图像');
%指纹图像开闭操作过程结果如下:
<img src="https://img-blog.csdn.net/20150511101217629?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% bwhitmiss击中或击不中变换
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0913(a)(small-squares).tif');
imshow(f);
title('击中或不击中原始图像');
%击中或不击中原始图像显示结果如下:
<img src="https://img-blog.csdn.net/20150511101425458?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
B1=strel([0 0 0;0 1 1;0 1 0]);%击中:要求击中所有1的位置
B2=strel([1 1 1;1 0 0;1 0 0]);%击不中,要求击不中所有1的位置
B3=strel([0 1 0;1 1 1;0 1 0]);%击中
B4=strel([1 0 1;0 0 0;0 0 0]);%击不中
B5=strel([0 0 0;0 1 0;0 0 0]);%击中
B6=strel([1 1 1;1 0 0;1 0 0]);%击不中

g=imerode(f,B1)&imerode(~f,B2)%利用定义来实现击中或击不中
figure,subplot(221),imshow(g);
title('定义实现组1击中击不中图像');

g1=bwhitmiss(f,B1,B2);
subplot(222),imshow(g1);
title('结构数组1击中击不中后的图像');

g2=bwhitmiss(f,B3,B4);
subplot(223),imshow(g2);
title('结构数组2击中击不中的图像');

g3=bwhitmiss(f,B5,B6);
subplot(224),imshow(g3);
title('结构数组3击中击不中的图像');
%击中击不中变换后图像如下:
<img src="https://img-blog.csdn.net/20150511101443648?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%%makelut
clc
clear

f=inline('sum(x(:))>=3');%inline是用来定义局部函数的
lut2=makelut(f,2)%为函数f构造一个接收2*2矩阵的查找表
lut3=makelut(f,3)

%% Conway生命游戏
clc
clear
lut=makelut(@conwaylaws,3);
bw1=  [0     0     0     0     0     0     0     0     0     0
       0     0     0     0     0     0     0     0     0     0
       0     0     0     1     0     0     1     0     0     0
       0     0     0     1     1     1     1     0     0     0
       0     0     1     0     0     0     0     1     0     0
       0     0     1     0     1     1     0     1     0     0
       0     0     1     0     0     0     0     1     0     0
       0     0     0     1     1     1     1     0     0     0
       0     0     0     0     0     0     0     0     0     0
       0     0     0     0     0     0     0     0     0     0  ];
subplot(221),imshow(bw1,'InitialMagnification','fit');
title('Generation 1');

bw2=applylut(bw1,lut);
subplot(222),imshow(bw2,'InitialMagnification','fit'),
title('Generation 2');

bw3=applylut(bw2,lut);
subplot(223),imshow(bw3,'InitialMagnification','fit');
title('Generation 3');

temp=bw1;
for i=2:100
    bw100=applylut(temp,lut);
    temp=bw100;
end
subplot(224),imshow(bw100,'InitialMagnification','fit')
title('Generation 100');
%显示Generation结果如下:
<img src="https://img-blog.csdn.net/20150511101505488?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% getsequence
clc
clear
se=strel('diamond',5)
decomp=getsequence(se)%getsequence函数为得到分解的strel序列
decomp(1)
decomp(2)

%% endpoints
clc
clear

f1=imread('.\images\dipum_images_ch09\Fig0914(a)(bone-skel).tif');
subplot(121),imshow(f1);
title('原始形态骨架图像');

g1=endpoints(f1);
%set(gcf,'outerposition',get(0,'screensize'));%运行完后自动生成最大的窗口
subplot(122),imshow(g1);
title('骨架图像的端点图像');
<img src="https://img-blog.csdn.net/20150511101524941?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%骨架头像端点检测头像如下:
f2=imread('.\images\dipum_images_ch09\Fig0916(a)(bone).tif');
figure,subplot(121),imshow(f2);
title('原始骨头图像');

g2=endpoints(f2);
subplot(122),imshow(g2);
title('骨头图像端点头像');%结果是没有端点
%骨头头像端点检测图像如下:
<img src="https://img-blog.csdn.net/20150511101352134?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% bwmorph组合常见形态学之细化
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');
subplot(221),imshow(f);
title('指纹图像细化原图');

g1=bwmorph(f,'thin',1);
subplot(222),imshow(g1);
title('指纹图像细化原图');

g2=bwmorph(f,'thin',2);
subplot(223),imshow(g2);
title('指纹图像细化原图');

g3=bwmorph(f,'thin',Inf);
subplot(224),imshow(g3);
title('指纹图像细化原图');
%指纹图像细化过程显示如下:
<img src="https://img-blog.csdn.net/20150511101604674?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% bwmorph组合常见形态学之骨骼化
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');
subplot(131),imshow(f);
title('指纹图像骨骼化原图');

fs=bwmorph(f,'skel',Inf);
subplot(132),imshow(fs);
title('指纹图像骨骼化');

for k=1:5
    fs=fs&~endpoints(fs);
end
subplot(133),imshow(fs);
title('指纹图像修剪后骨骼话');
%指纹图像骨骼化过程显示:
<img src="https://img-blog.csdn.net/20150511101625126?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% 使用函数bwlabel标注连通分量
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0917(a)(ten-objects).tif');
imshow(f),title('标注连通分量原始图像');
%其结果显示如下:
<img src="https://img-blog.csdn.net/20150511101453130?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
[L,n]=bwlabel(f);%L为标记矩阵,n为找到连接分量的总数
[r,c]=find(L==3);%返回第3个对象所有像素的行索引和列索引

rbar=mean(r);
cbar=mean(c);

figure,imshow(f)
hold on%保持当前图像使其不被刷新
for k=1:n
    [r,c]=find(L==k);
    rbar=mean(r);
    cbar=mean(c);
    plot(cbar,rbar,'Marker','o','MarkerEdgeColor','k',...
         'MarkerFaceColor','k','MarkerSize',10);%这个plot函数用法不是很熟悉
    plot(cbar,rbar,'Marker','*','MarkerFaceColor','w');%其中的marker为标记
end
title('标记所有对象质心后的图像');
<img src="https://img-blog.csdn.net/20150511101702129?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% 由重构做开运算
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0922(a)(book-text).tif');
subplot(321),imshow(f);
title('重构原始图像');

fe=imerode(f,ones(51,1));%竖线腐蚀
subplot(322),imshow(fe);
title('使用竖线腐蚀后的结果');

fo=imopen(f,ones(51,1));%竖线做开运算
subplot(323),imshow(fo);
title('使用竖线做开运算结果');

fobr=imreconstruct(fe,f);%fe做标记
subplot(324),imshow(fobr);
title('使用竖线做重构开运算');

ff=imfill(f,'holes');%对f进行孔洞填充
subplot(325),imshow(ff);
title('对f填充孔洞后的图像');

fc=imclearborder(f,8);%清除边界,2维8邻接
subplot(326),imshow(fc);
title('对f清除边界后的图像');
%图像重构过程显示如下:
<img src="https://img-blog.csdn.net/20150511101524392?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% 使用顶帽变换和底帽变换
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0926(a)(rice).tif');
subplot(221),imshow(f);
title('顶帽底帽变换原始图像');

se=strel('disk',10);%产生结构元素
%顶帽变换是指原始图像减去其开运算的图像
%而开运算可用于补偿不均匀的背景亮度,所以用一个大的结构元素做开运算后
%然后用原图像减去这个开运算,就得到了背景均衡的图像,这也叫做是图像的顶帽运算
f1=imtophat(f,se);%使用顶帽变换
subplot(222),imshow(f1);
title('使用顶帽变换后的图像');

%底帽变换是原始图像减去其闭运算后的图像
f2=imbothat(imcomplement(f),se);%使用底帽变换,为什么原图像要求补呢?
%f2=imbothat(f,se);%使用底帽变换
subplot(223),imshow(f2);
title('使用底帽变换后的图像');

%顶帽变换和底帽变换联合起来用,用于增加对比度
f3=imsubtract(imadd(f,imtophat(f,se)),imbothat(f,se));%里面参数好像不合理?
subplot(224),imshow(f3);
title('使用顶帽底帽联合变换后图像');
%顶帽底帽变换过程图像如下:
<img src="https://img-blog.csdn.net/20150511101541786?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%%使用开运算和闭运算做形态学平滑
%由于开运算可以除去比结构元素更小的明亮细节,闭运算可以除去比结构元素更小的暗色细节
%所以它们经常组合起来一起进行平滑图像并去除噪声
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif');
subplot(221),imshow(f);
title('木钉图像原图');

se=strel('disk',5);%disk其实就是一个八边形
fo=imopen(f,se);%经过开运算
subplot(222),imshow(f);
title('使用半径5的disk开运算后的图像');

foc=imclose(fo,se);
subplot(223),imshow(foc);
title('先开后闭的图像');

fasf=f;
for i=2:5
    se=strel('disk',i);
    fasf=imclose(imopen(fasf,se),se);
end
subplot(224),imshow(fasf);
title('使用开闭交替滤波后图像');
%使用开运算和闭运算做形态学平滑结果如下:
<img src="https://img-blog.csdn.net/20150511101753750?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% 颗粒分析
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif');

sumpixels=zeros(1,36);
for k=0:35
    se=strel('disk',k);
    fo=imopen(f,se);
    sumpixels(k+1)=sum(fo(:));
end

%可以看到,连续开运算之间的表面积会减少
plot(0:35,sumpixels),xlabel('k'),ylabel('surface area');
title('表面积和结构元素半径之间的关系');
%其运算结果如下:   
<img src="https://img-blog.csdn.net/20150511102014946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
figure,plot(-diff(sumpixels));%diff()函数为差分或者近似倒数,即相邻2个之间的差值
xlabel('k'),ylabel('surface area reduction');
title('减少的表面积和结构元素半径之间的关系');
%其运算结果如下:
<img src="https://img-blog.csdn.net/20150511102031341?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
%% 使用重构删除复杂图像的背景
clc
clear
f=imread('.\images\dipum_images_ch09\Fig0930(a)(calculator).tif');
subplot(221),imshow(f);
title('灰度级重构原图像');

f_obr=imreconstruct(imerode(f,ones(1,71)),f);
subplot(222),imshow(f_obr);
title('经开运算重构图');

f_o=imopen(f,ones(1,71));
subplot(223),imshow(f_o);
title('经开运算后图');

f_thr=imsubtract(f,f_obr);
subplot(224),imshow(f_thr);
title('顶帽运算重构图')
%使用重构删除复杂图像的背景1:
<img src="https://img-blog.csdn.net/20150511101729692?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
f_th=imsubtract(f,f_o)
figure,subplot(221),imshow(f_th);
title('经顶帽运算图');

g_obr=imreconstruct(imerode(f_thr,ones(1,11)),f_thr);
subplot(222),imshow(g_obr);
title('用水平线对f_thr经开运算后重构图');

g_obrd=imdilate(g_obr,ones(1,2));
subplot(223),imshow(g_obrd);
title('使用水平线对上图进行膨胀');

f2=imreconstruct(min(g_obrd,f_thr),f_thr);
subplot(224),imshow(f2);
title('最后的重构结果');
%使用重构删除复杂图像的背景2:
<img src="https://img-blog.csdn.net/20150511101757132?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
其中代码实现部分特别详细:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值