-
数字形态学-QRS波中的R波检测
2019-07-06 11:30:53数学形态学最基本的概念是结构元素,它本身具有一定的形态(如点、线段和圆等),相当于一个`探针’, 在图形中不断地移动结构元素,便可考察出图形各部分间的关系,类似于人的注意焦点(focus of attention,FOA)视觉...数学形态学-QRS波的R波检测
**数学形态法原理
数学形态学是一门建立在严格数学理论基础上的学科,它提供了一种有效的非线性信号处理方法,可以很好地保持信号的几何信息。数学形态学最基本的概念是结构元素,它本身具有一定的形态(如点、线段和圆等),相当于一个`探针’,
在图形中不断地移动结构元素,便可考察出图形各部分间的关系,类似于人的注意焦点(focus of attention,FOA)视觉特点,结构元素可直接携带图形知识(形态、大小等)。用不同的结构元素来处理一维信号可以得出不同的结果.[1]
腐蚀和膨胀是数学形态学中最基本的运算,其定义如下:
设信号序列 f 为定义在 F={0,1,…,N-1}上的序列函数,结构元素 k 为定义在 K={0,1,…,M-1}上的函数,其中 N>M,那么结构元素 k 对信号 f 的腐蚀运算可以定义为:
其中 m=0,1,…,N-M。结构元素 k 对信号 f 的膨胀运算可以定义为:
其中 m=M-1,M-2,…,N-1。信号 f 被膨胀的结果就是把结构元素 k 平移后使集合 K 与集合 F 交集非空点构成的集合,其作用效果是集合 F 呈现出的图像扩大了。而腐蚀的结果就是把结构元素 k 平移后,使集合 K 包含于集合 F 交集所有点构成的集合,其作用效果是使集合 F 呈现出的图像缩小。
膨胀和腐蚀运算还可以组成开(opening,)、闭(closing,•)、击中、薄化、厚化等几种运算方式。其中开(opening,)、闭(closing,•)的定义为:
- 数学形态学理论认为,开运算和闭运算分别是在信号的下方和上方移动结构元素。开运算可以削除信号“波峰”,具有收缩性,消除信号孤立点,抑制正脉冲噪声,使信号光滑;闭运算则可以填充信号的“波谷”,具有扩张性,可抑制负脉冲噪声。开闭运算均具有低通特性。
**利用数学形态学处理心电信号
1、选取合适的结构元g;
2、利用PV和VE产生一种新的信号,记为PVE信号;
3、利用简单的幅度或斜率阈值对PVE信号进行判断;
结构元选取线性结构,然后利用公式算法在matlab里面编写算法。数学形态学可以将QRS中的高大T波滤除,也可以抑制基线漂移。只不过他也会将高频信号放大,造成干扰。接下来就是整个处理结果展示。
T波较大信号以及滤波后的结果:
基线漂移比较严重的信号以及处理结果:
直接设置幅度阈值,利用峰值检测R波:
附上下载matlab程序连接:https://download.csdn.net/download/sjidqh/11289411 -
最全面的图像形态学处理
2013-12-26 15:00:55本章的练习主要是形态学的一些基本概念和技术,这些构成了一组提取图像特征的有力工具,针对二值图像和灰度图像的腐蚀、膨胀和重构的基本操作可以组合使用,以执行非常宽泛的任务。其练习代码和结果如下: 1 %% ...本章的练习主要是形态学的一些基本概念和技术,这些构成了一组提取图像特征的有力工具,针对二值图像和灰度图像的腐蚀、膨胀和重构的基本操作可以组合使用,以执行非常宽泛的任务。其练习代码和结果如下:
1 %% 第9章 形态学处理 2 3 %% imdilate膨胀 4 clc 5 clear 6 7 A1=imread('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif'); 8 info=imfinfo('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif') 9 B=[0 1 0 10 1 1 1 11 0 1 0]; 12 A2=imdilate(A1,B);%图像A1被结构元素B膨胀 13 A3=imdilate(A2,B); 14 A4=imdilate(A3,B); 15 16 subplot(221),imshow(A1); 17 title('imdilate膨胀原始图像'); 18 19 subplot(222),imshow(A2); 20 title('使用B后1次膨胀后的图像'); 21 22 subplot(223),imshow(A3); 23 title('使用B后2次膨胀后的图像'); 24 25 subplot(224),imshow(A4); 26 title('使用B后3次膨胀后的图像'); 27%imdilate图像膨胀处理过程运行结果如下:
28 29 %% imerode腐蚀 30 clc 31 clear 32 A1=imread('.\images\dipum_images_ch09\Fig0908(a)(wirebond-mask).tif'); 33 subplot(221),imshow(A1); 34 title('腐蚀原始图像'); 35 36 %strel函数的功能是运用各种形状和大小构造结构元素 37 se1=strel('disk',5);%这里是创建一个半径为5的平坦型圆盘结构元素 38 A2=imerode(A1,se1); 39 subplot(222),imshow(A2); 40 title('使用结构原始disk(5)腐蚀后的图像'); 41 42 se2=strel('disk',10); 43 A3=imerode(A1,se2); 44 subplot(223),imshow(A3); 45 title('使用结构原始disk(10)腐蚀后的图像'); 46 47 se3=strel('disk',20); 48 A4=imerode(A1,se3); 49 subplot(224),imshow(A4); 50 title('使用结构原始disk(20)腐蚀后的图像'); 51 %图像腐蚀处理过程运行结果如下: 52
53 %% 开运算和闭运算 54 clc 55 clear 56 f=imread('.\images\dipum_images_ch09\Fig0910(a)(shapes).tif'); 57 %se=strel('square',5');%方型结构元素 58 se=strel('disk',5');%圆盘型结构元素 59 imshow(f);%原图像 60 title('开闭运算原始图像') 61%运行结果如下:
62 63 %开运算数学上是先腐蚀后膨胀的结果 64 %开运算的物理结果为完全删除了不能包含结构元素的对象区域,平滑 65 %了对象的轮廓,断开了狭窄的连接,去掉了细小的突出部分 66 fo=imopen(f,se);%直接开运算 67 figure,subplot(221),imshow(fo); 68 title('直接开运算'); 69 70 %闭运算在数学上是先膨胀再腐蚀的结果 71 %闭运算的物理结果也是会平滑对象的轮廓,但是与开运算不同的是,闭运算 72 %一般会将狭窄的缺口连接起来形成细长的弯口,并填充比结构元素小的洞 73 fc=imclose(f,se);%直接闭运算 74 subplot(222),imshow(fc); 75 title('直接闭运算'); 76 77 foc=imclose(fo,se);%先开后闭运算 78 subplot(223),imshow(foc); 79 title('先开后闭运算'); 80 81 fco=imopen(fc,se);%先闭后开运算 82 subplot(224),imshow(fco); 83 title('先闭后开运算'); 84%开闭运算结果如下:
85 86 %先膨胀再腐蚀 87 fse=imdilate(f,se);%膨胀 88 89 %gcf为得到当前图像的句柄,当前图像是指例如PLOT,TITLE,SURF等 90 %get函数为得到物体的属性,get(0,'screensize')为返回所有物体screensize属性值 91 %set函数为设置物体的属性 92 figure,set(gcf,'outerposition',get(0,'screensize'));%具体目的是设置当前窗口的大小 93 subplot(211),imshow(fse); 94 title('使用disk(5)先膨胀后的图像'); 95 96 fes=imerode(fse,se); 97 subplot(212),imshow(fes); 98 title('使用disk(5)先膨胀再腐蚀后的图像'); 99%先膨胀后腐蚀图像如下:
100 101 %先腐蚀再膨胀 102 fse=imerode(f,se); 103 figure,set(gcf,'outerposition',get(0,'screensize')) 104 subplot(211),imshow(fse); 105 title('使用disk(5)先腐蚀后的图像'); 106 107 fes=imdilate(fse,se); 108 subplot(212),imshow(fes); 109 title('使用disk(5)先腐蚀再膨胀后的图像'); 110%先腐蚀后膨胀的图像如下:
111 112 %% imopen imclose在指纹上的应用 113 clc 114 clear 115 f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif'); 116 se=strel('square',3);%边长为3的方形结构元素 117 subplot(121),imshow(f); 118 title('指纹原始图像'); 119 120 A=imerode(f,se);%腐蚀 121 subplot(122),imshow(A); 122 title('腐蚀后的指纹原始图像'); 123%指纹原始图像和腐蚀后的图像结果如下:
124 125 fo=imopen(f,se); 126 figure,subplot(221),imshow(fo); 127 title('使用square(3)开操作后的图像'); 128 129 fc=imclose(f,se); 130 subplot(222),imshow(fc); 131 title('使用square闭操作后的图像'); 132 133 foc=imclose(fo,se); 134 subplot(223),imshow(foc); 135 title('使用square(3)先开后闭操作后的图像') 136 137 fco=imopen(fc,se); 138 subplot(224),imshow(fco); 139 title('使用square(3)先闭后开操作后的图像'); 140%指纹图像开闭操作过程结果如下:
141 142 %% bwhitmiss击中或击不中变换 143 clc 144 clear 145 f=imread('.\images\dipum_images_ch09\Fig0913(a)(small-squares).tif'); 146 imshow(f); 147 title('击中或不击中原始图像'); 148%击中或不击中原始图像显示结果如下:
149 150 B1=strel([0 0 0;0 1 1;0 1 0]);%击中:要求击中所有1的位置 151 B2=strel([1 1 1;1 0 0;1 0 0]);%击不中,要求击不中所有1的位置 152 B3=strel([0 1 0;1 1 1;0 1 0]);%击中 153 B4=strel([1 0 1;0 0 0;0 0 0]);%击不中 154 B5=strel([0 0 0;0 1 0;0 0 0]);%击中 155 B6=strel([1 1 1;1 0 0;1 0 0]);%击不中 156 157 g=imerode(f,B1)&imerode(~f,B2)%利用定义来实现击中或击不中 158 figure,subplot(221),imshow(g); 159 title('定义实现组1击中击不中图像'); 160 161 g1=bwhitmiss(f,B1,B2); 162 subplot(222),imshow(g1); 163 title('结构数组1击中击不中后的图像'); 164 165 g2=bwhitmiss(f,B3,B4); 166 subplot(223),imshow(g2); 167 title('结构数组2击中击不中的图像'); 168 169 g3=bwhitmiss(f,B5,B6); 170 subplot(224),imshow(g3); 171 title('结构数组3击中击不中的图像'); 172%击中击不中变换后图像如下:
173 174 %%makelut 175 clc 176 clear 177 178 f=inline('sum(x(:))>=3');%inline是用来定义局部函数的 179 lut2=makelut(f,2)%为函数f构造一个接收2*2矩阵的查找表 180 lut3=makelut(f,3) 181 182 %% Conway生命游戏 183 clc 184 clear 185 lut=makelut(@conwaylaws,3); 186 bw1= [0 0 0 0 0 0 0 0 0 0 187 0 0 0 0 0 0 0 0 0 0 188 0 0 0 1 0 0 1 0 0 0 189 0 0 0 1 1 1 1 0 0 0 190 0 0 1 0 0 0 0 1 0 0 191 0 0 1 0 1 1 0 1 0 0 192 0 0 1 0 0 0 0 1 0 0 193 0 0 0 1 1 1 1 0 0 0 194 0 0 0 0 0 0 0 0 0 0 195 0 0 0 0 0 0 0 0 0 0 ]; 196 subplot(221),imshow(bw1,'InitialMagnification','fit'); 197 title('Generation 1'); 198 199 bw2=applylut(bw1,lut); 200 subplot(222),imshow(bw2,'InitialMagnification','fit'), 201 title('Generation 2'); 202 203 bw3=applylut(bw2,lut); 204 subplot(223),imshow(bw3,'InitialMagnification','fit'); 205 title('Generation 3'); 206 207 temp=bw1; 208 for i=2:100 209 bw100=applylut(temp,lut); 210 temp=bw100; 211 end 212 subplot(224),imshow(bw100,'InitialMagnification','fit') 213 title('Generation 100'); 214%显示Generation结果如下:
215 216 %% getsequence 217 clc 218 clear 219 se=strel('diamond',5) 220 decomp=getsequence(se)%getsequence函数为得到分解的strel序列 221 decomp(1) 222 decomp(2) 223 224 %% endpoints 225 clc 226 clear 227 228 f1=imread('.\images\dipum_images_ch09\Fig0914(a)(bone-skel).tif'); 229 subplot(121),imshow(f1); 230 title('原始形态骨架图像'); 231 232 g1=endpoints(f1); 233 %set(gcf,'outerposition',get(0,'screensize'));%运行完后自动生成最大的窗口 234 subplot(122),imshow(g1); 235 title('骨架图像的端点图像'); 236 %骨架头像端点检测头像如下: 237 238 f2=imread('.\images\dipum_images_ch09\Fig0916(a)(bone).tif'); 239 figure,subplot(121),imshow(f2); 240 title('原始骨头图像'); 241 242 g2=endpoints(f2); 243 subplot(122),imshow(g2); 244 title('骨头图像端点头像');%结果是没有端点 245%骨头头像端点检测图像如下:
246 247 %% bwmorph组合常见形态学之细化 248 clc 249 clear 250 f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif'); 251 subplot(221),imshow(f); 252 title('指纹图像细化原图'); 253 254 g1=bwmorph(f,'thin',1); 255 subplot(222),imshow(g1); 256 title('指纹图像细化原图'); 257 258 g2=bwmorph(f,'thin',2); 259 subplot(223),imshow(g2); 260 title('指纹图像细化原图'); 261 262 g3=bwmorph(f,'thin',Inf); 263 subplot(224),imshow(g3); 264 title('指纹图像细化原图'); 265%指纹图像细化过程显示如下:
266 267 %% bwmorph组合常见形态学之骨骼化 268 clc 269 clear 270 f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif'); 271 subplot(131),imshow(f); 272 title('指纹图像骨骼化原图'); 273 274 fs=bwmorph(f,'skel',Inf); 275 subplot(132),imshow(fs); 276 title('指纹图像骨骼化'); 277 278 for k=1:5 279 fs=fs&~endpoints(fs); 280 end 281 subplot(133),imshow(fs); 282 title('指纹图像修剪后骨骼话'); 283%指纹图像骨骼化过程显示:
284 285 %% 使用函数bwlabel标注连通分量 286 clc 287 clear 288 f=imread('.\images\dipum_images_ch09\Fig0917(a)(ten-objects).tif'); 289 imshow(f),title('标注连通分量原始图像'); 290%其结果显示如下:
291 292 [L,n]=bwlabel(f);%L为标记矩阵,n为找到连接分量的总数 293 [r,c]=find(L==3);%返回第3个对象所有像素的行索引和列索引 294 295 rbar=mean(r); 296 cbar=mean(c); 297 298 figure,imshow(f) 299 hold on%保持当前图像使其不被刷新 300 for k=1:n 301 [r,c]=find(L==k); 302 rbar=mean(r); 303 cbar=mean(c); 304 plot(cbar,rbar,'Marker','o','MarkerEdgeColor','k',... 305 'MarkerFaceColor','k','MarkerSize',10);%这个plot函数用法不是很熟悉 306 plot(cbar,rbar,'Marker','*','MarkerFaceColor','w');%其中的marker为标记 307 end 308 title('标记所有对象质心后的图像');
309 310 %% 由重构做开运算 311 clc 312 clear 313 f=imread('.\images\dipum_images_ch09\Fig0922(a)(book-text).tif'); 314 subplot(321),imshow(f); 315 title('重构原始图像'); 316 317 fe=imerode(f,ones(51,1));%竖线腐蚀 318 subplot(322),imshow(fe); 319 title('使用竖线腐蚀后的结果'); 320 321 fo=imopen(f,ones(51,1));%竖线做开运算 322 subplot(323),imshow(fo); 323 title('使用竖线做开运算结果'); 324 325 fobr=imreconstruct(fe,f);%fe做标记 326 subplot(324),imshow(fobr); 327 title('使用竖线做重构开运算'); 328 329 ff=imfill(f,'holes');%对f进行孔洞填充 330 subplot(325),imshow(ff); 331 title('对f填充孔洞后的图像'); 332 333 fc=imclearborder(f,8);%清除边界,2维8邻接 334 subplot(326),imshow(fc); 335 title('对f清除边界后的图像'); 336%图像重构过程显示如下:
337 338 %% 使用顶帽变换和底帽变换 339 clc 340 clear 341 f=imread('.\images\dipum_images_ch09\Fig0926(a)(rice).tif'); 342 subplot(221),imshow(f); 343 title('顶帽底帽变换原始图像'); 344 345 se=strel('disk',10);%产生结构元素 346 %顶帽变换是指原始图像减去其开运算的图像 347 %而开运算可用于补偿不均匀的背景亮度,所以用一个大的结构元素做开运算后 348 %然后用原图像减去这个开运算,就得到了背景均衡的图像,这也叫做是图像的顶帽运算 349 f1=imtophat(f,se);%使用顶帽变换 350 subplot(222),imshow(f1); 351 title('使用顶帽变换后的图像'); 352 353 %底帽变换是原始图像减去其闭运算后的图像 354 f2=imbothat(imcomplement(f),se);%使用底帽变换,为什么原图像要求补呢? 355 %f2=imbothat(f,se);%使用底帽变换 356 subplot(223),imshow(f2); 357 title('使用底帽变换后的图像'); 358 359 %顶帽变换和底帽变换联合起来用,用于增加对比度 360 f3=imsubtract(imadd(f,imtophat(f,se)),imbothat(f,se));%里面参数好像不合理? 361 subplot(224),imshow(f3); 362 title('使用顶帽底帽联合变换后图像'); 363%顶帽底帽变换过程图像如下:
364 365 %%使用开运算和闭运算做形态学平滑 366 %由于开运算可以除去比结构元素更小的明亮细节,闭运算可以除去比结构元素更小的暗色细节 367 %所以它们经常组合起来一起进行平滑图像并去除噪声 368 clc 369 clear 370 f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif'); 371 subplot(221),imshow(f); 372 title('木钉图像原图'); 373 374 se=strel('disk',5);%disk其实就是一个八边形 375 fo=imopen(f,se);%经过开运算 376 subplot(222),imshow(f); 377 title('使用半径5的disk开运算后的图像'); 378 379 foc=imclose(fo,se); 380 subplot(223),imshow(foc); 381 title('先开后闭的图像'); 382 383 fasf=f; 384 for i=2:5 385 se=strel('disk',i); 386 fasf=imclose(imopen(fasf,se),se); 387 end 388 subplot(224),imshow(fasf); 389 title('使用开闭交替滤波后图像'); 390%使用开运算和闭运算做形态学平滑结果如下:
391 392 %% 颗粒分析 393 clc 394 clear 395 f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif'); 396 397 sumpixels=zeros(1,36); 398 for k=0:35 399 se=strel('disk',k); 400 fo=imopen(f,se); 401 sumpixels(k+1)=sum(fo(:)); 402 end 403 404 %可以看到,连续开运算之间的表面积会减少 405 plot(0:35,sumpixels),xlabel('k'),ylabel('surface area'); 406 title('表面积和结构元素半径之间的关系'); 407%其运算结果如下:
408 409 figure,plot(-diff(sumpixels));%diff()函数为差分或者近似倒数,即相邻2个之间的差值 410 xlabel('k'),ylabel('surface area reduction'); 411 title('减少的表面积和结构元素半径之间的关系'); 412%其运算结果如下:
413 414 %% 使用重构删除复杂图像的背景 415 clc 416 clear 417 f=imread('.\images\dipum_images_ch09\Fig0930(a)(calculator).tif'); 418 subplot(221),imshow(f); 419 title('灰度级重构原图像'); 420 421 f_obr=imreconstruct(imerode(f,ones(1,71)),f); 422 subplot(222),imshow(f_obr); 423 title('经开运算重构图'); 424 425 f_o=imopen(f,ones(1,71)); 426 subplot(223),imshow(f_o); 427 title('经开运算后图'); 428 429 f_thr=imsubtract(f,f_obr); 430 subplot(224),imshow(f_thr); 431 title('顶帽运算重构图') 432%使用重构删除复杂图像的背景1:
433 434 f_th=imsubtract(f,f_o) 435 figure,subplot(221),imshow(f_th); 436 title('经顶帽运算图'); 437 438 g_obr=imreconstruct(imerode(f_thr,ones(1,11)),f_thr); 439 subplot(222),imshow(g_obr); 440 title('用水平线对f_thr经开运算后重构图'); 441 442 g_obrd=imdilate(g_obr,ones(1,2)); 443 subplot(223),imshow(g_obrd); 444 title('使用水平线对上图进行膨胀'); 445 446 f2=imreconstruct(min(g_obrd,f_thr),f_thr); 447 subplot(224),imshow(f2); 448 title('最后的重构结果'); 449%使用重构删除复杂图像的背景2:
形态学这一章很有用,因为它还可以应用在图像分割中。
作者:tornadomeet出处:http://www.cnblogs.com/tornadomeet欢迎转载或分享,但请务必声明文章出处。 -
二叉树基本概念学习
2020-05-13 20:59:50它有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空。 二叉树分类: 1、满二叉树 定义:高度为h,并且由2h-1个结点组成的二叉树,称为满二叉树。(叶子节点高度一致) 2.完全...二叉树:
二叉树是每个结点最多有两个子树的树结构。它有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空。二叉树分类:
1、满二叉树
定义:高度为h,并且由2h-1个结点组成的二叉树,称为满二叉树。(叶子节点高度一致)
2.完全二叉树
定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下层的叶结点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。
特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。
3.二叉查找树( Binary Search Tree)
特性:
1.左子树节点值小于等于根节点值。
2.右子树节点值大于等于根节点值。
3.缺点,极端情况下二叉树不平衡,会变成线性查找了。
4.AVL树
AVL树是一颗严格的自平衡的二叉查找树(左<根<右),同时左子树和右子树的高度之差的绝对值不超过1。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。5.红黑树
红黑树(Red Black Tree)是一种弱自平衡二叉查找树,红黑树确保从根节点到叶子节点没有一条路径会比其它路径长出两倍。因此课件红黑树的高度是高于AVL树的。
红黑树满足如下特性:
① 每个结点是红色或者黑色的。
② 根结点是黑色的。
③ 叶子节点是黑色空节点(NIL)。
④ 红色节点的左右子结点都必须是黑色的(但黑色结点的子结点可以是黑色的)
⑤ 任一节点到叶子节点的路径必须包含相同数目的黑色结点。AVL树和红黑树的插入和删除操作都需要通过树的旋转来维持平衡。
-
基于形态学运算的图像变换
2019-04-18 20:00:18(1)腐蚀和膨胀是形态学中最基本的运算,而结构元素又是数学形态学中最基本的工具。结构元素可以简单理解为像素的结构以及一个原点。使用形态学滤波就是对像素的每个元素应用这个结构,当结构元素的原点和像素对齐时...一、形态学滤波对图像进行腐蚀、膨胀运算
1.概念及原理
(1)腐蚀和膨胀是形态学中最基本的运算,而结构元素又是数学形态学中最基本的工具。结构元素可以简单理解为像素的结构以及一个原点。使用形态学滤波就是对像素的每个元素应用这个结构,当结构元素的原点和像素对齐时,它与图像的相交部分定义了一组进行形态学运算的像素。结构元素可以是任何形状,我们一般使用简单的方形、圆形、或菱形,原点即位于中心位置。
(2)腐蚀替换当前像素位像素集合中找到的最小像素值,膨胀则相反。为了想象出两个运算的效果,可以考虑背景(黑色)和前景(白色)。腐蚀情况下,给定像素的结构元素接触到背景,该像素被置为背景。膨胀则是给定像素位置接触到前景物体,该像素被置为白色。因此,腐蚀后的图像尺寸变小,膨胀即相反。
2.实验
由于形态学滤波通常使用二值图像,所以我们先把图像转换为二值图像然后对图像进行腐蚀和膨胀。以下实验都是对该二值图像进行处理。
源码示例#include<iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv/cv.h> using namespace std; using namespace cv; Mat g_pGrayImage; Mat g_pBinaryImage; int main(){ // 从文件中加载原图 Mat pSrcImage = cvLoadImage("horse.jpg", CV_LOAD_IMAGE_UNCHANGED); // 转为灰度图 g_pGrayImage.create(pSrcImage.rows, pSrcImage.cols, CV_8U); cvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY); // 创建二值图 g_pBinaryImage.create(g_pGrayImage.rows, g_pGrayImage.cols, CV_8U); // 转为二值图 threshold(g_pGrayImage, g_pBinaryImage, 100, 255, CV_THRESH_BINARY); //显示二值图像 cvNamedWindow("BinaryImage"); imshow("BinaryImage", g_pBinaryImage); //腐蚀图像 Mat eroded; //目标图像 erode(g_pBinaryImage, eroded, Mat()); //显示腐蚀后的图像 cvNamedWindow("Eroded Image"); imshow("Eroded Image", eroded); //膨胀图像 Mat dilated; //目标图像 dilate(g_pBinaryImage, dilated, Mat()); //显示膨胀后的图像 cvNamedWindow("Dilated Image"); imshow("Dilated Image", dilated); waitKey(0); system("pause"); return 0; }
运行效果
二、形态学滤波对图像进行开闭运算
1.概念及原理
(1)闭运算定义为对图像进行先膨胀再腐蚀,开运算定义为对图像进行先腐蚀再膨胀
(2)闭滤波器可以填充白色前景物中的小洞,开滤波器可以移除场景中比较小的物体。这些滤波器通常在物体检测中使用,闭滤波器可以将误分割成碎片的物体重新连接,而开滤波器可以处理图像噪点引起的小像素块。
2.实验
通过合适的参数调用cv::morphologyEx 使用更高级的形态学滤波。
源码示例#include<iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv/cv.h> using namespace std; using namespace cv; Mat g_pGrayImage; Mat g_pBinaryImage; int main(){ // 从文件中加载原图 Mat pSrcImage = cvLoadImage("horse.jpg", CV_LOAD_IMAGE_UNCHANGED); // 转为灰度图 g_pGrayImage.create(pSrcImage.rows, pSrcImage.cols, CV_8U); cvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY); // 创建二值图 g_pBinaryImage.create(g_pGrayImage.rows, g_pGrayImage.cols, CV_8U); // 转为二值图 threshold(g_pGrayImage, g_pBinaryImage, 100, 255, CV_THRESH_BINARY); //显示二值图像 cvNamedWindow("BinaryImage"); imshow("BinaryImage", g_pBinaryImage); //闭运算图像,使用5*5的结构元素使得滤波效果更明显 Mat element5(5, 5, CV_8U, Scalar(1)); Mat closed; morphologyEx(g_pBinaryImage, closed, MORPH_CLOSE, element5); //显示闭运算后的图像 cvNamedWindow("闭运算图像"); imshow("闭运算图像", closed); //开运算图像 Mat opened; //目标图像 morphologyEx(g_pBinaryImage, opened, MORPH_OPEN, element5); //显示开运算后的图像 cvNamedWindow("开运算图像"); imshow("开运算图像", opened); waitKey(0); system("pause"); return 0; }
程序运行后的效果
三、形态学滤波对图像进行边缘及角点检测
实验一
检测灰度图中的直线。
源码示例#include<iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv/cv.h> using namespace std; using namespace cv; class MorphoFeatures{ private: //用于生成二值图像的阈值 int ithreshold; //角点检测中用到的结构元素 Mat cross; Mat diamond; Mat square; Mat x; void applyThreshold(Mat &result); public: Mat getEdges(const Mat &image); void setThreshold(float t); }; //获取二值的边缘图像 void MorphoFeatures::applyThreshold(Mat &result){ //使用阈值化 if (ithreshold > 0) { threshold(result, result, ithreshold, 255, THRESH_BINARY); } } //morphologyEx + 合适的滤波器实现直线的检测 Mat MorphoFeatures::getEdges(const Mat &image){ //得到梯度图 Mat result; morphologyEx(image, result, MORPH_GRADIENT, Mat()); //阈值化以得到二值图像 applyThreshold(result); return result; } //设置直方图的阈值[0,1] void MorphoFeatures::setThreshold(float t){ ithreshold = t; } int main(){ Mat image = cvLoadImage("floor.jpg",0); MorphoFeatures morpho; morpho.setThreshold(80); //获取边缘 Mat edges; edges = morpho.getEdges(image); namedWindow("floor"); imshow("floor",image); namedWindow("edges"); imshow("edges", edges); waitKey(0); system("pause"); return 0; }
实验二
检测灰度图中的角点
角点检测使用四种不同的结构元素检测图像角点,分别为十字型、菱型、x型和方形元素,尺寸规定为5*5。与边缘检测不同,角点的检测复杂。运算过程主要分三步:
第一步,先用十字形的结构元素膨胀原图像,这种情况下只会在边缘处“扩张”,角点不发生变化。接着用菱形的结构元素腐蚀原图像,只有拐角处才会被“收缩”,而直线边缘不发生变化。
第二步,用X型的结构元素膨胀原图像,角点膨胀的比边要多。这样第二次用方块腐蚀时,角点恢复原状,而边要腐蚀的更多。
第三步,将一二步的两幅输出图像相减,结果只保留了各个拐角处的细节。
源码示例#include<iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv/cv.h> using namespace std; using namespace cv; class MorphoFeatures{ private: //用于生成二值图像的阈值 int ithreshold; //角点检测中用到的结构元素 Mat cross; Mat diamond; Mat square; Mat x; void applyThreshold(Mat &result); public: MorphoFeatures():ithreshold(50), cross(5, 5, CV_8U, Scalar(0)), diamond(5, 5, CV_8U, Scalar(1)), square(5, 5, CV_8U, Scalar(1)),x(5,5,CV_8U,Scalar(0)){ //创建十字形元素 for (int i = 0; i < 5; i++) { cross.at<uchar>(2, i) = 1; cross.at<uchar>(i, 2) = 1; } //创建菱形元素 diamond.at<uchar>(0, 0) = 0; diamond.at<uchar>(0, 1) = 0; diamond.at<uchar>(1, 0) = 0; diamond.at<uchar>(4, 4) = 0; diamond.at<uchar>(3, 4) = 0; diamond.at<uchar>(4, 3) = 0; diamond.at<uchar>(4, 0) = 0; diamond.at<uchar>(4, 1) = 0; diamond.at<uchar>(3, 0) = 0; diamond.at<uchar>(0, 4) = 0; diamond.at<uchar>(0, 3) = 0; diamond.at<uchar>(1, 4) = 0; //创建x形元素 for (int i = 0; i < 5; i++) { x.at<uchar>(i, i) = 1; x.at<uchar>(4-i, i) = 1; } } Mat getEdges(const Mat &image); void setThreshold(float t); Mat getCorners(const Mat&image); void drawOnImage(const Mat &binary, Mat &image); }; //获取二值的边缘图像 void MorphoFeatures::applyThreshold(Mat &result){ //使用阈值化 if (ithreshold > 0) { threshold(result, result, ithreshold, 255, THRESH_BINARY); } } //morphologyEx + 合适的滤波器实现直线的检测 Mat MorphoFeatures::getEdges(const Mat &image){ //得到梯度图 Mat result; morphologyEx(image, result, MORPH_GRADIENT, Mat()); //阈值化以得到二值图像 applyThreshold(result); return result; } //设置直方图的阈值[0,1] void MorphoFeatures::setThreshold(float t){ ithreshold = t; } //连接使用这些结构以得到最终的角点映射图 Mat MorphoFeatures::getCorners(const Mat&image){ Mat result; //十字形膨胀 dilate(image, result, cross); //菱形腐蚀 erode(result, result, diamond); Mat result2; //X形膨胀 dilate(image, result2, x); //方形腐蚀 erode(result2, result2, square); //通过对两张图像做差值得到角点图像 absdiff(result2, result, result); //阈值化以得到二值图像 applyThreshold(result); return result; } //在二值图像中的每个检测点上绘制一个圆 更好的可视化结果 void MorphoFeatures::drawOnImage(const Mat &binary, Mat &image){ Mat_<uchar>::const_iterator it = binary.begin<uchar>(); Mat_<uchar>::const_iterator itend = binary.end<uchar>(); //遍历每个像素 for (int i = 0; it != itend; ++it, ++i) { if (*it) circle(image, Point(i%image.step, i/image.step), 5, Scalar(255, 0, 0)); } } int main(){ Mat image = cvLoadImage("floor.jpg"); Mat grayImage; cvtColor(image, grayImage,CV_BGR2GRAY); //显示原图 namedWindow("Image"); imshow("Image", grayImage); MorphoFeatures morpho; //得到角点 Mat corners; corners = morpho.getCorners(grayImage); //在图像中显示角点 morpho.drawOnImage(corners, grayImage); namedWindow("Corners on Image"); imshow("Corners on Image", grayImage); waitKey(0); return 0; }
这里需要注意由于要把输入图像转化为二值图像,因此阈值的选择会影响角点检测效果,在此可以输入不同的阈值查看角点检测效果。
四、分水岭算法对图像进行分割
1.概念及原理
(1)分水岭分割方法是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
实验
实验主要分为
1.对二值图像进行反转,因为我们一般用255白色表示前景 0黑色表示背景
2.有二值图腐蚀移除噪点和微小物体 获得前景
3.膨胀二值图获取背景
4.前景与背景相加得到markers标记图像
5.设置markers标记进行分水岭分割
源码示例#include<iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv/cv.h> using namespace std; using namespace cv; class MorphoFeatures{ private: //用于生成二值图像的阈值 int ithreshold; //角点检测中用到的结构元素 Mat cross; Mat diamond; Mat square; Mat x; void applyThreshold(Mat &result); public: MorphoFeatures():ithreshold(50), cross(5, 5, CV_8U, Scalar(0)), diamond(5, 5, CV_8U, Scalar(1)), square(5, 5, CV_8U, Scalar(1)),x(5,5,CV_8U,Scalar(0)){ //创建十字形元素 for (int i = 0; i < 5; i++) { cross.at<uchar>(2, i) = 1; cross.at<uchar>(i, 2) = 1; } //创建菱形元素 diamond.at<uchar>(0, 0) = 0; diamond.at<uchar>(0, 1) = 0; diamond.at<uchar>(1, 0) = 0; diamond.at<uchar>(4, 4) = 0; diamond.at<uchar>(3, 4) = 0; diamond.at<uchar>(4, 3) = 0; diamond.at<uchar>(4, 0) = 0; diamond.at<uchar>(4, 1) = 0; diamond.at<uchar>(3, 0) = 0; diamond.at<uchar>(0, 4) = 0; diamond.at<uchar>(0, 3) = 0; diamond.at<uchar>(1, 4) = 0; //创建x形元素 for (int i = 0; i < 5; i++) { x.at<uchar>(i, i) = 1; x.at<uchar>(4-i, i) = 1; } } Mat getEdges(const Mat &image); void setThreshold(float t); Mat getCorners(const Mat&image); void drawOnImage(const Mat &binary, Mat &image); }; //获取二值的边缘图像 void MorphoFeatures::applyThreshold(Mat &result){ //使用阈值化 if (ithreshold > 0) { threshold(result, result, ithreshold, 255, THRESH_BINARY); } } //morphologyEx + 合适的滤波器实现直线的检测 Mat MorphoFeatures::getEdges(const Mat &image){ //得到梯度图 Mat result; morphologyEx(image, result, MORPH_GRADIENT, Mat()); //阈值化以得到二值图像 applyThreshold(result); return result; } //设置直方图的阈值[0,1] void MorphoFeatures::setThreshold(float t){ ithreshold = t; } //连接使用这些结构以得到最终的角点映射图 Mat MorphoFeatures::getCorners(const Mat&image){ Mat result; //十字形膨胀 dilate(image, result, cross); //菱形腐蚀 erode(result, result, diamond); Mat result2; //X形膨胀 dilate(image, result2, x); //方形腐蚀 erode(result2, result2, square); //通过对两张图像做差值得到角点图像 absdiff(result2, result, result); //阈值化以得到二值图像 applyThreshold(result); return result; } //在二值图像中的每个检测点上绘制一个圆 更好的可视化结果 void MorphoFeatures::drawOnImage(const Mat &binary, Mat &image){ Mat_<uchar>::const_iterator it = binary.begin<uchar>(); Mat_<uchar>::const_iterator itend = binary.end<uchar>(); //遍历每个像素 for (int i = 0; it != itend; ++it, ++i) { if (*it) circle(image, Point(i%image.step, i/image.step), 5, Scalar(255, 0, 0)); } } int main(){ Mat image = cvLoadImage("floor.jpg"); Mat grayImage; cvtColor(image, grayImage,CV_BGR2GRAY); //显示原图 namedWindow("Image"); imshow("Image", grayImage); MorphoFeatures morpho; //得到角点 Mat corners; corners = morpho.getCorners(grayImage); //在图像中显示角点 morpho.drawOnImage(corners, grayImage); namedWindow("Corners on Image"); imshow("Corners on Image", grayImage); waitKey(0); return 0; }
实验过程中的一些图片
原图和像素反转二值图
fg前景图和bg背景图
标记图像和边界图像
五、GrabCut算法提取前景物体
源码示例#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<imgproc/imgproc.hpp> #include<iostream> using namespace std; using namespace cv; int main() { Mat image=imread("group.jpg"); namedWindow("Image"); imshow("Image",image); Rect rectangle(10,100,380,180); Mat result; Mat bgModel,fgModel; grabCut(image,result,rectangle,bgModel,fgModel,5,GC_INIT_WITH_RECT); compare(result,GC_PR_FGD,result,CMP_EQ); Mat foreground(image.size(),CV_8UC3,Scalar(255,255,255)); image.copyTo(foreground,result); namedWindow("Foreground"); imshow("Foreground",foreground); waitKey(); return 0; }
提取到前景效果图
grabCut函数的API说明如下:
void cv::grabCut( InputArray _img, InputOutputArray _mask, Rect rect,
InputOutputArray _bgdModel, InputOutputArray _fgdModel,
int iterCount, int mode )
/*
****参数说明:
img——待分割的源图像,必须是8位3通道(CV_8UC3)图像,在处理的过程中不会被修改;
mask——掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。mask只能取以下四种值:
GCD_BGD(=0),背景;
GCD_FGD(=1),前景;
GCD_PR_BGD(=2),可能的背景;
GCD_PR_FGD(=3),可能的前景。
如果没有手工标记GCD_BGD或者GCD_FGD,那么结果只会有GCD_PR_BGD或GCD_PR_FGD;
rect——用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
bgdModel——背景模型,如果为null,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
fgdModel——前景模型,如果为null,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
iterCount——迭代次数,必须大于0;
mode——用于指示grabCut函数进行什么操作,可选的值有:
GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut;
GC_EVAL(=2),执行分割。
*/
【OpenCV学习笔记 008】基于形态学运算的图像变换 配套的源码下载
-
用形态学运算变换图像(一)用形态学滤波器腐蚀和膨胀图像
2018-11-06 16:10:42用形态学运算变换图像(一) ...最基本的概念是结构元素,结构元素可简单定义为像素的组合,在对应的像素上设定结构元素的原点,也成锚点。结构元素原则上可为任何形状,通常为正方形、圆形、菱形,且把中心点... -
图像形态学概要-腐蚀、膨胀、开运算、闭运算、形态学梯度(形态学边缘提取)、顶帽操作、黑帽操作
2016-07-12 13:12:15图像形态学中两种最基本的操作就是对图形的腐蚀和膨胀,可以说,形态学中的中高级操作都是建立在这两种操作之上。 关于图像腐蚀和膨胀的概念,不严谨的简单理解是:经过腐蚀和膨胀操作后最终的效果是对图像中物体的... -
图像处理之形态学梯度计算
2017-03-23 10:00:43形态学操作膨胀与腐蚀图像形态学中最基本的两个形态学操作、常常被组合起来一起使用实现一些复杂的图像形态学操作,计算图像的形态学梯度是形态学重要操作之一是有膨胀和腐蚀基础操作适当的组合形成。可以计算的梯度... -
OpenCV_用形态学运算变换图像
2017-12-09 08:01:34数学形态学是一门20c60s发展起来的理论,用于分析和处理离散...数学形态学中最基本的概念是结构元素。结构元素可以简单地定义为像素的组合,在对应的像素上定义了一个原点。形态学滤波器的应用过程就包含了用这个结构元 -
OPENCV形态学操作1
2016-03-06 23:27:00形态学操作是指基于形状的一系列图像处理操作,包括膨胀,腐蚀,二值化,开运算,闭运算,顶帽算法,黑帽算法,形态学梯度等,最基本的形态学操作就是膨胀和腐蚀. 一.膨胀 首先需要明确一个概念,膨胀和腐蚀都是针对于图像... -
形态学-膨胀与腐蚀
2017-12-01 09:26:17本篇文章中,我们一起探究了图像处理中,最基本的形态学运算——膨胀与腐蚀。浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试。。。。。。。。。。 OK... -
OpenCV学习笔记(五)用形态学运算变换图像
2020-06-16 00:58:12在数学形态学中最基本的概念是结构元素,类似滤波当中的核,核的尺寸是可调的,将核的中心点作为原点,也叫锚点。形态学滤波器通常作用于二值图像,形态学中习惯用高像素值(白色)作为前景物体,用低像素值(黑色)... -
数学形态学概要,腐蚀 膨胀,开运算,闭运算
2019-05-14 21:38:20数学形态学(Mathematical morphology)是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。... 数学形态学两个最基本的操作是腐蚀跟膨胀. 利用数学形态学, 我们... -
OpenCV中形态学操作:膨胀、腐蚀、开闭运算
2019-12-25 17:36:141、基本概念 图像形态学即数学形态学(Mathematical morphology)是一门建立在格伦和拓扑学基础上的图像分析学科...腐蚀和膨胀是最基本的形态学运算。 腐蚀和膨胀是针对白色部分(高亮部分)而言的。 膨胀(dilate... -
-
opencv 核 腐蚀_学习 opencv---(9)形态学图像处理(一):膨胀和腐蚀
2021-01-14 14:20:52本篇文章中,我们一起探究了图像处理中,最基本的形态学运算——膨胀与腐蚀。浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试。。。。。。。。。。一、理论与... -
【OpenCV计算机视觉编程攻略】用形态学滤波器检测边缘和角点
2018-09-21 17:45:16机器感知 ...腐蚀和膨胀是最基本的形态学运算, 数学形态学中最基本的概念是结构元素。 结构元素可以简单地定义为像素的组合(下图的正方形) , 在对应的像素上定义了一个原点(也称锚点) 。 ... -
opencv计算机视觉编程攻略_【OpenCV计算机视觉编程攻略】用形态学滤波器检测边缘和角点...
2021-01-22 20:43:031. 准备工作:腐蚀和膨胀是最基本的形态学运算, 数学形态学中最基本的概念是结构元素。 结构元素可以简单地定义为像素的组合(下图的正方形) , 在对应的像素上定义了一个原点(也称锚点) 。 形态学滤波器的应用... -
opencv笔记十二(形态学操作)morphologyEx(Mat old, Mat new, CV_MOP_OPEN, Mat getStructuringElement )
2018-07-02 21:15:29形态学操作膨胀与腐蚀图像形态学中最基本的两个形态学操作、常常被组合起来一起使用实现一些复杂的图像形态学操作,计算图像的形态学梯度是形态学重要操作之一是有膨胀和腐蚀基础操作适当的组合形成。可以计算的梯..... -
【OpenCV入门教程之十】 形态学图像处理(一):膨胀与腐蚀
2018-02-08 10:40:51本篇文章中,我们一起探究了图像处理中,最基本的形态学运算——膨胀与腐蚀。浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试。。。。。。。。。。OK,开始吧... -
医学图像处理_医学图像处理教程(一)——医学算法数据的基本概念
2020-12-18 02:39:35从今天起我将开始分享医学图像处理基础算法课程,从最基本的函数开始,分享函数的原理,函数API参数讲解,每篇都会给出一个示例。参考了数字图像处理(冈萨雷斯)部分内容,列举了一些以后要分享的函数,主要分成五大... -
-
-
-
javaSE单例模式两种形态
2020-06-19 17:01:07这个网站将整个过程从无到有按步骤陈列出来,每一步都很清晰,对于抽象的概念解释得很形象,非常容易让我理解,真的是宝藏。 虽说看视频和看习题答案需要积分,但是我大多都用不着哈哈哈哈,下面的提问区域还有人... -
-
根据编写的xmind中看点模块思维导图 使用Excel编写至少100条测试用例
-
DHCP 动态主机配置服务(在Linux环境下,配置单网段或跨网段提)
-
深度剖析C语言知识体系 原理+实践,一课带你吃透C语言
-
【LeetCode】转置矩阵(JavaScript)
-
Linux基础入门系列课程
-
spark大数据分析与实战
-
Mysql数据库面试直通车
-
MySQL 高可用工具 DRBD 实战部署详解
-
Java多态、接口继承、抽象类继承、向上向下转型实例
-
在产品中找到里面的bug 用excel编写缺陷报告 至少20条,并记录到禅道
-
Zookeeper客户端操作
-
NVIDIA-SMI系列命令总结
-
ArcGIS地理数据处理高级教程_003_2利用数据框进行重投影
-
cesium地图设备轨迹回放视频.mp4
-
同城图标6113个.rar
-
ISBFrontEnd-源码
-
深究字符编码的奥秘,与乱码说再见
-
MMM 集群部署实现 MySQL 高可用和读写分离
-
Jsplumb从入门到实战
-
【Python-随到随学】FLask第二周