数字图像处理
实验指导
书
关于书的成语关于读书的排比句社区图书漂流公约怎么写关于读书的小报汉书pdf
山东大学威海分校机电与信息工程学院
2012年3月
概述
实验项目:数字图像处理程序编程
运行环境:Windows XP/7
编程工具:Visual C++ 6.0
主要内容:
(1) 建立程序框架,实现图像的读取、保存、显示;
(2) 编写颜色处理、几何变换、平滑锐化等图像处理代码,并实现其调用;
(3) 自行编写实现扩展的图像处理功能。
第一节 建立程序框架
预备工作:在本机的硬盘上以自己完整的学号和姓名建立一个文件夹。上机编程的内容全部保存在该文件夹中。每次下机前将该文件夹拷贝到网络服务器上本班的文件夹中;下次上机时再从服务器上将文件夹拷贝到本机。
1. 新建应用程序
1.1运行Visual C++ 6.0;
1.2 点击菜单“文件——新建”,打开“新建”对话框(Ctrl+N);
点击“工程”选项页;选中“MFC AppWizard(exe)”;在“位置”编辑框中选中自己所建立的文件夹;在“工程名称”编辑框中输入DIPXXX,其中XXX为自己姓名的拼音缩写和学号,如DIPJQ;按“确定”按钮,进入向导过程。
2. 应用程序向导
步骤1:选择“单文档”,其它不变,
步骤2:不作改变,点击“下一步”;
步骤3:不作改变,
步骤4:按下“高级”按钮,在“文件扩展名”编辑框中输入bmp,关闭;点击“下一步”;
步骤5:选择“作为静态的DLL”,点击“下一步”;
步骤6:将CDIPJQView类的基类选择为CScrollView,其它不变,点击“完成”。
点击“确定”。
3. 应用程序框架及基本操作
在完成向导过程后,将建立一套应用程序框架,该框架中包含如下几个类:
CDIPJQApp ——应用程序类
CMainFrame ——主窗口框架类
CDIPJQDoc ——文档类
CDIPJQView ——视图类
CAboutDlg ——关于对话框类
(其中JQ应换为自己姓名的拼音缩写和学号,后同)
每个类都有一个类定义文件.h,和类实现文件.cpp。
在VC主界面左侧的组合窗口中,切换到“ClassViev”选项页,点击展开“DIPJQ Classes”,将列出该应用程序的所有类。双击某个类,将在编辑窗口中打开该类的.h文件;点击展开类,双击类中已实现的某个成员函数,将打开该类的.cpp文件。
4. 修改“关于”对话框
在VC主界面左侧的组合窗口中,切换到“ResourceView”选项页,展开“DIPJQresources”,展开“Dialog”,双击“IDD_ABOUTBOX”,对“关于”对话框进行编辑,在“版权所有 (C) 2009”之前加上自己的学号和姓名,然后保存。
5. 组建和运行程序
点击菜单“组建——组建”,或点击相应的工具条按钮(F7),生成可执行程序(exe);
点击菜单“组建—执行”,或点击相应的工具条按钮(Ctrl+F5),运行该程序,在程序中打开“关于”对话框。
第二节 建立图像类
1. 建立类文件
点击菜单“插入—类”,打开“新建类”对话框;在类的类型中选中“Generic Class”;在名称中输入“SDImage”;确定。建立起SDImage类的头文件SDImage.h和源文件SDImage.cpp。
2. 编写类定义代码
打开SDImage.h文件,将SDImage类的定义代码添加到该头文件中(灰底部分为文件中已有的代码,后同):
class SDImage
{
public:
BOOL CopyFrom(SDImage *a_pImg);
BOOL Create(int a_Width,int a_Height);
int FitBlt(HDC a_DestDC,int a_DestX,int a_DestY,int a_DestWidth,int a_DestHeight,int a_SrcX,int a_SrcY,int a_SrcWidth,int a_SrcHeight,DWORD a_Rop=SRCCOPY);
BOOL StretchBlt(HDC a_DestDC,int a_DestX,int a_DestY,int a_DestWidth,int a_DestHeight,int a_SrcX,int a_SrcY,int a_SrcWidth,int a_SrcHeight,DWORD a_Rop=SRCCOPY);
BOOL BitBlt(HDC a_DestDC,int a_DestX,int a_DestY,int a_Width,int a_Height,int a_SrcX,int a_SrcY,DWORD a_Rop=SRCCOPY);
BOOL SaveBitmap(CString a_Filename);
BOOL IsValid();
void Destroy();
CDC m_DC;
BYTE * m_pBits;
int m_ImageSize;
int m_WidthBytes;
int m_Height;
BOOL LoadBmpFile(CString a_Filename);
int m_Width;
SDImage();
virtual ~SDImage();
protected:
HDC m_hMemDC;
HBITMAP m_hBitmap;
private:
HBITMAP m_hOldBitmap;
};
#endif // !defined(AFX_SDIMAGE_H__BA98791A_D437_4687_AAEA_B988391C2FCC__INCLUDED_)
***添加成员变量和成员函数
右键单击左侧类中SDImage类,选择添加成员变量。
右键单击左侧类中SDImage类,选择添加成员函数。
3. 编写类实现代码
打开SDImage.cpp文件,将SDImage类的实现代码添加到该文件中。
(1) 构造及析构函数
SDImage:: SDImage()
{
m_hBitmap = NULL;
m_pBits = NULL;
m_hMemDC = NULL;
}
SDmage::~ SDmage()
{
Destroy();
}
(2) 图像空间创建函数
按给定的图像尺寸分配图像的内存空间,并定义相关参数。
BOOL SDImage::Create(int a_Width, int a_Height)
{
Destroy();
if( a_Width==0 || a_Height==0 )
return FALSE;
if( a_Width<0 ) a_Width = -a_Width;
if( a_Height<0 ) a_Height = -a_Height;
BITMAPINFO bi;
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;
HDC hdc=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;
return FALSE;
}
BITMAP bm;
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;
return FALSE;
}
m_hOldBitmap = (HBITMAP)SelectObject(m_hMemDC,m_hBitmap);
m_DC.Attach(m_hMemDC);
return TRUE;
}
(3) 图像空间释放函数
void SDImage::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) 图像有效性判别及图像复制函数
BOOL SDImage::IsValid()
{
return ( m_hBitmap!=NULL && m_pBits!=NULL && m_hMemDC!=NULL );
}
BOOL SDImage::CopyFrom(SDImage *a_pImg)
{
if( a_pImg==NULL || !a_pImg->IsValid() )
return FALSE;
if( !Create(a_pImg->m_Width, a_pImg->m_Height) )
return FALSE;
memcpy(
(void*)m_pBits, (void*)a_pImg->m_pBits, m_WidthBytes*m_Height );
return TRUE;
}
(5) 图像显示函数
直接显示,缩放显示,按适合窗口的尺寸显示图像。
BOOL SDImage::BitBlt(HDC a_DestDC, int a_DestX, int a_DestY, int a_Width, int a_Height, int a_SrcX, int a_SrcY, DWORD a_Rop)
{
return ::BitBlt(a_DestDC, a_DestX, a_DestY, a_Width, a_Height,m_hMemDC, a_SrcX, a_SrcY, a_Rop)
}
BOOL SDImage::StretchBlt(HDC a_DestDC, int a_DestX, int a_DestY, int a_DestWidth, int a_DestHeight, int a_SrcX, int a_SrcY, int a_SrcWidth, int a_SrcHeight, DWORD a_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);
}
(6) Bmp文件读入函数
BOOL SDImage::LoadBmpFile(CString a_Filename)
{
FILE *pf = fopen(a_Filename,"rb");
if( pf==NULL ) return FALSE;
BITMAPFILEHEADER bmfHeader;
if ( fread((LPSTR)&bmfHeader,1,sizeof(bmfHeader),pf) != sizeof(bmfHeader) )
{
fclose(pf); return FALSE;
}
if( bmfHeader.bfType != ((WORD)('M'<<8) | 'B') )
{
fclose(pf); return FALSE;
}
int leng = bmfHeader.bfSize - sizeof(bmfHeader);
BYTE *pBmp = (BYTE *)calloc(leng,1);
if( pBmp == NULL )
{
fclose(pf); return FALSE;
}
if ( (int)fread(pBmp,1,leng,pf) != leng )
{
free(pBmp); fclose(pf);
return FALSE;
}
fclose(pf);
BYTE *pImg=(BYTE*)(pBmp + bmfHeader.bfOffBits - sizeof(BITMAPFILEHEADER));
BITMAPINFO *pbi;
pbi = (BITMAPINFO*)pBmp;
if( pbi->bmiHeader.biBitCount != 24 )
{
free(pBmp); return FALSE;
}
int widthBytes = ((pbi->bmiHeader.biWidth*pbi->bmiHeader.biBitCount+31)/32)*4;
int i;
BYTE *p1,*p2;
RGBQUAD *ci = pbi->bmiColors;
if( Create( pbi->bmiHeader.biWidth, abs(pbi->bmiHeader.biHeight) ) )
{
int bytes = m_WidthBytes;
if( bytes>widthBytes ) bytes = widthBytes;
for(i=0;i
bmiHeader.biHeight<0 )
p2 = pImg + i*widthBytes;
else
p2 = pImg + (m_Height-1-i)*widthBytes;
memcpy(p1,p2,bytes);
}
free(pBmp); return TRUE;
}
else
{free(pBmp); return FALSE; }
}
(7) Bmp文件保存函数
BOOL SDImage::SaveBitmap(CString a_Filename)
{
if( !IsValid() ) return FALSE;
FILE *pf = fopen(a_Filename,"wb");
if( pf==NULL ) return FALSE;
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;
UINT widthBytes = ((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;
BITMAPFILEHEADER hdr;
BITMAPINFOHEADER *pbih;
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);
int i;
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); return FALSE;
}
}
free((HLOCAL)pbmi);
fclose(pf);
return TRUE;
}
4. 组建程序
在SDImage.cpp处于当前编辑窗口时,点击菜单“组建—编译”,或点击相应的工具栏图标,对SDImage.cpp进行编译。在VC主界面下侧的组合窗口中将显示编译的状态。当编译中出现错误时,按F4键将依次定位到源程序的错误处,请检查并改正错误。
第四节 定义图像文档实现图像读/写
1. 添加头文件
在DIPJQ.h文件中添加如下一行代码:(其中灰色部分为程序中已有的代码,后同)
#include "resource.h" // main symbols
#include "SDImage.h"
2. 定义图像类指针
在DIPJQDoc.h文件中添加如下一行代码:
// Attributes
public:
class SDImage *m_pCurImage,*m_pLastImage;
注:定义两个图像类的指针,以使程序具备对最近一次处理的恢复功能。
3. 图像对象的建立和释放
在“ClassView”选项页中,点击展开“CDIPJQDoc”,双击“CDIPJQDoc()”,打开DIPJQDoc.cpp文件,在文件中修改添加如下代码:
CDIPJQDoc::CDIPJQDoc()
{
// TODO: add one-time construction code here
m_pCurImage = new SDImage;
m_pLastImage = new SDImage;
}
CDIPJQDoc::~CDIPJQDoc()
{
delete m_pCurImage;
delete m_pLastImage;
}
4. 进行消息映射
点击菜单“查看—建立类向导”,打开“MFC ClassWizard”对话框(Ctrl+w)。在“Class Name”下拉框中选中“CDIPJQDoc”,在“Object IDs”列
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
框中选中“CDIPJQDoc”,然后在“Messgaes”列表框中,选中“OnOpenDocument”并双击,建立起相应的消息映射函数;再选中“OnSaveDocument”双击。
在“Object IDs”列表框中选中“ID_EDIT_UNDO”,然后在“Message”列表框中双击“COMMAND”,建立起相应的消息映射函数。
5. 添加消息映射函数代码
在“ClassView”选项页中,点击展开“CDIPJQDoc”,双击“OnOpenDocument(LPCTSTR lpszPathName)”,打开DIPJQDoc.cpp文件,在文件中添加如下代码:
BOOL CDIPJQDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
// TODO: Add your specialized creation code here
return m_pCurImage->LoadBmpFile(lpszPathName);
}
BOOL CDIPJQDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
// TODO: Add your specialized code here and/or call the base class
return m_pCurImage->SaveBitmap(lpszPathName);
}
void CDIPJQDoc::OnEditUndo()
{
// TODO: Add your command handler code here
if( m_pCurImage->IsValid() && m_pLastImage->IsValid() )
{
SDImage *p = m_pCurImage;
m_pCurImage = m_pLastImage;
m_pLastImage = p;
UpdateAllViews(NULL);
}
}
点击菜单“组建——组建”,再次组建整个程序,排除组建过程中出现的错误。
***此时运行程序,图像数据可以读入,但是无法显示图像。
第五节 实现图像显示
1. 定义显示控制变量
在DIPJQView.h文件中添加两个显示控制变量。
public:
CDIPJQDoc* GetDocument();
int m_ShowMode;
int m_ShowScale;
在DIPJQView.cpp文件中定义两个显示模式枚举常量,在构造函数中给显示控制参数赋初值。
enum {SHOWMODE_SCALE, SHOWMODE_FIT};
CDIPJQView::CDIPJQView()
{
// TODO: add construction code here
m_ShowMode = SHOWMODE_FIT;
m_ShowScale = 100;
}
2. 图像显示代码
在CDIPJQView类的OnDraw()函数中添加图像显示代码。
void CDIPJQView::OnDraw(CDC* pDC)
{
CDIPJQDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CRect rect;
if( m_ShowMode == SHOWMODE_FIT )
{
GetClientRect(&rect);
m_ShowScale = pDoc->m_pCurImage->FitBlt(pDC->m_hDC,0,0,rect.Width(),
rect.Height(),0,0,pDoc->m_pCurImage->m_Width,
pDoc->m_pCurImage->m_Height);
}
else
{
CSize size;
size = GetTotalSize();
GetClientRect(&rect);
int x0=0,y0=0;
if( rect.Width()>size.cx )
x0 = (rect.Width()-size.cx)/2;
if( rect.Height()>size.cy )
y0 = (rect.Height()-size.cy)/2;
if( m_ShowScale==100 )
pDoc->m_pCurImage->BitBlt(pDC->m_hDC,x0,y0,pDoc->m_pCurImage->m_Width,
pDoc->m_pCurImage->m_Height,0,0);
else
pDoc->m_pCurImage->StretchBlt(pDC->m_hDC,x0,y0,size.cx,size.cy,
0,0,pDoc->m_pCurImage->m_Width,pDoc->m_pCurImage->m_Height);
}
}
3. 图像区域设置代码
在CDIPJQView类的OnInitialUpdate()函数中添加视图滚动区域设置代码。
void CDIPJQView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CDIPJQDoc* pDoc = GetDocument();
CSize sizeTotal;
// TODO: calculate the total size of this view
if( pDoc->m_pCurImage->IsValid() )
{
if( m_ShowMode==SHOWMODE_FIT )
{
CRect rect;
this->GetClientRect(&rect);
sizeTotal.cx = rect.Width();
sizeTotal.cy = rect.Height();
}
else
{
sizeTotal.cx = (int)(pDoc->m_pCurImage->m_Width*m_ShowScale/100.0+0.5);
sizeTotal.cy = (int)(pDoc->m_pCurImage->m_Height*m_ShowScale/100.0+0.5);
}
//
((CMainFrame*)AfxGetApp()->m_pMainWnd)->ShowScale(m_ShowScale);
}
else
{
sizeTotal.cx = sizeTotal.cy = 100;
}
SetScrollSizes(MM_TEXT, sizeTotal);
}
4. 修整程序菜单
切换到“ResourceView”选项页,展开“DIPJQ resources”,展开“Menu”,双击“IDR_MAINFRAME”,对菜单进行编辑。在各顶层菜单下保留如下菜单项,其余删除。
文件:打开,保存,另存为,最近文件,退出 编辑:撤消
查看:工具栏,状态栏 帮助:关于
5. 添加显示操作菜单
点击顶层菜单“查看”,双击下部空白菜单项,打开“菜单项目 属性”对话框,在ID下拉列表框中输入“ID_SHOW_ENLARGE”,在标明编辑框中输入“放大”,在提示编辑框中输入“放大显示图象\n放大”。关闭对话框,将该菜单项拖至最上部。
继续依次建立如下三个菜单项:
ID
标明
提示
ID_SHOW_REDUCE
缩小
缩小显示图象\n缩小
ID_SHOW_ORIGINAL
原始尺寸
按原始尺寸显示图象\n原始尺寸
ID_SHOW_FIT
适合窗口
使图象完整显示在窗口中\n适合窗口
点击顶层菜单“查看”,双击下部空白菜单项,在“菜单项目 属性”对话框中,选中“分隔符”,关闭对话框,将分隔符拖至“工具栏”菜单项之上,“适合窗口”之下。
6. 编辑工具栏
切换到“ResourceView”选项页,展开“DIPJQ resources”,展开“Toolbar”,双击“IDR_MAINFRAME”,对工具栏进行编辑。
保留打开、保存、关于三个按钮,删除其它按钮。
添加“撤消”按钮:点中最后的空白按钮,绘制撤消图形,双击该按钮,将ID设为“ID_EDIT_UNDO”,将按钮拖至保存按钮之后。
再依次添加如下四个按钮:
放大——ID_SHOW_ENLARGE
缩小——ID_SHOW_REDUCE
原始尺寸——ID_SHOW_ORIGINAL
适合屏幕——ID_SHOW_FIT
工具栏中个按钮的形状如下:
7. 进行消息映射
点击菜单“查看—>建立类向导”,打开“MFC ClassWizard”对话框(Ctrl+w)。在“Class Name”下拉框中选中“CDIPJQView”,在“Object IDs”列表框中选中“CDIPJQView”,然后在“Message”列表框中选中“WM_SIZE”并双击,建立消息映射函数。
在“Object IDs”列表框中选中“ID_SHOW_ENLARGE”,然后在“Message”列表框中双击“COMMAND”,建立相应的消息映射函数。之后,依次建立“ID_SHOW_REDUCE”,“ID_SHOW_ORIGINAL”,“ID_SHOW_FIT”的消息映射函数。
8. 添加消息映射函数代码
打开DIPJQView.cpp,在生成的消息映射函数中添加代码。
void CDIPJQView::OnSize(UINT nType, int cx, int cy)
{
CScrollView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
OnInitialUpdate();
}
void CDIPJQView::OnShowEnlarge()
{
// TODO: Add your command handler code here
m_ShowMode = SHOWMODE_SCALE;
if( m_ShowScale>=400 ) return;
if( m_ShowScale<100 )
m_ShowScale = (m_ShowScale+10)/10*10;
else if( m_ShowScale<200 )
m_ShowScale = (m_ShowScale+25)/25*25;
else if( m_ShowScale<400 )
m_ShowScale = (m_ShowScale+50)/50*50;
OnInitialUpdate();
}
void CDIPJQView::OnShowReduce()
{
// TODO: Add your command handler code here
m_ShowMode = SHOWMODE_SCALE;
if( m_ShowScale<=10 ) return;
if( m_ShowScale<=100 )
m_ShowScale = (m_ShowScale-10)/10*10;
else if( m_ShowScale<=200 )
m_ShowScale = (m_ShowScale-25)/25*25;
else
m_ShowScale = (m_ShowScale-50)/50*50;
OnInitialUpdate();
}
void CDIPJQView::OnShowOriginal()
{
// TODO: Add your command handler code here
m_ShowMode = SHOWMODE_SCALE;
m_ShowScale = 100;
OnInitialUpdate();
}
void CDIPJQView::OnShowFit()
{
// TODO: Add your command handler code here
m_ShowMode = SHOWMODE_FIT;
OnInitialUpdate();
}
9. 设置状态栏
在CMainFrame类中定义如下函数:
// Operations
public:
void ShowScale(int a_Scale); //在状态栏中显示图象显示比例
在MainFrm.cpp文件的最后写出该函数的实现代码:
void CMainFrame::ShowScale(int a_Scale) //在状态栏中显示图象显示比例
{
CString str;
str.Format("%d",a_Scale);
str += "%";
m_wndStatusBar.SetPaneText(1,str);
}
在MainFrm.cpp文件修改状态栏设置数组元素(原有而未列出的删除):
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
0
};
在MainFrm.cpp文件的int CMainFrame::OnCreate()函数中添加如下代码:
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
UINT nID,nStyle; int cxWidth;
m_wndStatusBar.GetPaneInfo(1,nID,nStyle,cxWidth);
m_wndStatusBar.SetPaneInfo(1,nID,nStyle,50);
在CDIPJQView.cpp的开始处添加一行:
#include "DIPJQ.h"
#include "MainFrm.h"
#include "DIPJQDoc.h"
去掉CDIPJQView::OnInitialUpdate()函数中倒数第7行开始处的注释符“//”。
运行程序
第六节 建立图像处理类
1. 建立类文件
点击菜单“插入—>类”,打开“新建类”对话框;在类的类型中选中“Generic Class”;在名称中输入“SDImageProc”;确定。将生成SDImageProc类的头文件SDImageProc.h和源文件SDImageProc.cpp。
2. 编写类定义代码
在头文件中编写SDmageProc类定义代码,如下。
class SDImageProc
{
public:
SDImageProc();
virtual ~SDImageProc();
class SDImage *m_pSrcImg,*m_pDestImg;
BOOL ImageIsValid();
};
#endif // !defined(AFX_SDMAGEPROC_H__CA6A65DD_DBE3_4D8F_AE45_FD6611866EE3__INCLUDED_)
3. 编写类实现代码
在SDImageProc.cpp中添加如下类实现代码:
#include "math.h"
SDImageProc: SDImageProc()
{
m_pSrcImg = m_pDestImg = NULL;
}
SDImageProc::~ SDImageProc()
{
}
BOOL SDImageProc::ImageIsValid()
{
if( m_pSrcImg==NULL || m_pDestImg==NULL )
return FALSE;
return m_pSrcImg->IsValid();
}
说明:各图像处理函数均将在该类中定义并实现,每添加一个图像处理函数,都应首先在SDImageProc.h文件中加入函数定义代码,然后在SDImageProc.cpp文件中编写函数实现代码。
第七节 实现颜色处理功能
(一) 亮度处理
1. 在图像处理类中实现亮度处理功能
在SDImageProc类中添加并实现亮度处理函数。
首先打开SDImageProc.h文件,在其中加入亮度处理函数的定义,如下:
class SDImageProc
{
public:
SDImageProc();
virtual ~SDImageProc();
class SDImage *m_pSrcImg,*m_pDestImg;
BOOL ImageIsValid(); //源和目标图象是否有效
BOOL ModifyLight(float d); //亮度调整,-1~1
};
#endif // !defined(AFX_SDMAGEPROC_H__CA6A65DD_DBE3_4D8F_AE45_FD6611866EE3__INCLUDED_)
再打开SDImageProc.cpp文件,在最后添加亮度处理函数的实现代码,如下:
BOOL SDmageProc::ModifyLight(float d)
{
if( !ImageIsValid() ) return FALSE;
m_pDestImg->Create(m_pSrcImg->m_Width, m_pSrcImg->m_Height);
BYTE *sd = m_pSrcImg->m_pBits;
BYTE *dd = m_pDestImg->m_pBits;
if(d>1) d=1; if(d<-1) d=-1;
d=1+d;
int i,v;
BYTE colMap[256];
for(i=0;i<256;i++)
{
v=(INT)(i*d+0.5);
if( v>255 ) v=255;
colMap[i]=(BYTE)v;
}
for(i=0;im_ImageSize;i++)
dd[i] = colMap[ sd[i] ];
return TRUE;
}
***注:
(1) 以上函数中加粗的5行代码,是在后面所要实现的各图像处理函数中都需要固定写出的代码。前4行总是写在函数开始处,后1行总是写在函数结尾处。
(2) 在所有的图像处理函数中,处理得到的图像都是写入新的图像数据块中,原图像数据块的指针总是sd,新图像数据块的指针总是dd。
(3) 在编程中所需用到的图像参数变量为:
原图像的宽度:pSrcImg->m_Width;原图像的高度:pSrcImg->m_Height;原图像每行字节数:pSrcImg->m_WidthBytes;原图像数据总字节数:pSrcImg->m_ImageSize。
新图像的宽度:pDestImg->m_Width;新图像的高度:pDestImg->m_Height;新图像每行字节数:pDestImg->m_WidthBytes;新图像数据总字节数:pDestImg->m_ImageSize。
2. 建立亮度对话框,用于亮度调整参数的输入
(1) 切换到“ResourceView”选项页,展开“DIPJQ Resources”,在“Dialog”上点击右键,选中“插入Dialog”,将新建并编辑一个对话框。
(2) 右键点击对话框上的空白处,选中“属性”,在ID中输入“IDD_DIALOG_LIGHT”,在标题中输入“亮度调整参数”,点击字体按钮,将字体设为Tahoma,字体大小设为10。
(3) 添加、调整对话框上的控件至下图所示状态:
在控件工具栏上按下“静态文本”选择按钮,在对话框的适当位置拉出一个静态文本控件,在控件上点击右键—>属性,ID不变,标题输入为“亮度调整比例系数:”;添加编辑框,ID输入为“IDC_EDIT_LIGHT_D”。编辑完成后,点击保存按钮。
(4) 点击VC菜单“查看—>建立类向导”;选中“Create a new class”,点击OK;在Name编辑框中输入“CDlgLight”,点击OK,将建立CDlgLight类,并打开“MFC Class Wizard”对话框。
(5) 于“Message Maps”选项页,在“Object IDs”列表框的最后选中“IDOK”,然后在“Messages”列表框中选中“BN_CLICKED”,双击,将建立起“确定”按钮对应的消息映射函数。
(6) 切换至“Member Variables”选项页,在“Control IDs”列表框中选中“IDC_EDIT_LIGHT_D”,双击,在Member Variables Name中输入“m_LightD”,在Cagetory中选中“Value”,在Variable type中选中“int”;点击OK。在Minimum Value中输入“-100”,在Maximum Value中输入“100”。点击“确定”按钮。
3. 建立菜单
切换到“ResourceView”选项页,展开“DIPJQ resources”,展开“Menu”,双击“IDR_MAINFRAME”,对菜单进行编辑。
双击最后的空白顶层菜单,在标明编辑框中输入“颜色处理”,选中“弹出”。将该菜单拖至“查看”之后。
点击菜单“颜色处理”,双击下部空白菜单项,打开“菜单项目 属性”对话框,在ID下拉列表框中输入“ID_PROC_LIGHT”,在标明编辑框中输入“调整亮度…”,在提示编辑框中输入“调整亮度\n亮度”。关闭对话框。
4. 建立消息映射函数
在CDIPJQDoc类中建立“调整亮度”菜单项的消息映射函数:
点击菜单“查看—>建立类向导”,在“Class Name”下拉框中选中“CDIPJQDoc”,在“Object IDs”列表框中选中“ID_PROC_LIGHT”,然后在“Message”列表框中双击“COMMAND”。
5. 在消息映射函数中添加调用代码
打开DIPJQDoc.cpp文件,在文件首部已有的#include语句之后添加一行:
#include "DlgLight.h"
#include "SDImage.h"
#include "SDmageProc.h"
在OnProcLight()函数中加入如下代码:
void CDIPJQDoc::OnProcLight()
{
// TODO: Add your command handler code here
CDlgLight dlg;
if( dlg.DoModal()==IDOK )
{
LImageProc lip;
lip.m_pSrcImg = m_pCurImage;
lip.m_pDestImg = m_pLastImage;
float d = dlg.m_LightD/100.0;
if( lip.ModifyLight(d) )
{
LImage *p = m_pCurImage;
m_pCurImage = m_pLastImage;
m_pLastImage = p;
UpdateAllViews(NULL);
SetPathName(" ");
}
}
}
注:在之后其它的消息映射函数中,加粗的三行代码将因处理功能的不同而改变,其它各行代码则保持不变。
6. 组建程序,运行测试
组建执行文件,排除错误,对亮度调整功能进行运行测试。在对图像进行了一次亮度调整后,可点击工具栏上的撤消按钮,将图像恢复为处理前的状态。
(二) 对比度处理
1. 在图像处理类中实现对比度处理功能
在SDImageProc.h文件中加入对比度处理函数的定义:
在LImageProc.h文件中加入对比度处理函数的定义:
BOOL ImageIsValid(); //源和目标图象是否有效
BOOL ModifyLight(float d); //亮度调整,-1~1
BOOL ModifyContrast(float d); //对比度调整,-1~1
在LImageProc.cpp文件的最后,添加对比度处理函数的实现代码,如下:
BOOL LImageProc:: ModifyContrast(float d) //对比度调整,-1~1
{
if( !ImageIsValid() ) return FALSE;
m_pDestImg->Create(m_pSrcImg->m_Width, m_pSrcImg->m_Height);
BYTE *sd = m_pSrcImg->m_pBits;
BYTE *dd = m_pDestImg->m_pBits;
//中间部分请参照前面的亮度处理函数自行写出
return TRUE;
}
2. 建立对比度对话框,用于对比度