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++项目开发起到一定的帮助作用。