用VC++实现图像阈值分割.docx
- 文档编号:9410416
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:17
- 大小:117.62KB
用VC++实现图像阈值分割.docx
《用VC++实现图像阈值分割.docx》由会员分享,可在线阅读,更多相关《用VC++实现图像阈值分割.docx(17页珍藏版)》请在冰豆网上搜索。
用VC++实现图像阈值分割
南昌航空大学实验报告
课题名称:
数字图像处理实验名称:
图像阈值分割
班级:
09045310姓名:
戴光涛同组人:
指导老师评定:
签名:
1、实验目的
用VC++实现位图阈值分割
2、实验内容与步骤
1、首先建立一个工程。
打开VC++6.0,单击文件【files】→新建【new】→工程【projects】在打开的projects下选择MFCAppWizard[exe]→在projectname下输入自己的工程名例如(Fenge)→单击【ok】→在打开的对话框中选择基于单文档【singledocument】→在第四步“MFCAppWizardstep4of6”面板中删掉【隐藏工具栏】和【打印和打印预览】两个选项,之后的全部选择默认,单击finish,出现一个“NewProjectInformation”窗口,单击【ok】。
一个简单的工程框架就建好了。
2、现在我们正式开始在新建工程Fenge中进行编程实现bmp位图的阈值分割。
点击左边框中的【ResourceView】框找到【Menu】点开,双击Menu下的图标,在右面的显示框中创建两个菜单:
打开ID:
ID_FILE_OPEN
阈值分割ID:
ID_YuZhiFenGe
3、给这两个菜单建立类向导。
在右边的窗口中右击“打开”,选择“建立类向导”,然后在打开的对话框中按下图1操作,“Classname”选择“CFengeView”→”ObjectIDs”中选择“ID_FILE_OPEN”→“Message”中选择“COMMAND”,点击“AddFunction”键就会在“Memberfunctions”中,然后点击“EditCode”,在自动生成的OnFileOpen函数中编写代码:
voidCFengenView:
:
OnFileOpen()
{
//TODO:
Addyourcommandhandlercodehere
CFileDialogfileDlg(true);
fileDlg.m_ofn.lpstrTitle="图片打开对话框";
fileDlg.m_ofn.lpstrFilter="BMPFiles(*.bmp)\0*.bmp\0\0";
if(IDOK==fileDlg.DoModal())
{
m_fileName.Format("%s",fileDlg.GetPathName());
m_Dib.LoadFile(m_fileName);
Invalidate();
}
}
图1
同理,操作“阈值分割”
图2
选择“CFengeView”。
点击“EditCode”,在自动生成“OnYuZhiFenGe”
函数中编写代码:
voidCFengenView:
:
OnYuZhiFenGe()
{
//TODO:
Addyourcommandhandlercodehere
if(m_Dib.IsValid())
{
inti;
intYuzhi;//阈值变量
//各颜色分量的灰度分布密度
floatmidu[256];
//计算灰度分布密度
m_Dib.Zhifangtu(midu);//调用灰度统计处理函数
//创建灰度直方图对话框
CDlgZhiFangTu*dlg;
dlg=newCDlgZhiFangTu(this);
dlg->Create(IDD_DIALOG_ZhiFangTu);
//传递灰度分布密度数据给面板类
for(i=0;i<256;i++)
dlg->m_fIntensity[i]=midu[i];
//显示对话框,由用户进行灰度折线变换
dlg->ShowWindow(SW_RESTORE);
//创建阈值选择对话框
CDlgYuZhiFenGedlg1;
dlg1.m_Yuzhi=0;
//显示对话框,提示用户输入阈值
if(dlg1.DoModal()==IDOK)
{
Yuzhi=dlg1.m_Yuzhi;
}
//删除对话框
deletedlg1;
deletedlg;
m_Dib.Yuzhifenge(Yuzhi);//调用阈值分割处理函数
//重绘
Invalidate();
}
}
4、创建一个处理位图的类CDib,且CDib类是由CObject类派生出来的。
点击工程菜单栏中的插入【insert】→【insertclass】→类类型选“GenericClass”,→类名称填“CDib”→【ok】。
可以看见工程窗口的ClassView中多了一个CDib类;点开CDib类的头文件,输入以下代码,注意变量可以直接复制,声明的函数不要直接复制(在CDib类右击选择“Addmemberfunction”,输入函数类型和函数名)。
classCDib:
publicCObject
{
public:
RGBQUAD*m_pRGB;
BYTE*m_pData;
UINTm_numberOfColors;
boolm_valid;
BITMAPFILEHEADERbitmapFileHeader;//定义了一个文件头结构体的对象
BITMAPINFOHEADER*m_pBitmapInfoHeader;//定义了一个指向信息头的结构体指针
BITMAPINFO*m_pBitmapInfo;//定义了一个结构体指针,BITMAPINFO是一个包含有信息头,和调色板的结构体
intbyBitCount;
DWORDdwWidthBytes;
BYTE*pDib;
DWORDsize;
charm_fileName[256];
public:
voidYuzhifenge(intYuzhi);
voidZhifangtu(float*tongji);
voidLoadFile(constchar*dibFileName);
voidSaveFile(constCStringfilename);
WORDDIBNumColors(LPBYTElpDIB);
WORDPaletteSize(LPBYTElpDIB);
BITMAPINFO*GetInfo();
BYTE*GetData();
RGBQUAD*GetRGB();
UINTGetNumberOfColors();
UINTGetHeight();
UINTGetWidth();
DWORDGetSize();
boolIsValid();
char*GetFileName();
CDib();
virtual~CDib();
};
6、对CDib类中的函数定义,找到Dib.cpp输入代码:
CDib:
:
CDib()
{
m_numberOfColors=0;
size=0;
m_valid=0;
byBitCount=0;
dwWidthBytes=0;
}
CDib:
:
~CDib()
{
GlobalFreePtr(m_pBitmapInfo);
}
char*CDib:
:
GetFileName()
{
returnm_fileName;
}
boolCDib:
:
IsValid()
{
returnm_valid;
}
DWORDCDib:
:
GetSize()
{
if(m_pBitmapInfoHeader->biSizeImage!
=0)
{
returnm_pBitmapInfoHeader->biSizeImage;
}
else
{
DWORDheight=(DWORD)GetHeight();
DWORDwidth=(DWORD)GetWidth();
returnheight*width;
}
}
UINTCDib:
:
GetHeight()
{
return(UINT)m_pBitmapInfoHeader->biHeight;
}
UINTCDib:
:
GetNumberOfColors()
{
intnumberOfColors;
if((m_pBitmapInfoHeader->biClrUsed==0)&&
(m_pBitmapInfoHeader->biBitCount<9))
//biClrUsed表示实际用到的颜色数,若0为2的biBitCount次中颜色
//biBitCount为用到的颜色的位数,小于9则表示最大为8位,那么之多为256色
{
switch(m_pBitmapInfoHeader->biBitCount)
{
case1:
numberOfColors=2;break;
case4:
numberOfColors=16;break;
case8:
numberOfColors=256;break;
}
}
else//若不是上面的情况,则直接返回颜色数
{
numberOfColors=(int)m_pBitmapInfoHeader->biClrUsed;
}
returnnumberOfColors;
}
RGBQUAD*CDib:
:
GetRGB()
{
returnm_pRGB;
}
BYTE*CDib:
:
GetData()
{
returnm_pData;
}
BITMAPINFO*CDib:
:
GetInfo()
{
returnm_pBitmapInfo;
}
WORDCDib:
:
PaletteSize(LPBYTElpDIB)
{
return(DIBNumColors(lpDIB)*sizeof(RGBTRIPLE));
}
WORDCDib:
:
DIBNumColors(LPBYTElpDIB)
{
WORDwBitCount;//DIBbitcount
wBitCount=((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
switch(wBitCount)
{
case1:
return2;
case4:
return16;
case8:
return256;
default:
return0;
}
}
voidCDib:
:
SaveFile(constCStringfilename)
{
strcpy(m_fileName,filename);
CFiledibFile(m_fileName,CFile:
:
modeCreate|CFile:
:
modeWrite);
dibFile.Write((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
dibFile.Write((void*)pDib,size);
dibFile.Close();
}
voidCDib:
:
LoadFile(constchar*dibFileName)
{
strcpy(m_fileName,dibFileName);//将路径名称拷贝到m_fileName之中
CFiledibFile(m_fileName,CFile:
:
modeRead);//创建CFile类对象,只读方式
dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));//读取文件头的内容
if(bitmapFileHeader.bfType==0x4d42)//判断是否为bmp格式,单步调试你会发现,此时的bfType值
{
DWORDfileLength=dibFile.GetLength();//读取文件的大小,你可以试试跟踪此值来看看它是否和你要打开的图片大小一致
size=fileLength-sizeof(BITMAPFILEHEADER);;//文件大小-文件头结构体的大小,此时你会发现,文件头的大小的确是14字节
pDib=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size);//详见说明
(2)
dibFile.Read((void*)pDib,size);//通过读取,把读出的数据存入刚才分配的内存之中
dibFile.Close();//文件操作完成之后关闭文件
m_pBitmapInfo=(BITMAPINFO*)pDib;//BITMAPINFO结构体指针指向该内存
m_pBitmapInfoHeader=(BITMAPINFOHEADER*)pDib;//信息头指向该内存
m_pRGB=(RGBQUAD*)(pDib+m_pBitmapInfoHeader->biSize);//调色板指针指向该内存的调色板部分。
因为pDib原本指向信息头,偏移40字节(信息头结构体的大小)之后便到了调色板部分,因此用加法来实现指针的偏移
intm_numberOfColors=GetNumberOfColors();//调用GetNumberOfColors函数来得到颜色数
if(m_pBitmapInfoHeader->biClrUsed==0)
{
m_pBitmapInfoHeader->biClrUsed=m_numberOfColors;//把颜色数赋予biClrUsed之中
}
DWORDcolorTableSize=m_numberOfColors*
sizeof(RGBQUAD);//用每个调色板结构体大小乘以颜色数量,得到调色板的大小
m_pData=pDib+m_pBitmapInfoHeader->biSize+colorTableSize;
//这时候代表把m_pData指针指向实际图像数据了
if(m_pRGB==(RGBQUAD*)m_pData)//如果调色板指针位置和实际图像位置指针指向位置相同,那就代表没有调色板
{
m_pRGB=NULL;//指针赋予空
}
m_pBitmapInfoHeader->biSizeImage=GetSize();//赋予实际位图的大小
m_valid=true;
}
else//如果不是bmp位图则失败
{
m_valid=false;
AfxMessageBox("Thisisn'tabitmapfile!
");
}
}
UINTCDib:
:
GetWidth()
{
return(UINT)m_pBitmapInfoHeader->biWidth;
}
voidCDib:
:
Zhifangtu(float*tongji)
{
//循环变量
inti;
intj;
//灰度计数
inthuidu[256];
intwide,height;//原图长、宽
//变量初始化
memset(huidu,0,sizeof(huidu));
if(m_pBitmapInfoHeader->biBitCount<9)//灰度图像
{
wide=this->GetWidth();
height=this->GetHeight();
intwidth=(((wide*24)+31)/32*4);
LPBYTEtemp1=newBYTE[wide*height+1024];//新图像缓冲区
//拷贝原图像到缓存图像
memcpy(temp1,m_pData,wide*height);
//对各像素进行灰度统计
for(i=0;i { for(j=0;j { unsignedchartemp=temp1[wide*i+j]; //灰度统计计数 huidu[temp]++; } } //计算灰度分布密度 for(i=0;i<256;i++) tongji[i]=huidu[i]/(height*wide*1.0f); } } voidCDib: : Yuzhifenge(intYuzhi) { //指向源图像的指针 LPBYTEp_data; LPBYTElpSrc; //指向缓存图像的指针 LPBYTElpDst; //指向缓存DIB图像的指针 LPBYTEtemp; //循环变量 longi; longj; //图像的高和宽 longwide; longheight; p_data=GetData(); wide=GetWidth(); height=GetHeight(); temp=newBYTE[wide*height]; memset(temp,255,wide*height); for(j=0;j { for(i=0;i { lpSrc=p_data+wide*j+i; lpDst=temp+wide*j+i; if(abs(*lpSrc-Yuzhi)<30) *lpDst=Yuzhi; } } memcpy(p_data,temp,wide*height); deletetemp; } 7、创建一个对话框类CDlgYuZhiFenGe和CDlgZhiFangTu,且CDlgYuZhiFenGe和CDlgZhiFangTu类是由CDialog类派生出来的。 点击工程菜单栏中的【插入】→【窗体】→名称填“CDlgYuZhiFenGe”,→基类填“CDialog”→【确定】。 可以看见工程窗口的ClassView中多了一个CDlgYuZhiFenGe类;CDlgZhiFangTu类同理。 8、在资源视图中做两个界面,分别为 阈值选择ID: IDD_DIALOG_YuZhiFenGe 直方图灰度统计ID: IDD_DIALOG_ZhiFangTu 做“阈值选择”界面如下图3, 阈值ID: IDC_STATIC(默认) 编辑ID: IDC_EDIT1(默认) 右键编辑框,选“类向导”→“MemberVariable”选项卡中点“IDC_EDIT1”→“AddVariable”,弹出的对话框中如下图4填: 在资源视图中做“直方图灰度统计”界面如图5,并在灰度直方图统计中添加“图像“控件,图像控件的ID为IDC_COORD(默认)。 添加CDlgZhiFangTu的类向导,在灰度直方图对话框上右键点击建立类向导,设置如下图 9、找到类CFengeView中的OnDraw(CDC*pDC)函数输入以下代码: voidCFengenView: : OnDraw(CDC*pDC) { CFengenDoc*pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO: adddrawcodefornativedatahere if(m_Dib.IsValid()) { BYTE*pBitmapData=m_Dib.GetData(); LPBITMAPINFOpBitmapInfo=m_Dib.GetInfo(); intbitmapHeight=m_Dib.GetHeight(); intbitmapWidth=m_Dib.GetWidth(); intscaleWidth=(int)(bitmapWidth*m_scale); intscaleHeitht=(int)(bitmapHeight*m_scale); : : StretchDIBits(pDC->GetSafeHdc(),0,0,scaleWidth,scaleHeitht,0,0,bitmapWidth,bitmapHeight,pBitmapData,pBitmapInfo,DIB_RGB_COLORS,SRCCOPY); } } 10、找到类CFengeView中的“CFengeView: : CFengeView()”函数输入以下代码: CFengeView: : CFengeView() { //TODO: addconstructioncodehere m_scale=1; m_fileName=""; } 11、最后编译。 提示: 需要加入头文件,各个变量。 特别的floatm_fIntensity[256]; 提示定义GlobalFreePtr和GlobalAllocPtr,需要加入头文件#include"windowsx.h" 三、实验截图 阈值分割前: 阈值分割: 阈值输入: 125 阈值分割后: 四、实验小结 通过本次实验,基本掌握了用VC++实现图像阈值分割,并且对其原理也有一定的了解,巩固了书本中所介绍的知识。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC 实现 图像 阈值 分割