直方图均衡化 图像处理程序的设计vc++.docx
《直方图均衡化 图像处理程序的设计vc++.docx》由会员分享,可在线阅读,更多相关《直方图均衡化 图像处理程序的设计vc++.docx(22页珍藏版)》请在冰豆网上搜索。
直方图均衡化图像处理程序的设计vc++
目录
1图像直方图均衡化设计…………………………………………………1
1.1设计要求………………………………………………………………1
1.2基本原理………………………………………………………………1
1.3设计方案及实现功能…………………………………………………3
2实现步骤…………………………………………………………………3
3部分主要程序代码………………………………………………………4
4运行结果及分析…………………………………………………………20
5心得体会…………………………………………………………………22
6参考文献…………………………………………………………………23
1图像直方图均衡化设计
1.1设计要求
要求用VC++实现如下功能:
(1)建立一个单文档的应用项目。
(2)在主框架添加菜单“图像处理”,并在此菜单下添加如下子菜单“显示原图像”、“显示原图像的直方图”、“图像直方图均衡化”、“显示均衡化处理后的直方图”。
(3)实现“显示原图像”功能,并以对话框的形式显示。
(4)实现“显示原图像直方图”功能,并以对话框的形式显示。
(5)实现“图像直方图均衡化”功能、实现“显示均衡化处理后的直方图”功能,并以对话框的形式显示。
1.2基本原理
图像的直方图包含了丰富的图像信息,描述了图像的灰度级内容,反映了图像的灰度分布情况。
图像直方图是图像处理中一种十分重要的图像分析工具,具有简单实用的特点,通过对图像的灰度值进行统计,可以得到一个一维离散的图像灰度统计、直方图函数。
直方图均衡化:
图像对比度增强的方法可以分成两类:
一类是直接对比度增强方法;另一类是间接对比度增强方法。
直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法。
直方图拉伸是通过对比度拉伸对直方图进行调整,从而“扩大”前景和背景灰度的差别,以达到增强对比度的目的,这种方法可以利用线性或非线性的方法来实现;直方图均衡化则通过使用累积函数对灰度值进行“调整”以实现对比度的增强。
直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。
直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。
直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。
缺点:
1)变换后图像的灰度级减少,某些细节消失;
2)某些图像,如直方图有高峰,经处理后对比度不自然的过分增强。
直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。
这种方法通常用来增加许多图像的局部对比度,尤其是当图像的有用数据的对比度相当接近的时候。
通过这种方法,亮度可以更好地在直方图上分布。
这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。
这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。
这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。
这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景杂讯的对比度并且降低有用信号的对比度。
直方图均衡化的基本思想是把原始图的直方图变换为均匀分布的形式,这样就增加了象素灰度值的动态范围从而可达到增强图像整体对比度的效果。
设原始图像在(x,y)处的灰度为f,而改变后的图像为g,则对图像增强的方法可表述为将在(x,y)处的灰度f映射为g。
在灰度直方图均衡化处理中对图像的映射函数可定义为:
g=EQ(f),这个映射函数EQ(f)必须满足两个条件(其中L为图像的灰度级数):
(1)EQ(f)在0≤f≤L-1范围内是一个单值单增函数。
这是为了保证增强处理没有打乱原始图像的灰度排列次序,原图各灰度级在变换后仍保持从黑到白(或从白到黑)的排列。
(2)对于0≤f≤L-1有0≤g≤L-1,这个条件保证了变换前后灰度值动态范围的一致性。
累积分布函数(cumulativedistributionfunction,CDF)即可以满足上述两个条件,并且通过该函数可以完成将原图像f的分布转换成g的均匀分布。
此时的直方图均衡化映射函数为:
gk=EQ(fk)=(ni/n)=pf(fi),
(k=0,1,2,……,L-1)
上述求和区间为0到k,根据该方程可以由源图像的各像素灰度值直接得到直方图均衡化后各像素的灰度值。
在实际处理变换时,一般先对原始图像的灰度情况进行统计分析,并计算出原始直方图分布,然后根据计算出的累计直方图分布求出fk到gk的灰度映射关系。
在重复上述步骤得到源图像所有灰度级到目标图像灰度级的映射关系后,按照这个映射关系对源图像各点像素进行灰度转换,即可完成对源图的直方图均衡化。
1.3设计方案及实现功能
利用VisualC++中提供的MFC框架设计一个简单的应用程序框架,具有图像显示,图像直方图均衡,直方图均衡后图像等菜单栏,再利用C++具有面向对象程序设计的性质,编写程序代码实现MFC框架中对应菜单栏中的图像处理的功能,即可得到一个简易的图像处理系统,达到课程考核题目的要求。
本次课程考核设计了一个简单的图片处理系统,主要具有以对话框的形式显示原始图片(bmp格式)、显示原图像的直方图、图像直方图均衡化、显示均衡化处理后的直方图的功能。
2实现步骤
步骤1:
创建单文档应用项目
启动VC,新建——工程——MFCAPPWizard[exe].定义工程名称VC,确定在选择单文档模式完成,实现出单文档项目的建立。
步骤2:
主框架菜单的添加
在VC的工作空间下方点Resources找到VC资源目录,从中看到Menu菜单项,点击打开。
然后看到主框架,双击一项或查看属性在标明里面可以修改显示字符。
按此次设计要求,在主框架一项上修改为图像处理,在其弹出打上勾,在弹出框里一次编辑“显示原图像”、“显示直方图”、“显示均衡化后直方图”、“显示直方图均衡化后的图像”。
ID定义留到依次设计此command功能的定义,以防弄混。
实现主框架菜单的添加。
步骤3:
BMP图像的打开
在主框架菜单第一项中,系统有一默认的文件,其下拉框有打开,对其进行类向导,选择在CVcview下,可观察到工作空间的classview中的CVcview下会出现ONFileOpend的类,由于应用OnPaint,此时在CVcview出点右键,AddwindowsMesssagesHander—然后选择WM_PAINT,添加Onpaint,此时可对ONFileOpen和Onpaint写入代码实现BMP图像文件的打开。
在完成写入代码的操作以后需将tools这一工具函数文件的、引入到工程中,先将tools,cpp与tool..h粘贴进入工程目录下,然后在工作空间中选择FileView一栏分别在SourcesFile和HeaderFile下添加cpp和h文件。
完成tools的添加。
此时需注意在程序开头打入include“tools.h”.
从而实现图像BMP文件的打开。
步骤4:
显示原图像的功能实现
在Menu中找到显示原图像这一command,首先定义ID为ID_XIAN_SHI,对其建立类向导如FileOpen。
然后再其中写入代码。
先可用MessageBox(“ok”)进行操作检验。
成功后,建立dlg,在Resources中Dialog里插入对话框。
将属性中标题改为显示原图,并建立类向导,生成新的class,定义名为XianShi,在其中添加OnPaint,OnInitDillog.此时对CVcview下的OnXianShi和XianShi下的onPaint和onInitdDalog分别写入代码,实现原图像的显示功能。
步骤5:
原图直方图的显示
操作步骤如同步骤四,详细见后续代码。
步骤6:
均衡化后的直方图显示
操作步骤如同步骤四,详细见后续代码。
步骤7:
显示均衡化之后的图像
操作步骤如同步骤四,详细见后续代码。
3部分主要程序代码
(1)BMP图像文件的打开程序代码
voidCVCView:
:
OnFileOpen()
{
//TODO:
Addyourcommandhandlercodehere
charfilt[220];
strcpy(filt,"BMPFiles(*.bmp)|*.bmp;|");
CFileDialogfd(true,"bmp",NULL,OFN_FILEMUSTEXIST,filt,this);
if(fd.DoModal()!
=IDOK)return;
CStringfname=fd.GetPathName();
fname1=fname;
fname.MakeUpper();
inti,dx,dy;
i=GetBmpSize(fname,&dx,&dy);
if(i==0)return;
UINT*buf=newUINT[dx*dy];
ReadBmp(fname,dx,dy,buf);
//显示图
mdr->overlay_rect(0,0,1000,1000,0xffffffff);//每次打开之前都要用白色刷一遍
mdr->write_video(0,0,dx,dy,buf);
mdr->swap();
deletebuf;//TODO:
Addyourcommandhandlercodehere
}
voidCVCView:
:
OnPaint()
{
CPaintDCdc(this);//devicecontextforpainting
//TODO:
Addyourmessagehandlercodehere
if(mdc==NULL)mdc=newCClientDC(this);
if(mdr==NULL)mdr=newmdraw(0,0,1000,600,mdc);
elsemdr->swap();
//DonotcallCView:
:
OnPaint()forpaintingmessages
}
(2)显示原图像程序代码
voidCVCView:
:
OnXianShi()
{
//TODO:
Addyourcommandhandlercodehere
//Dlg.DoModal();
XianShiDlg;
CStringstr;
inti,dx,dy;
i=GetBmpSize(fname1,&dx,&dy);
if(i==0)return;
UINT*buf=newUINT[dx*dy];
ReadBmp(fname1,dx,dy,buf);
Dlg.filename=fname1;
Dlg.buf=buf;
Dlg.DoModal();
deletebuf;
}
voidXianShi:
:
OnPaint()
{CPaintDCdc(this);
CClientDC*pDC=newCClientDC(this);
CBitmapm_bitmap;
HBITMAPhBitmap=(HBITMAP)LoadImage(NULL,_T(filename),IMAGE_BITMAP,
0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE);
m_bitmap.Attach(hBitmap);
CDCdcImage;
if(!
dcImage.CreateCompatibleDC(pDC))
return;
BITMAPbm;
m_bitmap.GetBitmap(&bm);
dcImage.SelectObject(&m_bitmap);
pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&dcImage,0,0,SRCCOPY);
this->SetWindowPos(NULL,NULL,NULL,bm.bmWidth+7,bm.bmHeight+30,SWP_NOMOVE);
(3)显示直方图程序代码
voidCVCView:
:
OnShowHist()
{
//TODO:
Addyourcommandhandlercodehere
//MessageBox("ok");
ShowHistDlg;
CStringstr;
inti,dx,dy;
i=GetBmpSize(fname1,&dx,&dy);
if(i==0)return;
UINT*buf=newUINT[dx*dy];
ReadBmp(fname1,dx,dy,buf);
Dlg.filename=fname1;
Dlg.buf=buf;
Dlg.DoModal();
deletebuf;
}
public:
ShowHist(CWnd*pParent=NULL);//standardconstructor
intm_nHist[256];
UINT*buf;
CStringfilename;
BOOLShowHist:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
//TODO:
Addextrainitializationhere
CStringstr;
inti,j,dx,dy;
unsignedchar*lpSrc;
CStringfname=this->filename;
//MessageBox(fname);
i=GetBmpSize(fname,&dx,&dy);
//str.Format("dx=%d,dy=%d",dx,dy);
//MessageBox(str);//成功得到图片的宽高
if(i==0)returnfalse;
UINT*buf=newUINT[dx*dy];
ReadBmp(fname,dx,dy,buf);
grade(buf,dx,dy);
for(i=0;i<255;i++){
m_nHist[i]=0;
}
intk;
for(i=0;ifor(j=0;jlpSrc=(unsignedchar*)(buf+dx*j+i);
//计数加1
m_nHist[*(lpSrc+1)]++;
}
}
returnTRUE;//returnTRUEunless
yousetthefocustoacontrol
//EXCEPTION:
OCXPropertyPagesshouldreturnFALSE
}
voidShowHist:
:
OnPaint()
{
CPaintDCdc(this);//devicecontextforpainting
//TODO:
Addyourmessagehandlercodehere
//循环变量
inti;
//获取绘制直方图文本框的标签
CWnd*pWnd=GetDlgItem(IDC_Show_Hist);//获得控件的句柄
//获取设备上下文
CDC*pDC=pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
pDC->Rectangle(0,0,400,203);//画一个矩形从而当做画直方图的区域
//创建画笔对象
CPen*pPenRed=newCPen;
//创建红色画笔(用于绘制坐标轴)
pPenRed->CreatePen(PS_SOLID,1,RGB(255,0,0));
//选入红色画笔,并保存以前的画笔
CPen*pOldPen=pDC->SelectObject(pPenRed);
//画直方图的坐标
//绘制y轴
pDC->MoveTo(20,20);
pDC->LineTo(20,180);
//绘制x轴
pDC->MoveTo(20,180);
pDC->LineTo(350,180);
//绘制X轴刻度值,x=20~276+30,y=20~180
CStringstrTemp;
strTemp.Format("0");
pDC->TextOut(20,184,strTemp);
strTemp.Format("50");
pDC->TextOut(70,184,strTemp);
strTemp.Format("100");
pDC->TextOut(120,184,strTemp);
strTemp.Format("150");
pDC->TextOut(170,184,strTemp);
strTemp.Format("200");
pDC->TextOut(220,184,strTemp);
strTemp.Format("255");
pDC->TextOut(270,184,strTemp);
//绘制X轴刻度
for(i=0;i<256;i+=5)
{
if((i&1)==0)//偶数,即10的倍数
{
pDC->MoveTo(i+20,180);
pDC->LineTo(i+20,184);
}
else//奇数,即5的奇数倍数
{
pDC->MoveTo(i+20,180);
pDC->LineTo(i+20,182);
}
}
//画横纵坐标的箭头
//绘制X轴箭头
pDC->MoveTo(350,180);
pDC->LineTo(345,175);
pDC->MoveTo(350,180);
pDC->LineTo(345,185);
//绘制Y轴箭头
pDC->MoveTo(20,20);
pDC->LineTo(25,25);
pDC->MoveTo(20,20);
pDC->LineTo(15,25);
//直方图中最大计数值
LONGlMaxCount=0;
//计算最大计数值
for(i=0;i<=255;i++)
{
//判断是否大于当前最大值
if(m_nHist[i]>lMaxCount)
{
//更新最大值
lMaxCount=m_nHist[i];
}
}
//输出最大计数值
pDC->MoveTo(20,25);
pDC->LineTo(14,25);
strTemp.Format("%d",lMaxCount);
pDC->TextOut(11,26,strTemp);
//声名画笔对象
CPen*pPenBlue=newCPen;
//创建蓝色画笔(用于绘制直方图)
pPenBlue->CreatePen(PS_SOLID,1,RGB(0,0,255));
//选入蓝色画笔
pDC->SelectObject(pPenBlue);
CStringstr;
//str.Format("lMaxCount=%d",lMaxCount);
//MessageBox(str);
//判断是否存在计数值
//str.Format("%d,%d",m_nHist[100],m_nHist[200]);
//MessageBox(str);//成功得到图片的宽高
if(lMaxCount>0){
//绘制直方图
for(i=0;i<255;i++)
{
pDC->MoveTo(i+20,180);
pDC->LineTo(i+20,180-(int)(m_nHist[i]*160/lMaxCount));
}
}
//恢复以前的画笔
pDC->SelectObject(pOldPen);
//删除新的画笔
deletepPenRed;
deletepPenBlue;
//DonotcallCDialog:
:
OnPaint()forpaintingmessages
}
(4)显示均衡化后的直方图程序代码
ShowBalanHistdlg;
voidCVCView:
:
OnShowBalanHist()
{
//TODO:
Addyourcommandhandlercodehere
//MessageBox("ok");
CStringstr;
inti,dx,dy;
i=GetBmpSize(fname1,&dx,&dy);
if(i==0)return;
UINT*buf=newUINT[dx*dy];
ReadBmp(fname1,dx,dy,buf);
dlg.filename=fname1;
dlg.buf=buf;
dlg.DoModal();
deletebuf;
}
classShowBalanHist:
publicCDialog
{
//Construction
structOld_DlgBal{
intk;//灰度级
intn;//各个灰度级的像素个数
floatp;//当前的灰度级出现的概率
floats;//当前的灰度级的累积概率
intt;//映射关系
};
structNew_DlgBal{
intk;//新的灰度级
intn;//相应的像素点个数
floatp;//新的灰度出现的概率
};
public:
ShowBalanHist(CWnd*pParent=NULL);//standardconstructor
CStringfilename;//打开的图像的文件名
UINT*buf;//内存缓冲区
Old_DlgBalm_oldHist[256];//旧的256个灰度值
New_DlgBalm_newHist[256];//新的256个灰度值