《数字图像处理》实验指导书.docx
《《数字图像处理》实验指导书.docx》由会员分享,可在线阅读,更多相关《《数字图像处理》实验指导书.docx(57页珍藏版)》请在冰豆网上搜索。
《数字图像处理》实验指导书
《数字图像处理》
实验指导书
编写:
罗建军
海南大学三亚学院
2009年10月
目录
一、概述1
二、建立程序框架1
三、建立图像类2
四、定义图像文档实现图像读/写9
五、实现图像显示11
六、建立图像处理类17
七、实现颜色处理功能18
(一)亮度处理18
(二)对比度处理21
(三)色阶处理22
(四)伽马变换24
(五)饱和度处理24
(六)色调处理28
八、实现几何变换功能28
(一)图像缩放28
(二)旋转30
(三)水平镜像34
(四)垂直镜像35
(五)右转90度35
(六)左转90度36
(七)旋转180度36
九、实现平滑锐化功能36
十、图像处理扩展编程37
一、概述
实验项目:
图像处理程序编程
运行环境:
WindowsXP/2000
编程工具:
VisualC++6.0
主要内容:
(1)建立程序框架,实现图像的读取、保存、显示;
(2)编写颜色处理、几何变换、平滑锐化等图像处理代码,并实现其调用;
(3)自行编写实现扩展的图像处理功能。
二、建立程序框架
预备工作:
在本机的硬盘上以自己完整的学号和姓名建立一个文件夹,如:
0810660044李剑。
上机编程的内容全部保存在该文件夹中。
每次下机前将该文件夹拷贝到网络服务器上本班的文件夹中;下次上机时再从服务器上将文件夹拷贝到本机。
1.新建应用程序
运行VisualC++6.0;
点击菜单“文件——新建”,打开“新建”对话框;
点击“工程”选项页;选中“MFCAppWizard(exe)”;在“位置”编辑框中选中自己所建立的文件夹;在“工程名称”编辑框中输入DIP?
?
?
,其中?
?
?
为自己姓名的拼音缩写,如DIPLJJ;按“确定”按钮,进入向导过程。
2.应用程序向导
步骤1:
选择“单文档”,其它不变,
步骤2:
不作改变,点击“下一步”;
步骤3:
不作改变,
步骤4:
取消“打印和打印预览”;按下“高级”按钮,在“文件扩展名”编辑框中输入bmp,关闭;点击“下一步”;
步骤5:
选择“作为静态的DLL”,点击“下一步”;
步骤6:
将CDIPLJJView类的基类选择为CScrollView,其它不变,点击“完成”。
点击“确定”。
3.应用程序框架及基本操作
在完成向导过程后,将建立一套应用程序框架,该框架中包含如下几个类:
CDIPLJJApp——应用程序类
CMainFrame——主窗口框架类
CDIPLJJDoc——文档类
CDIPLJJView——视图类
CAboutDlg——关于对话框类
(其中LJJ应换为自己姓名的拼音缩写,后同)
每个类都有一个类定义文件.h,和类实现文件.cpp。
在VC主界面左侧的组合窗口中,切换到“ClassViev”选项页,点击展开“DIPLJJClasses”,将列出该应用程序的所有类。
双击某个类,将在编辑窗口中打开该类的.h文件;点击展开类,双击类中已实现的某个成员函数,将打开该类的.cpp文件。
4.修改“关于”对话框
在VC主界面左侧的组合窗口中,切换到“ResourceView”选项页,展开“DIPLJJresources”,展开“Dialog”,双击“IDD_ABOUTBOX”,对“关于”对话框进行编辑,在“版权所有(C)2009”之前加上自己的学号和姓名,然后保存。
5.组建和运行程序
点击菜单“组建——组建”,或点击相应的工具条按钮,生成可执行程序(exe);
点击菜单“组建——执行”,或点击相应的工具条按钮,运行该程序,在程序中打开“关于”对话框。
三、建立图像类
1.建立类文件
点击菜单“插入——类”,打开“新建类”对话框;在类的类型中选中“GenericClass”;在名称中输入“LImage”;确定。
将建立LImage类的头文件LImage.h和源文件LImage.cpp。
2.编写类定义代码
打开LImage.h文件,将LImage类的定义代码添加到该头文件中(灰底部分为文件中已有的代码,后同):
classLImage
{
public:
LImage();
virtual~LImage();
BOOLCreate(inta_Width,inta_Height);
voidDestroy();
BOOLIsValid();
BOOLCopyFrom(LImage*a_pImg);
BOOLLoadBmpFile(CStringa_Filename);
BOOLSaveBitmap(CStringa_Filename);
//属性
intm_Width,m_Height;//图像的宽度,高度,以象素计
intm_WidthBytes;//每行象素所占字节数
intm_ImageSize;//象素数据总字节数
BYTE*m_pBits;//图像数据块
CDCm_DC;
//显示
BOOLBitBlt(HDCa_DestDC,inta_DestX,inta_DestY,inta_Width,inta_Height,
inta_SrcX,inta_SrcY,DWORDa_Rop=SRCCOPY);
BOOLStretchBlt(HDCa_DestDC,inta_DestX,inta_DestY,inta_DestWidth,
inta_DestHeight,inta_SrcX,inta_SrcY,inta_SrcWidth,inta_SrcHeight,
DWORDa_Rop=SRCCOPY);
intFitBlt(HDCa_DestDC,inta_DestX,inta_DestY,inta_DestWidth,inta_DestHeight,
inta_SrcX,inta_SrcY,inta_SrcWidth,inta_SrcHeight,DWORDa_Rop=SRCCOPY);
protected:
HBITMAPm_hBitmap;
HDCm_hMemDC;
private:
HBITMAPm_hOldBitmap;
};
#endif//!
defined(AFX_LIMAGE_H__4BFB411F_B5D3_4A26_8188_919613CED4A8__INCLUDED_)
3.编写类实现代码
打开LImage.cpp文件,将LImage类的实现代码添加到该文件中。
(1)构造及析构函数
LImage:
:
LImage()
{
m_hBitmap=NULL;
m_pBits=NULL;
m_hMemDC=NULL;
}
LImage:
:
~LImage()
{
Destroy();
}
(2)图像空间创建函数
按给定的图像尺寸分配图像的内存空间,并定义相关参数。
BOOLLImage:
:
Create(inta_Width,inta_Height)
{
Destroy();
if(a_Width==0||a_Height==0)returnFALSE;
if(a_Width<0)a_Width=-a_Width;
if(a_Height<0)a_Height=-a_Height;
BITMAPINFObi;
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth=a_Width;
bi.bmiHeader.biHeight=-a_Height;//使图像原点在左上角;若为正数则在左下角
bi.bmiHeader.biPlanes=1;
bi.bmiHeader.biBitCount=24;
bi.bmiHeader.biCompression=BI_RGB;
bi.bmiHeader.biSizeImage=0;
bi.bmiHeader.biXPelsPerMeter=11810;
bi.bmiHeader.biYPelsPerMeter=11810;
bi.bmiHeader.biClrUsed=0;
bi.bmiHeader.biClrImportant=0;
HDChdc=CreateCompatibleDC(NULL);
m_hBitmap=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&m_pBits,NULL,0);
DeleteDC(hdc);
if(m_hBitmap==NULL||m_pBits==NULL)
{
m_hBitmap=NULL;
m_pBits=NULL;
returnFALSE;
}
BITMAPbm;
GetObject(m_hBitmap,sizeof(BITMAP),&bm);
m_Width=bm.bmWidth;
m_Height=bm.bmHeight;
m_WidthBytes=bm.bmWidthBytes;
m_ImageSize=m_WidthBytes*m_Height;
m_hMemDC=CreateCompatibleDC(NULL);
if(m_hMemDC==NULL)
{
DeleteObject(m_hBitmap);
m_hBitmap=NULL;
m_pBits=NULL;
m_hMemDC=NULL;
returnFALSE;
}
m_hOldBitmap=(HBITMAP)SelectObject(m_hMemDC,m_hBitmap);
m_DC.Attach(m_hMemDC);
returnTRUE;
}
(3)图像空间释放函数
voidLImage:
:
Destroy()
{
if(m_hBitmap!
=NULL&&m_pBits!
=NULL&&m_hMemDC!
=NULL)
{
m_DC.Detach();
SelectObject(m_hMemDC,m_hOldBitmap);
DeleteDC(m_hMemDC);
DeleteObject(m_hBitmap);
}
m_hBitmap=NULL;
m_pBits=NULL;
m_hMemDC=NULL;
}
(4)图像有效性判别及图像复制函数
BOOLLImage:
:
IsValid()
{
return(m_hBitmap!
=NULL&&m_pBits!
=NULL&&m_hMemDC!
=NULL);
}
BOOLLImage:
:
CopyFrom(LImage*a_pImg)
{
if(a_pImg==NULL||!
a_pImg->IsValid())
returnFALSE;
if(!
Create(a_pImg->m_Width,a_pImg->m_Height))
returnFALSE;
memcpy((void*)m_pBits,(void*)a_pImg->m_pBits,m_WidthBytes*m_Height);
returnTRUE;
}
(5)图像显示函数
直接显示,缩放显示,按适合窗口的尺寸显示图像。
BOOLLImage:
:
BitBlt(HDCa_DestDC,inta_DestX,inta_DestY,inta_Width,inta_Height,
inta_SrcX,inta_SrcY,DWORDa_Rop)
{
return:
:
BitBlt(a_DestDC,a_DestX,a_DestY,a_Width,a_Height,
m_hMemDC,a_SrcX,a_SrcY,a_Rop);
}
BOOLLImage:
:
StretchBlt(HDCa_DestDC,inta_DestX,inta_DestY,inta_DestWidth,
inta_DestHeight,inta_SrcX,inta_SrcY,inta_SrcWidth,inta_SrcHeight,DWORDa_Rop)
{
:
:
SetStretchBltMode(a_DestDC,COLORONCOLOR);
return:
:
StretchBlt(a_DestDC,a_DestX,a_DestY,a_DestWidth,a_DestHeight,
m_hMemDC,a_SrcX,a_SrcY,a_SrcWidth,a_SrcHeight,a_Rop);
}
intLImage:
:
FitBlt(HDCa_DestDC,inta_DestX,inta_DestY,inta_DestWidth,
inta_DestHeight,inta_SrcX,inta_SrcY,inta_SrcWidth,inta_SrcHeight,DWORDa_Rop)
{
intdx,dy,dw,dh;
doublesx,sy;
sx=(double)a_SrcWidth/(double)a_DestWidth;
sy=(double)a_SrcHeight/(double)a_DestHeight;
if(sx<=1&&sy<=1)
{
dx=a_DestX+(a_DestWidth-a_SrcWidth)/2;
dy=a_DestY+(a_DestHeight-a_SrcHeight)/2;
dw=a_SrcWidth;
dh=a_SrcHeight;
}
elseif(sx>sy)
{
dx=a_DestX;
dw=a_DestWidth;
dh=(int)(a_SrcHeight/sx);
dy=a_DestY+(a_DestHeight-dh)/2;
}
elseif(sy>sx)
{
dw=(int)(a_SrcWidth/sy);
dx=a_DestX+(a_DestWidth-dw)/2;
dy=a_DestY;
dh=a_DestHeight;
}
else
{
dx=a_DestX;dy=a_DestY;
dw=a_DestWidth;dh=a_DestHeight;
}
:
:
SetStretchBltMode(a_DestDC,COLORONCOLOR);
:
:
StretchBlt(a_DestDC,dx,dy,dw,dh,
m_hMemDC,a_SrcX,a_SrcY,a_SrcWidth,a_SrcHeight,a_Rop);
if(a_SrcWidth!
=0)
return(int)(dw*100.0/a_SrcWidth+0.5);
else
return-1;
}
(6)Bmp文件读入函数
读入一个Bmp文件并将图像放入对象中。
BOOLLImage:
:
LoadBmpFile(CStringa_Filename)
{
FILE*pf=fopen(a_Filename,"rb");
if(pf==NULL)returnFALSE;
BITMAPFILEHEADERbmfHeader;
if(fread((LPSTR)&bmfHeader,1,sizeof(bmfHeader),pf)!
=sizeof(bmfHeader))
{fclose(pf);returnFALSE;}
if(bmfHeader.bfType!
=((WORD)('M'<<8)|'B'))
{fclose(pf);returnFALSE;}
intleng=bmfHeader.bfSize-sizeof(bmfHeader);
BYTE*pBmp=(BYTE*)calloc(leng,1);
if(pBmp==NULL)
{fclose(pf);returnFALSE;}
if((int)fread(pBmp,1,leng,pf)!
=leng)//读入位图文件头后的所有数据
{
free(pBmp);fclose(pf);
returnFALSE;
}
fclose(pf);
BYTE*pImg=(BYTE*)(pBmp+bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER));
BITMAPINFO*pbi;
pbi=(BITMAPINFO*)pBmp;
if(pbi->bmiHeader.biBitCount!
=24)
{free(pBmp);returnFALSE;}
intwidthBytes=((pbi->bmiHeader.biWidth*pbi->bmiHeader.biBitCount+31)/32)*4;
//将读入的bmp象素数据填入m_pBits
inti;
BYTE*p1,*p2;
RGBQUAD*ci=pbi->bmiColors;
if(Create(pbi->bmiHeader.biWidth,abs(pbi->bmiHeader.biHeight)))
{
intbytes=m_WidthBytes;
if(bytes>widthBytes)bytes=widthBytes;
for(i=0;i{
p1=m_pBits+i*m_WidthBytes;
if(pbi->bmiHeader.biHeight<0)//文件中扫描线由上向下存储
p2=pImg+i*widthBytes;
else//文件中扫描线由下向上存储
p2=pImg+(m_Height-1-i)*widthBytes;
memcpy(p1,p2,bytes);
}
free(pBmp);returnTRUE;
}
else
{free(pBmp);returnFALSE;}
}
(7)Bmp文件保存函数
将对象中的图像保存为Bmp文件。
BOOLLImage:
:
SaveBitmap(CStringa_Filename)
{
if(!
IsValid())returnFALSE;
FILE*pf=fopen(a_Filename,"wb");
if(pf==NULL)returnFALSE;
BITMAPINFO*pbmi;
pbmi=(BITMAPINFO*)calloc(1,sizeof(BITMAPINFOHEADER));
pbmi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth=m_Width;
pbmi->bmiHeader.biHeight=m_Height;
pbmi->bmiHeader.biPlanes=1;
pbmi->bmiHeader.biBitCount=24;
pbmi->bmiHeader.biCompression=BI_RGB;
UINTwidthBytes=((m_Width*24+31)/32)*4;
pbmi->bmiHeader.biSizeImage=widthBytes*m_Height;
pbmi->bmiHeader.biXPelsPerMeter=11810;
pbmi->bmiHeader.biYPelsPerMeter=11810;
pbmi->bmiHeader.biClrUsed=0;
pbmi->bmiHeader.biClrImportant=0;
BITMAPFILEHEADERhdr;//bitmapfile-header
BITMAPINFOHEADER*pbih;//bitmapinfo-header
pbih=(BITMAPINFOHEADER*)pbmi;
hdr.bfType=0x4d42;//0x42="B"0x4d="M"
hdr.bfSize=(DWORD)(sizeof(BITMAPFILEHEADER)+
pbih->biSize+pbih->biSizeImage);
hdr.bfReserved1=0;
hdr.bfReserved2=0;
hdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+pbih->biSize;
fwrite(&hdr,sizeof(BITMAPFILEHEADER),1,pf);//写入位图文件头
fwrite(pbih,sizeof(BITMAPINFOHEADER),1,pf);//写入位图信息头
inti;
BYTE*p1;
for(i=m_Height-1;i>=0;i--)
{
p1=m_pBits+m_WidthBytes*i;
if(fwrite(p1,1,widthBytes,pf)!
=widthBytes)
{free((HLOCAL)pbmi);fclose(pf);returnFALSE;}
}
free((HLOCAL)pbmi);
fclose(pf);
returnTRUE;
}
4.组建程序
在LImage.cpp处于当前编辑窗口时,点击菜单“组建——编译”,或点击相应的工具栏图标,对LImage.cpp进行编译。
在VC主界面下侧的组合窗口中将显示编译的状态。
当编译出现错误时,按F4键将定位到源程序的错误处,然后检查并改正错误。
四、定义图像文档实现图像读/写
1.添加头文件
在DIPLJJ.h文件中添加如下一行代码:
(其中灰色部分为程序中已有的代码,后同)
#include"resource.h"//mainsymbols
#include"L