C++基于Directx MMX实现的图像灰度转换代码
本文实例讲述了基于DirectxMMX编写的实现图像灰度处理的方法,要编译此程序需DirectXSDK5.0,代码中所需要的ddutil.h与ddutil.cpp文件,请自行下载加入工程。在WindowNT4.0+SP3环境中编译通过,代码已经过整理,包含有注释。如下所示:
#include<windows.h>
#include<windowsx.h>
#include<stdio.h>
#include<ddraw.h>
#include<math.h>
#include"ddutil.h"
#defineMEAN_GRAY0//平均值法
#defineMAXIMUM_GRAY1//最大值法
#defineWEIGHT_GRAY2//加权平均值法
#defineTITLE"灰度转换"//窗口标题
#defineCLASSNAME"Gray"//窗口类名
#defineWIDTH640
#defineHEIGHT480
#defineCOLORS8
#defineSTEP1
#defineSCANLINE16
HINSTANCEhInst;//应用程序实例句柄
HWNDhWndMain;//主窗口句柄
LPDIRECTDRAWlpDD;//DirectDraw对象
LPDIRECTDRAWSURFACElpDDSPrimary;//主页面
LPDIRECTDRAWSURFACElpDDSBack;//后台缓冲区
LPDIRECTDRAWSURFACElpDDSPic1;//离屏页面1
LPDIRECTDRAWPALETTElpDDPal;//调色板
BOOLbActive;//应用程序是否活跃?
intKey=0;
boolContrast=false;
boolGray=false;
//函数声明
voidFreeObjects(void);
BOOLInitDDraw(void);
BOOLInitPalette(void);
BOOLInitSurfaces(void);
voidUpdateFrame(void);
voidMakeRect(RECT*rect,longleft,longtop,longright,longbottom);
voidIncreaseContrast(BYTE*pByte,constintLow,constintHight,
constfloatGrad)
{
if(*pByte<=Low)
*pByte=0;
elseif((Low<*pByte)&&(*pByte<Hight))
*pByte=(BYTE)((*pByte-Low)/Grad);
else
*pByte=255;
}
voidChangeContrast(intnDelta)
{
LPPALETTEENTRYPal=(LPPALETTEENTRY)LocalAlloc(LPTR,sizeof(PALETTEENTRY)*256);
//获取调色板
lpDDPal->GetEntries(0,0,256,Pal);
intLow,High;
floatGrad;
for(inti=0;i<256;i++)
{
if(nDelta>=0)
{
Low=0+nDelta;
High=255-nDelta;
Grad=((float)(High-Low))/255;
IncreaseContrast(&Pal[i].peRed,Low,High,Grad);
IncreaseContrast(&Pal[i].peGreen,Low,High,Grad);
IncreaseContrast(&Pal[i].peBlue,Low,High,Grad);
}
else
{
Pal[i].peRed=(BYTE)((int)(Pal[i].peRed/Grad))-nDelta;
Pal[i].peGreen=(BYTE)((int)(Pal[i].peGreen/Grad))-nDelta;
Pal[i].peBlue=(BYTE)((int)(Pal[i].peBlue/Grad))-nDelta;
}
}
//更新调色板
lpDDPal->SetEntries(0,0,256,Pal);
}
//灰度转换函数--本程序的关键
//函数:ConvertToGrayScale
//参数:Method为转换灰度的方式,值可为:
//MAXIMUM_GRAY=最大值法,MEAN_GRAY=平均值法,
//WEIGHT_GRAY=加权平均值法
//Color目前只能为8即只能处理8位调色板方式
//返值:无
voidConvertToGrayScale(unsignedshortMethod,unsignedshortColor)
{
BYTEConvert;
inti;
switch(Color)
{
case8:
LPPALETTEENTRYPal=(LPPALETTEENTRY)LocalAlloc(LPTR,sizeof(PALETTEENTRY)*256);
//获取调色板
lpDDPal->GetEntries(0,0,256,Pal);
switch(Method)
{
caseMAXIMUM_GRAY:
//最大值法转换
for(i=0;i<256;i++)
{
//计算的公式为:R=G=B=max(R,G,B)
Convert=(max(max(Pal[i].peRed,Pal[i].peGreen),Pal[i].peBlue));
Pal[i].peRed=Pal[i].peGreen=Pal[i].peBlue=Convert;
}
break;
caseMEAN_GRAY:
//平均值法转换
for(i=0;i<256;i++)
{
//计算的公式为:R=G=B=(R+G+B)/3
Convert=((Pal[i].peRed+Pal[i].peGreen+Pal[i].peBlue)/3);
Pal[i].peRed=Pal[i].peGreen=Pal[i].peBlue=Convert;
}
break;
caseWEIGHT_GRAY:
//加权平均值法转换
for(i=0;i<256;i++)
{
//计算的公式为:R=G=B=(R*0.3+G*0.59+B*0.11)
//为不使用浮点乘法,现公式为:
//R=G=B=(R*3+G*6+B)/10
//些许的误差可以不计
Convert=(Pal[i].peRed*3+Pal[i].peGreen*6+Pal[i].peBlue)/10;
Pal[i].peRed=Pal[i].peGreen=Pal[i].peBlue=Convert;
}
break;
}
//更新调色板
lpDDPal->SetEntries(0,0,256,Pal);
break;
}
}
//**********************************
//函数:FreeObject
//功能:释放所有DirectDraw对象
voidFreeObjects(void)
{
if(lpDD!=NULL)//释放DirectDraw对象
{
if(lpDDSPrimary!=NULL)//释放主页面
{
lpDDSPrimary->Release();
lpDDSPrimary=NULL;
}
if(lpDDSPic1!=NULL)//释放离屏页面1
{
lpDDSPic1->Release();
lpDDSPic1=NULL;
}
if(lpDDPal!=NULL)//释放调色板
{
lpDDPal->Release();
lpDDPal=NULL;
}
lpDD->Release();
lpDD=NULL;
}
}
//************************************
//函数:RestoreAll
//功能:页面丢失后,恢复页面内存
HRESULTRestoreAll(void)
{
HRESULTddrval;
//恢复主页面,这也将恢复换页链中的所有页面
ddrval=lpDDSPrimary->Restore();
//恢复离屏页面
ddrval=lpDDSPic1->Restore();
//重新绘制页面图象
InitSurfaces();
returnddrval;
}
//**************************************
//函数:WindowProc
//功能:主窗口的消息处理过程
LRESULTCALLBACKWinProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{
switch(message)
{
caseWM_SETCURSOR:
SetCursor(NULL);
returnTRUE;
caseWM_ACTIVATEAPP://应用程序激活消息
bActive=wParam;
break;
caseWM_KEYDOWN://击键消息
switch(wParam)
{
caseVK_ESCAPE:
PostMessage(hWnd,WM_CLOSE,0,0);
break;
caseVK_F1:
Gray=true;
Key=MEAN_GRAY;
InitPalette();
break;
caseVK_F2:
Gray=true;
Key=MAXIMUM_GRAY;
InitPalette();
break;
caseVK_F3:
Gray=true;
Key=WEIGHT_GRAY;
InitPalette();
break;
caseVK_F4:
Gray=false;
Key=0;
InitPalette();
break;
caseVK_F5:
Contrast=!Contrast;
if(false==Contrast)
{
InitPalette();
}
break;
caseVK_F6:
break;
}
break;
caseWM_DESTROY://销毁窗口消息
FreeObjects();
PostQuitMessage(0);
break;
}
//调用缺省的过程处理过程
returnDefWindowProc(hWnd,message,wParam,lParam);
}
//*********************************
//函数:InitWindow()
//功能:创建主窗口。
BOOLInitWindow(HINSTANCEhInstance,intnCmdShow)
{
WNDCLASSwc;//窗口类结构
//填充窗口类结构
wc.style=0;
wc.lpfnWndProc=WinProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hInstance;
wc.hIcon=LoadIcon(hInstance,IDI_APPLICATION);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//选择黑色刷做为窗口背景
wc.lpszMenuName=NULL;
wc.lpszClassName=CLASSNAME;
//注册窗口类
RegisterClass(&wc);
//创建主窗口
hWndMain=CreateWindowEx(
0,
CLASSNAME,//窗口的类名称,必须与上面的wc.lpszClassName一致
TITLE,//窗口的标题名
WS_POPUP,
0,
0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
hInstance,
NULL);
if(!hWndMain)
returnFALSE;
//显示并更新窗口
ShowWindow(hWndMain,nCmdShow);
returnTRUE;
}
//*********************************
//函数:InitDDraw()
//功能:初始化DirectDraw环境,创建换页链(主页面,一个后台缓冲区)
//以及创建一个定时器。
BOOLInitDDraw(void)
{
DDSURFACEDESCddsd;
DDSCAPSddscaps;
HRESULTddrval;
//创建DirectDraw对象
ddrval=DirectDrawCreate(NULL,&lpDD,NULL);
if(ddrval!=DD_OK)
returnFALSE;
//取得全屏独占模式
ddrval=lpDD->SetCooperativeLevel(hWndMain,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
if(ddrval!=DD_OK)
returnFALSE;
//设置显示器显示模式为640x480x8
ddrval=lpDD->SetDisplayMode(WIDTH,HEIGHT,COLORS);
if(ddrval!=DD_OK)
returnFALSE;
//填充换页链结构
ddsd.dwSize=sizeof(ddsd);
ddsd.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|
DDSCAPS_FLIP|
DDSCAPS_COMPLEX;
//后台缓冲区数量为1
ddsd.dwBackBufferCount=1;
//创建换页链,包括了主页面及其后台缓冲区
ddrval=lpDD->CreateSurface(&ddsd,&lpDDSPrimary,NULL);
if(ddrval!=DD_OK)
returnFALSE;
//获得指向后台缓冲区的页面指针
ddscaps.dwCaps=DDSCAPS_BACKBUFFER;
ddrval=lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);
if(ddrval!=DD_OK)
returnFALSE;
//创建离屏页面
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize=sizeof(ddsd);
ddsd.dwFlags=DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH;
ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth=WIDTH;
ddsd.dwHeight=HEIGHT;
if(lpDD->CreateSurface(&ddsd,&lpDDSPic1,NULL)!=DD_OK)
returnFALSE;
//调用页面初始化函数
if(!InitSurfaces())
returnFALSE;
returnTRUE;
}
//**********************************
//函数:WinMain()
//功能:应用程序入口
intPASCALWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow)
{
MSGmsg;
hInst=hInstance;
//初始化主窗口
if(!InitWindow(hInstance,nCmdShow))
returnFALSE;
//初始化DirectDraw环境
if(!InitDDraw())
{
MessageBox(hWndMain,"初始化DirectDraw过程中出错!","Error",MB_OK);
FreeObjects();
DestroyWindow(hWndMain);
returnFALSE;
}
//进入消息循环
while(1)
{
if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
{
if(!GetMessage(&msg,NULL,0,0))
returnmsg.wParam;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
elseif(bActive)
{
UpdateFrame();
}
elseWaitMessage();
}
returnmsg.wParam;
}
BOOLInitPalette(void)
{
//从磁盘文件中载入调色板
lpDDPal=DDLoadPalette(lpDD,"back.bmp");
//将调色板设置给主页面
if(lpDDPal)
{
lpDDSPrimary->SetPalette(lpDDPal);
returnTRUE;
}
returnFALSE;
}
//****************************
//函数:InitSurfaces()
//功能:初始化页面图象
BOOLInitSurfaces(void)
{
HBITMAPhbm;
InitPalette();
//从磁盘文件中将我们所需要的图象载入到一个hbm位图对象中
hbm=(HBITMAP)LoadImage(hInst,"back.bmp",IMAGE_BITMAP,
0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
if(hbm==NULL)
returnFALSE;
DDCopyBitmap(lpDDSPic1,hbm,0,0,WIDTH,HEIGHT);
//释放hbm位图对象
DeleteObject(hbm);
returnTRUE;
}
//更新屏幕
voidUpdateFrame(void)
{
HRESULTddrval;
//计算刷新率
staticintfps=0,frame=0,nt=0,ot=0;
frame++;
nt=timeGetTime();
if(nt>ot+1000)
{
ot=nt;
fps=frame;
frame=0;
}
//清屏后台缓冲区
DDBLTFXddBltFx;
ddBltFx.dwSize=sizeof(DDBLTFX);
ddBltFx.dwFillColor=DDColorMatch(lpDDSBack,RGB(0,0,0));
lpDDSBack->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
//调用灰度的实现函数
if(true==Gray)
{
ConvertToGrayScale(Key,COLORS);
Gray=false;
}
//增加对比度
if(true==Contrast)
{
ChangeContrast(2);
}
RECTsrect,drect;
MakeRect(&srect,0,0,WIDTH,HEIGHT);
MakeRect(&drect,0,0,WIDTH,HEIGHT);
//将背景图象Blit到后台缓冲区
lpDDSBack->Blt(&drect,lpDDSPic1,&srect,DDBLT_WAIT,NULL);
//打印刷新率fps
HDChdc;
chartemp[50];
lpDDSBack->GetDC(&hdc);
SetBkMode(hdc,TRANSPARENT);
SetTextColor(hdc,RGB(0,255,255));
sprintf(temp,"fps=%d",fps);
TextOut(hdc,0,0,temp,strlen(temp));
sprintf(temp,"图象特效----灰度转换");
TextOut(hdc,30,400,temp,strlen(temp));
lpDDSBack->ReleaseDC(hdc);
//换页
while(1)
{
ddrval=lpDDSPrimary->Flip(NULL,DDFLIP_WAIT);//调用换页函数
if(ddrval==DD_OK)//成功则退出while循环
break;
elseif(ddrval==DDERR_SURFACELOST)//如果页面丢失,则恢复页面,再继续while循环
RestoreAll();
else
break;
}
}
voidMakeRect(RECT*rect,longleft,longtop,longright,longbottom)
{
rect->left=left;
rect->top=top;
rect->right=right;
rect->bottom=bottom;
}
感兴趣的朋友可以调试运行一下本文实例,相信会对大家进行C++项目开发起到一定的帮助作用。