图像处理的开闭运算.docx
《图像处理的开闭运算.docx》由会员分享,可在线阅读,更多相关《图像处理的开闭运算.docx(37页珍藏版)》请在冰豆网上搜索。
![图像处理的开闭运算.docx](https://file1.bdocx.com/fileroot1/2023-1/21/3efb8a5a-fd72-440f-aeb8-d7c6b480ed5c/3efb8a5a-fd72-440f-aeb8-d7c6b480ed5c1.gif)
图像处理的开闭运算
图像处理的开运算与闭运算
0.前言
腐蚀和膨胀是依据数学形态学集合论方法发展起来的图像处理方法,起源于岩相对岩石结构的定量描述工作,在数字图像处理和机器视觉领域中得到了广泛的应用,形成了一种独特的数字图像分析方法和理论。
数学形态学是图像处理和模式识领域的新方法,其基本思想是:
用具有一定形态的结构元素去量度和提取图像中的对应形状,以达到图像分析和识别的目的。
优势有以下几点:
有效滤除噪声,保留图像中原有信息,算法易于用并行处理方法有效实现,基于数学形态学的边缘信息提取处理优于基于微分运算的边缘提取算法,提取的边缘比较平滑,提取的图像骨架也比较连续,断点少
腐蚀:
是一种消除边界点,使边界向内部收缩的过程。
可以用来消除小且无意义的物体。
膨胀:
是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程。
可以用来填补物体中的空洞。
开运算:
先腐蚀后膨胀的过程开运算。
用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。
开运算通常是在需要去除小颗粒噪声,以及断开目标物之间粘连时使用。
其主要作用与腐蚀相似,与腐蚀操作相比,具有可以基本保持目标原有大小不变的优点。
闭运算:
先膨胀后腐蚀的过程称为闭运算。
用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积。
原因:
虽然腐蚀处理可以将粘连的目标物进行分离,膨胀处理可以将断开的目标物进行接续,但同时都存在一个问题,就是经过腐蚀处理后,目标物的面积小于原有面积,而经过膨胀处理之后,目标物的面积大于原有面积。
开、闭运算就是为了解决这个问题而被提出的。
数学形态学中二值图像的形态变换是一种针对集合的处理过程。
其形态算子的实质是表达物体或形状的集合与结构元素间的相互作用,结构元素的形状就决定了这种运算所提取的信号的形状信息。
形态学图像处理是在图像中移动一个结构元素,然后将结构元素与下面的二值图像进行交、并等集合运算。
1.系统分析
系统功能需求
(1)位图图像文件的导入、转换、显示、保存、关闭模块
在该功能模块中提供:
位图图像文件的导入功能;把32位或8位位图文件转换为24位位图文件的功能;显示经过导入和转换后的24位位图文件的功能;图像保存(提供保存为8位和24位位图的功能)和关闭图像的功能。
这一模块主要对图像进行后续处理及其操作的基础。
(2)基于膨胀和腐蚀的图像处理模块
该模块主要的功能是用膨胀和腐蚀算法,得到对应的参数图像(图像增强),
结合膨胀和腐蚀,做出开闭运算的图像
(3)图像控制模块
该模块主要功能是实现对原始图像另存;分形图像、分割结果图像保存的操作
场景分析和开发
场景名称
参与
执行者
前置条件
事件流
后置条件
图像信息导入
用户
系统已
打开
1、打开系统主界面
2、选择文件菜单中的“打开”命令,选择文件
3、对图像类型进行合法性检查,合则4,否则2
4、清除上一次数据
5、把图像转换为24位位图文件
6、提取图像像素数据,并保存三份
7、将用户所要处理的图像导入系统中
1、图像导入
2、在图像显示界面上显示(三组图像及其直方图)
3、用户可以作其他的处理
基于腐蚀和膨胀图像的开闭处理
用户
系统已打开图像已导入
1、选择“图像处理”菜单
2、根据用户需要选择需要的处理类型
3、系统对图像作相应的处理
4、将处理后图像保存并显示给用户(中间组和右边组:
包括图像、直方图)
1、得到处理后图像(增强);2、在图像显示界面上显示(中间组和右边组);3、用户可以作其他的处理
处理结果图像保存场景
用户
系统已打开,图像已导入,并作相应的处理
1、选择“文件”菜单
2、选择“另保存”菜单,路径+文件名
3、将分形结果图像保存。
1、得到分形结果图像;2、用户可以作其他的处理
抽象用例对应活动图
用例图
根据功能分析和用例分析,我们得到“图像处理开闭运算”的用例图。
(1)图像信息的导入用例图
(2)基于腐蚀膨胀图像处理用例图
(3)原始图像另存用例
(4)处理结果图像保存用例
(5)总的用例图
建立系统总体架构及领域概念模型
系统总体架构
系统总体架构用于描述整个软件的体系结构,包括对各个功能模块的划分、功能定义、软件的层次结构等。
根据前面建立的系统用例图,我们选用分层架构模式。
下面我们用包图来描述总体结构。
系统领域概念模型
领域概念模型用于描述用户需求和相关业务领域中全局性的概念及其相互之间的关系。
它在系统总体架构的基础上,进一步从概念上帮助开发人员理清系统结构及系统各组成部分之间的相互作用。
领域概念模型使用UML的类图来表示,但不需要标出每个类的属性和方法,只需根据以上所作的场景开发和建立的用例,提取关键的概念并以类的形式表示出来即可。
领域概念模型可以理解为类图的草图
本系统拟采用MFC支持的文档视图结构中的单文档界面(SDI)结构。
大部分Windows应用程序都相当复杂。
典型的情况是,它们均包含业务逻辑处理层和界面层(程序框架),在MFC中对应于两个代表性的类:
“文档”和“视图”。
MFC将文档和视图有机地组成一个整体的框架,提供给程序编写者,这就是我们通常所说的文档/视图结构。
通常,当创建一个SDI应用程序时,如果不考虑About对话框窗口类的话,SDI应用程序将创建4个特定的类,即CC***APP类、CMainFrame类、CC***DOC类、CC***VIEW类,每个类在程序运行时都有自己的特殊用途。
其中:
(1)CC***APP类:
创建所有其它组件。
该类接收所有的事件消息,然后将这些消息传递给CMainFrame类、CC***DOC类、CC***VIEW。
在编程中几乎不需要修改和添加代码。
。
(2)CMainFrame类:
它包括菜单、工具栏、滚动条、状态栏、和所有其他与该框架相关联的显示对象。
在编程中几乎不需要修改和添加代码。
(3)CC***DOC类:
它是关于文档存储的类。
可以在这个类中创建数据结构,并利用这些数据结构存储和处理构成文档的数据。
(注意:
一般通过在该类中定义一个用户类的对象作为该类的成员变量,以此来创建数据结构,在程序中通过该成员变量来调用用户类的各种成员函数【方法】)。
该类从用户自己定义的类或CC***VIEW类得到输入并将要显示的信息输出到CC***VIEW类。
该类还负责存盘和从文件中检索文档数据的工作。
(4)CC***VIEW类:
它用于向用户显示可视化文档,并将用户输入的信息传送到CC***DOC类,然后从CC***DOC类接收显示信息。
在该类中所需要的大部分代码工作包括绘制用户的文档、处理用户的输入、调用用户自定义类中的方法(通过CC***DOC类的指针)。
CC***DOC类有几个子类,包括CEditView、CFormView、CHtmlView、CListView、CRichEditView、CScrollView、CTreeView等,但大部分子类和CC***VIEW类的属性和使用方法区别不大。
2系统设计
在系统需求分析阶段,通过建立系统总体结构、领域概念模型,已经确定了系统的基本结构。
在系统设计阶段主要内容有:
设计用例实现方案、数据设计、用户界面设计,建立组件图、配置图、生成系统代码框架等几部分工作
提取边界类、实体类、控制类
(1)提取边界类
边界类主要描述目标软件系统和外部环境的交互,复杂界面控制、外部接口和环境隔离,处理目标软件系统与用户、其他软件系统及操作系统和其他设备之间的交互。
根据已建立系统总体结构、领域概念模型,可以提取以下边界类:
1)CMainFrame类、CC***VIEW类、CC***APP类、CC***DOC类中的涉及数据输入以及界面变化的方法(成员函数)
2)CDlg***类
3)CImg类中的涉及数据输入以及显示的方法(成员函数)
(2)提取实体类
实体类表示目标软件系统中具有持久意义的信息项和操作,它向目标软件系统的其他部分提供读取信息项内容的必要接口,不涉及业务逻辑处理。
根据已建立系统总体结构、领域概念模型,可以提取以下边界类:
1)CC***DOC类中的涉及数据保存的方法(成员函数)
2)CImg类中的涉及数据保存的方法(成员函数)
(3)提取控制类和辅助类
控制类作为完成用例任务的责任承担者,主要用于协调、控制其他类共同完成用例规定的功能或行为。
它一般不处理具体的任务细节,但它应该能够分解任务并将子任务分派给适当的辅助类,同时在辅助类之间进行消息传递和协调。
MFC中采用消息映射机制实现处理来自操作面板接收的各种用户指令,并将这些命令分派给适当的辅助类。
辅助类用于辅助控制类完成用例规定的功能或行为。
可提取以下的辅助类:
1)CImg类中的用于完成用例规定的功能或行为的各种方法(成员函数)
2)CC***VIEW类、CC***DOC类、CDlg***类中的用于完成用例规定的功能或行为的各种方法(成员函数)或消息响应函数。
基于所提取的边界类、实体类和构建的控制类和辅助类,我们将在已提取的各种类的基础上,构造系统的交互图、协作图等动态视图,为设计生成系统类图做准备。
通过建立系统的顺序图和协作图---构造交互图
顺序图和协作图是反映用户和系统动态交互的两种视图。
顺序图按时间顺序描述系统元素之间的交互,而协作图则按照时间和空间顺序描述系统元素(包括系统用户)之间的交互和它们之间的动态关系。
二者都是表示对象间的交互作用,前者强调时间顺序,但没有明确的表达对象间的关系;后者描述对象之间的关系,但时间顺序必须从序号获得。
顺序图和协作图都是来自UML模型的相同信息,语义上是等价的,二者可以相互转换而不丢失任何信息。
实际使用中,常用时序图,即在顺序图的基础上,加入表示时间顺序的序号。
(1)图像导入时序图
(2)开闭运算计算时序图
(3)原始图像另存时序图
(4)开闭处理后图像保存时序图
类图的生成
类图(ClassDiagram)是在系统的领域概念模型基础上进一步添加对象的属性和方法生成的,它描述类、接口、协作、以及它们之间的关系,是系统设计的核心部分。
类图是系统静态视图的一部分,主要用于描述软件系统的静态结构,主要支持系统的功能需求,也即系统要提供给最终用户的服务。
类图也是面向对象系统建模中最常用的图,是定义其他图的基础。
在类图基础上,我们可以定义组件图、配置图,为代码生成做好准备。
在系统实现部分,表述,加入!
类名:
CImg-----------Img.h和Img.cpp
public:
voidClose();
voidOpen();
voidDilate();
voidGrayDilate(BYTE*pData);
voidErosion();
voidGrayErosion(BYTE*pData);
voidSort(int*pBuf,intl,intr);
voidMidFilter(intnWidth,intnHeight);
voidGrayErosion(intD);
voidSave8(LPCTSTRlpszPathName);
voidSave24(LPCTSTRlpszPathName);
voidSave(LPCTSTRlpszPathName,intnType);
voidDrawIntensity(CDC*pDC,BYTE*lpSrc,intnType);
voidShow(CDC*pDC,intx=0,inty=0,char*pStr=NULL);
voidF24to8(constBYTE*pSrc,BYTE*pDest);
voidF32to24(BYTE*lpBit);
voidF8To24(BYTE*lpBit);
BOOLInitial(LPCTSTRlpszPathName);
voidClean();
CImageProcess();
virtual~CImageProcess();
private:
BYTE*m_lpSrcBit;//图像像素数据(原始图像,左边图像)
BYTE*m_lpModifyBit1;//处理后的图像像素数据(中间图像)
BYTE*m_lpModifyBit2;//处理后的图像像素数据(右边图像)
BITMAPINFO*m_lpBmif;//图像信息头文件
char*m_sImgPath;//图像的路径
intm_nWidth;//图像宽度
intm_nHeight;//图像高度
BOOLm_bGray;
intm_nLineByte;//图像每行占的字节数(24位图像)
intm_nLineByte8;//图像每行占的字节数(8位图像)
intm_nImgByteSize;//图像的所占的字节大小
BYTE*m_lpSrcBit8;//8位位图数据
BYTE*m_lpModifyBit8;//8位位图数据
总体框架和界面设计
人机界面也称为用户界面,它是交互式应用软件系统的门面。
(1)用户打开系统主界面---系统功能的外部模型
运行可执行程序后,首先进入系统的主界面。
界面要求简单,符合用户习惯
(2)用户导入图像界面
(3)基于腐蚀膨胀的开闭图像处理界面
腐蚀
膨胀
开运算
闭运算
数据存储设计
设计数据存储的目的是将目标软件系统中依赖于系统运行环境的数据存取部分与其他部分相分离。
在本软件中,需要将处理后的图像保存到指定位置、指定格式、指定文件名。
3.系统设计
3.1建立工程
(1)New---Projects---MfcAppwizard---工程名
(2)SingleDocument…
(3)CScrollView…Finish.
3.2建立用户类CImg
(1)NewClass…
1)右击“工程名”…
2)双击C***Doc类,添加头文件#include"ImageProcess.h"
(2)添加成员变量…
private:
BYTE*m_lpSrcBit;//图像像素数据(原始图像,左边图像)
BYTE*m_lpModifyBit1;//处理后的图像像素数据(中间图像)(处理后为分形图像)
BYTE*m_lpModifyBit2;//处理后的图像像素数据(右边图像)(处理后为分割图像)
BITMAPINFO*m_lpBmif;//图像信息头文件
char*m_sImgPath;//图像的路径
intm_nWidth;//图像宽度
intm_nHeight;//图像高度
intm_nLineByte;//图像每行占的字节数(24位图像)
intm_nLineByte8;//图像每行占的字节数(8位图像)
intm_nImgByteSize;//图像的所占的字节大小
intm_nMse;//图像方差(计算图像直方图时使用)
BOOLm_bGray;
(3)依次添加成员函数并完成代码
1)CImg:
:
CImgeProcess()//构造函数:
用于对成员变量进行初始化;
m_lpSrcBit=NULL;
m_lpBmif=NULL;
m_lpModifyBit1=NULL;
m_lpModifyBit2=NULL;
m_nLineByte=1;
m_nLineByte8=1;
m_nHeight=1;
m_nWidth=1;
m_nImgByteSize=1;
m_sImgPath=NULL;
m_nMse=0;
m_pD=NULL;
m_pa=NULL;
m_pe=NULL;
m_Rmax=0;
m_Rmax2=0;
m_lpSrcBit8=NULL;
m_lpModifyBit8=NULL;
m_mes="";
m_sCodeTime="";
2)CImageProcess:
:
~CImageProcess()//析构函数;用于释放内存,避免内存泄露!
Clean();
3)voidCImageProcess:
:
Clean()//实际的释放内存函数
if(m_lpSrcBit!
=NULL)
{
delete[]m_lpSrcBit;
m_lpSrcBit=NULL;
}
if(m_lpModifyBit1!
=NULL)
{
delete[]m_lpModifyBit1;
m_lpModifyBit1=NULL;
}
if(m_lpModifyBit2!
=NULL)
{
delete[]m_lpModifyBit2;
m_lpModifyBit2=NULL;
}
if(m_lpBmif!
=NULL)
{
delete[]m_lpBmif;
m_lpBmif=NULL;
}
if(m_sImgPath!
=NULL)
{
delete[]m_sImgPath;
m_sImgPath=NULL;
}
if(m_pD!
=NULL)
{
delete[]m_pD;
m_pD=NULL;
}
if(m_pa!
=NULL)
{
delete[]m_pa;
m_pa=NULL;
}
if(m_pe!
=NULL)
{
delete[]m_pe;
m_pe=NULL;
}
if(m_lpSrcBit8!
=NULL)
{
delete[]m_lpSrcBit8;
m_lpSrcBit8=NULL;
}
if(m_lpModifyBit8!
=NULL)
{
delete[]m_lpModifyBit8;
m_lpModifyBit8=NULL;
}
4)BOOLInitial(LPCTSTRlpszPathName);//打开图像及其初始化工作
/*******************************************************
初始化函数
功能:
进行一系列的初始化操作,初始化位图的基本数据,
如长、宽,信息头等。
*******************************************************/
BOOLCImageProcess:
:
Initial(LPCTSTRlpszPathName)
{
//读取图像文件数据
CFilefile(lpszPathName,CFile:
:
modeRead);//使用MSDN讲解
DWORDlen=file.GetLength();
BYTE*pTemp=newBYTE[len];
if((file.ReadHuge(pTemp,len))!
=len)
{
AfxMessageBox("文件读取失败!
");
delete[]pTemp;
returnFALSE;
}
if(((BITMAPFILEHEADER*)pTemp)->bfType!
=*(WORD*)"BM")
{
AfxMessageBox("目前只支持BMP格式!
");
delete[]pTemp;
returnFALSE;
}
//清除上一次数据
Clean();
//取得文件头指针
BITMAPFILEHEADER*lpbmfh=(BITMAPFILEHEADER*)pTemp;
//取得信息头指针
BITMAPINFO*lpBMheader=(BITMAPINFO*)(lpbmfh+1);
//取得像素指针
BYTE*lpBit=(BYTE*)lpbmfh+lpbmfh->bfOffBits;;
/初始化图像信息
intnBitNum=lpBMheader->bmiHeader.biBitCount;
m_nWidth=lpBMheader->bmiHeader.biWidth;
m_nHeight=lpBMheader->bmiHeader.biHeight;
m_nLineByte=(m_nWidth*3*8+31)/32*4;
m_nLineByte8=(m_nWidth*8+31)/32*4;
m_nImgByteSize=m_nLineByte*m_nHeight;
//为像素数据申请存储空间
m_lpSrcBit=newBYTE[m_nHeight*m_nLineByte];
m_lpSrcBit8=newBYTE[m_nLineByte8*m_nLineByte];
m_lpModifyBit8=newBYTE[m_nLineByte8*m_nLineByte];//颜色数转换
if(nBitNum==8)
{
F8To24(lpBit);
}
elseif(nBitNum==32)
{
F32to24(lpBit);
}
elseif(nBitNum==24)
{
memcpy(m_lpSrcBit,lpBit,m_nHeight*m_nLineByte);}
else
{
AfxMessageBox("不支持的BMP格式!
");
delete[]pTemp;
Clean();
returnFALSE;
}
//保存图像文件的路径
m_sImgPath=newchar[MAX_PATH];
strcpy(m_sImgPath,lpszPathName);
//把信息头该为24位,8,32位统一按24位处理
lpBMheader->bmiHeader.biBitCount=24;
m_lpBmif=newBITMAPINFO;
memcpy(m_lpBmif,lpBMheader,sizeof(BITMAPINFO));
delete[]pTemp;
m_lpModifyBit1=newBYTE[m_nHeight*m_nLineByte];
memcpy(m_lpModifyBit1,m_lpSrcBit,m_nHeight*m_nLineByte);
m_lpModifyBit2=newBYTE[m_nHeight*m_nLineByte];
memcpy(m_lpModifyBit2,m_lpSrcBit,m_nHeight*m_nLineByt