技术标签: 图像处理
数学形态学(也称图像代数)表示以形态为基础对图像进行分析的数学工具
基本思想:是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的
形态学图像处理的数学基础和所用语言是集合论
形态学图像处理的应用可以简化图像数据,保持它们基本的形状特性,并除去不相干的结构
形态学图像处理的基本运算有4个:膨胀、腐蚀、开操作和闭操作
数字图像处理中的形态学处理是指将数学形态学作为工具从图像中提取对于表达和描绘区域形状有用处的图像分量,比如边界、骨架以及凸壳,还包括用于预处理或后处理的形态学过滤、细化和修剪等。图像形态学处理中我们感兴趣的主要是二值图像。
在二值图像中,所有黑色像素的集合是图像完整的形态学描述,二值图像的各个分量是Z2的元素。假定二值图像A和形态学处理的结构元素B是定义在笛卡儿网格上的集合,网格中值为1的点是集合的元素,当结构元素的原点移到点(x,y)时,记为Sxy,为简单起见,结构元素为3x3,且全都为1,在这种限制下,决定输出结果的是逻辑运算。
二值形态学逻辑运算
逻辑运算尽管本质上很简单,但对于实现以形态学为基础的图像处理算法是一种有力的补充手段。在图像处理中用到的主要逻辑运算是:与、或、非(求补)、异或,它们可以互相组合形成其他逻辑运算。
二值形态学中的运算对象是集合。设A为图像集合,S为结构元为结构元素,数学形态学运算是用S对A进行操作。
需要指出,实际上结构元素本身也是一个图像集合。对每个结构元素可以指定一个原点,它是结构元素参与形态学运算的参考点。
应注意,原点可以包含在结构元素中,也可以不包含在结构元素中,但运算的结果常不相同。
二值形态学中两个最基本的运算是腐蚀与膨涨,当然也可以用在灰度图像。
基本的形态转换是膨胀与腐蚀,它们能实现多种功能:例如消除噪声,分割出独立的图像元素以及在图像中连接相邻元素,形态学也常被用于寻找图像中额明显极大值区域或者极小值区域以及求出图像的梯度。
图像腐蚀 膨胀 细化的基本原理
膨胀和腐蚀
膨胀和腐蚀这两种操作是形态学处理的基础,许多形态学算法都是以这两种运算为基础的。
① 膨胀
是以得到B的相对与它自身原点的映像并且由z对映像进行移位为基础的。即B的反射平移,A被B膨胀是所有位移z的集合,这样, 和A至少有一个元素是重叠的。我们可以把上式改写为:
结构元素B可以看作一个卷积模板,区别在于膨胀是以集合运算为基础的,卷积是以算术运算为基础的,但两者的处理过程是相似的。
⑴ 用结构元素B,扫描图像A的每一个像素
⑵ 用结构元素与其覆盖的二值图像做“或”操作
⑶ 如果都为0,结果图像的该像素为0。否则为1
另外一种定义是:图像A与形态核B进行卷积,计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。
② 腐蚀
对Z中的集合A和B,B对A进行腐蚀的整个过程如下:
⑴ 用结构元素B,扫描图像A的每一个像素
⑵ 用结构元素与其覆盖的二值图像做“与”操作
⑶ 如果都为1,结果图像的该像素为1。否则为0
腐蚀在数学形态学运算中的作用是消除物体边界点。
如果结构元素取3×3的像素块,腐蚀将使物体的边界沿周边减少一个像素。
腐蚀可以把小于结构元素的物体(毛刺、小凸起)去除,这样选取不同大小的结构元素,就可以在原图像中去掉不同大小的物体。
如果两个物体之间有细小的连通,那么当结构元素足够大时,通过腐蚀运算可以将两个物体分开。
⑷ 击中(匹配)或击不中变换
假设集合A是由3个子集X,Y和Z组成的集合,击中(匹配)的目的是要在A中找到X的位置,我们设X被包围在一个小窗口W中,与W有关的X的局部背景定义为集合的差(W-X),则X在A内能得到精确拟合位置集合是由X对A的腐蚀后由(W-X)对A的补集Ac腐蚀的交集,这个交集就是我们要找的位置,我们用集合B来表示由X和X的背景构成的集合,我们可以令B=(B1,B2),这里B1=X,B2=(W-X),则在A中对B进行匹配可以表示为:
A⊙B
我们称为形态学上的击中或击不中变换。
⑸ 开闭操作
开操作是先腐蚀、后膨胀处理。
闭操作是先膨胀、后腐蚀处理。
(6) 细化
图像细化一般作为一种图像预处理技术出现,目的是提取源图像的骨架,即是将原图像中线条宽度大于1个像素的线条细化成只有一个像素宽,形成“骨架”,形成骨架后能比较容易的分析图像,如提取图像的特征。
细化基本思想是“层层剥夺”,即从线条边缘开始一层一层向里剥夺,直到线条剩下一个像素的为止。图像细化大大地压缩了原始图像地数据量,并保持其形状的基本拓扑结构不变,从而为文字识别中的特征抽取等应用奠定了基础。细化算法应满足以下条件:
① 将条形区域变成一条薄线;
② 薄线应位与原条形区域的中心;
③ 薄线应保持原图像的拓扑特性。
细化分成串行细化和并行细化,串行细化即是一边检测满足细化条件的点,一边删除细化点;并行细化即是检测细化点的时候不进行点的删除只进行标记,而在检测完整幅图像后一次性去除要细化的点。
常用的图像细化算法有hilditch算法,pavlidis算法和rosenfeld算法等
(7)形态学梯度
其实就是膨胀操作减去腐蚀操作,得到高亮区域的边缘。即它能描述灰度变化的剧烈程度。
(8)礼帽,黑帽
两个操作用于分离比邻近的点亮或者暗的一些斑块,当试图孤立的部分与其邻近的部分有亮度变化时,就可以使用这些方法,
礼帽:原始数据 - 原始数据开运算的结果,黑帽:原始数据的闭运算减去原始数据。
注:进行细化算法前要先对图像进行二值化,即图像中只包含“黑”和“白”两种颜色。
具体详细的图像形态学资料参考:http://wenku.baidu.com/view/1923d18fcc22bcd126ff0ccc.html
二、OpenCv形态学操作相关函数
1、MorphologyEx 高级形态学变换
void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp,
IplConvKernel* element, int operation, int iterations=1 );
src
输入图像.
dst
输出图像.
temp
临时图像,某些情况下需要
element
结构元素
operation
形态操作的类型:
CV_MOP_OPEN - 开运算
CV_MOP_CLOSE - 闭运算
CV_MOP_GRADIENT - 形态梯度
CV_MOP_TOPHAT - "顶帽"
CV_MOP_BLACKHAT - "黑帽"
iterations
膨胀和腐蚀次数.
函数 cvMorphologyEx 在膨胀和腐蚀基本操作的基础上,完成一些高级的形态变换:
可以自定义形态核,即结构元素,但注意形态核卷积核不同,不需要任何的数值填充。参考点指定核与源图像的位置关系,同时也锁定了计算结果在目标图像中的位置。
开运算
dst=open(src,element)=dilate(erode(src,element),element)
闭运算
dst=close(src,element)=erode(dilate(src,element),element)
形态梯度
dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)
"顶帽"
dst=tophat(src,element)=src-open(src,element)
"黑帽"
dst=blackhat(src,element)=close(src,element)-src
临时图像 temp 在形态梯度以及对“顶帽”和“黑帽”操作时的 in-place 模式下需要。
2、Dilate 使用任意结构元素膨胀图像
void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );
src
输入图像.
dst
输出图像.
element
用于膨胀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素
iterations
膨胀的次数
函数 cvDilate 对输入图像使用指定的结构元进行膨胀,该结构决定每个具有最小值象素点的邻域形状:
dst=dilate(src,element): dst(x,y)=max((x',y') in element))src(x+x',y+y')
函数支持(in-place)模式。膨胀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。
3、Erode 使用任意结构元素腐蚀图像
void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );
src
输入图像.
dst
输出图像.
element
用于腐蚀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素
iterations
腐蚀的次数
函数 cvErode 对输入图像使用指定的结构元素进行腐蚀,该结构元素决定每个具有最小值象素点的邻域形状:
dst=erode(src,element): dst(x,y)=min((x',y') in element))src(x+x',y+y')
函数支持本地操作,不需另外开辟存储空间的意思。腐蚀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。
注:CreateStructuringElementEx 创建结构元素;ReleaseStructuringElement 删除结构元素。
三、OpenCv形态学实例代码:
1、腐蚀、膨胀、开运算、闭运算
内容参考:http://blog.csdn.net/gnuhpc/archive/2009/06/21/4286177.aspx
/*******************************
数学形态运算,最常见的基本运算有七种,
分别为:腐蚀、膨胀、开运算、闭运算、击中、细化和粗化,
它们是全部形态学的基础。
********************************/
#include "cv.h"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
IplImage *src=0;
IplImage *dst=0;
IplConvKernel *element=0;//声明一个结构元素
int element_shape=CV_SHAPE_RECT;//长方形形状的元素
int max_iters=10;
int open_close_pos=0;
int erode_dilate_pos=0;
void OpenClose(int pos)
{
int n=open_close_pos-max_iters;
int an=n>0?n:-n;
element = cvCreateStructuringElementEx(an*2+1, an*2+1,an,an,element_shape,0);//创建结构元素
if (n<0)
{
cvErode(src,dst,element,1);//腐蚀图像
cvDilate(dst,dst,element,1);//膨胀图像
}
else
{
cvDilate(dst,dst,element,1);//膨胀图像
cvErode(src,dst,element,1);//腐蚀图像
}
cvReleaseStructuringElement(&element);
cvShowImage("Open/Close",dst);
}
void ErodeDilate(int pos)
{
int n=erode_dilate_pos-max_iters;
int an=n>0?n:-n;
element = cvCreateStructuringElementEx(an*2+1,an*2+1,an,an,element_shape,0);
if (n<0)
{
cvErode(src,dst,element,1);
}
else
{
cvDilate(src,dst,element,1);
}
cvReleaseStructuringElement(&element);
cvShowImage("Erode/Dilate",dst);
}
int main(int argc,char **argv)
{
char *filename =argc ==2?argv[1]:(char *)"lena.jpg";
if( (src = cvLoadImage(filename,1)) == 0 )
return -1;
dst=cvCloneImage(src);
cvNamedWindow("Open/Close",1);
cvNamedWindow("Erode/Dilate",1);
open_close_pos = erode_dilate_pos = max_iters;
cvCreateTrackbar("iterations","Open/Close",&open_close_pos,max_iters*2+1,OpenClose);
cvCreateTrackbar("iterations","Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate);
for (;;)
{
int c;
OpenClose(open_close_pos);
ErodeDilate(erode_dilate_pos);
c= cvWaitKey(0);
if (c==27)
{
break;
}
switch(c) {
case 'e':
element_shape=CV_SHAPE_ELLIPSE;
break;
case 'r':
element_shape=CV_SHAPE_RECT;
break;
case '\r':
element_shape=(element_shape+1)%3;
break;
default:
break;
}
}
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvDestroyWindow("Open/Close");
cvDestroyWindow("Erode/Dilate");
return 0;
}
/*****************************
#include "StdAfx.h"
#include "cv.h"
#include "highgui.h"
#include "highgui.h"
int main(int argc, char ** argv)
{
cvNamedWindow("sourceImage");
cvNamedWindow("open");
cvNamedWindow("close");
cvNamedWindow("gradient");
cvNamedWindow("topHat");
cvNamedWindow("blackHat");
IplImage * src = cvLoadImage("test.bmp");
cvShowImage("sourceImage",src);
IplImage * temp = cvCreateImage(cvGetSize(src), 8,3);
IplImage * img=cvCreateImage(cvGetSize(src), 8, 3);
cvCopyImage(src,temp);
cvCopyImage(src, img);
//开运算
cvMorphologyEx(
src,
img,
temp,
NULL, //default 3*3
CV_MOP_OPEN,
4);
cvShowImage("open", img);
//闭运算
cvMorphologyEx(
src,
img,
temp,
NULL, //default 3*3
CV_MOP_CLOSE,
4);
cvShowImage("close", img);
//形态梯度
cvMorphologyEx(
src,
img,
temp,
NULL, //default 3*3
CV_MOP_GRADIENT,
3);
cvShowImage("gradient", img);
//cvWaitKey(0);
//"礼帽"
cvMorphologyEx(
src,
img,
temp,
NULL, //default 3*3
CV_MOP_TOPHAT,
3);
cvShowImage("topHat", img);
//cvWaitKey(0);
//“黑帽”
cvMorphologyEx(
src,
img,
temp,
NULL, //default 3*3
CV_MOP_BLACKHAT,
3);
cvShowImage("blackHat", img);
cvWaitKey(0);
cvReleaseImage(&temp);
cvReleaseImage(&src);
cvReleaseImage(&img);
cvDestroyAllWindows();
return 0;
}
文章浏览阅读196次。pb调用存储过程的时候,使用了事务,为了存储过程的逻辑功能完整,往往在存储过程中也会使用事务。如何保证存储过程内外的事务合理使用显得尤为重要。pb调用存储过程的事务,我们称其为主事务。他与存储过程内的事务关系,无非就两种情况。两个事务是同一个事务或者两个事务是独立的两个事务。oracle提供了参数PRAGMA AUTONOMOUS_TRANSACTION用于标示存储过程内的事务为自治事务,实例如下...
文章浏览阅读280次。2019独角兽企业重金招聘Python工程师标准>>> ..._p2v克隆windows
文章浏览阅读1.1k次。描述系统中的类,以及各个类之间的关系的静态视图。---------------------------------------摘自《设计模式就该这样学:基于经典框架源码和真实业务场景》(谭勇德)_uml
文章浏览阅读2.2k次,点赞3次,收藏7次。解决Windows cmd里git log 中文乱码的问题在当前cmd里输入set LESSCHARSET=utf-8设置环境变量,变量名: LESSCHARSET ,变量值: utf-8_cmd git log 中文乱码
文章浏览阅读4.8k次。Extjs多个tab页面——panel层叠_extjs写一个panel,多个ta
文章浏览阅读1.9w次,点赞21次,收藏110次。搭建流媒体服务,将rtsp或者rtmp视频流转换为H5可以直接播放的视频。用在直播、安防监控、视频点播、屏幕画面转播等_rtmp拉流地址
文章浏览阅读390次。什么是关键字:被java语音赋予特点含义的单词关键字的特点:组成字母全小部小写常见的代码编辑器,对关键字有特殊的颜色常见关键字举例用于定义数据类型的关键字:class 类interface 声明了这是一个java 的接口@interface 是用来修饰 Annotation 的,它是继承了 java...._关键字用来定义条件语句的分支
文章浏览阅读868次。联系: 视图(view)是在基本表之上建立的表,它的结构(即所定义的列)和内容(即所有数据行)都来自基本表,它依据基本表存在而存在。一个视图可以对应一个基本表,也可以对应多个基本表。视图是基本表的抽象和在逻辑意义上建立的新关系。区别:1、视图是已经编译好的sql语句。而表不是 2、视图没有实际的物理记录。而表有。 3、表是内容,视图是窗口 4、表只用物理空间而视图不占用物理空间,视图只是逻辑概..._统计和数据库视图有什么关系
文章浏览阅读614次。【代码】ZZULIOJ1061: 顺序输出各位数字。_zznuoj1061顺序输出各位数字
文章浏览阅读601次。问题截图:解决方案:在pom.xml文件中添加: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.4.3</version> _failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.3.0
文章浏览阅读310次。之前在[ArduPilot飞控之FAILSAFE机制](https://blog.csdn.net/lida2003/article/details/132191018)中,针对Ardupilot的`FAILSAFE`机制进行了相对完整的介绍。本章节将从代码的角度来看`FAILSAFE`代码触发入口,以及对应的应对策略。_开源飞控解锁
文章浏览阅读3.3k次。软件项目的生命周期分为六个阶段:项目前期、项目启动、项目蓝图、项目实施、项目验收、项目运维。其中项目运维是项目中的重要环节。针对本次客户反馈工作进行反思总结。_运维工作汇报不足