C++基于Directx MMX实现的图像灰度转换代码

本文实例讲述了基于Directx MMX 编写的实现图像灰度处理的方法,要编译此程序需DirectX SDK5.0,代码中所需要的ddutil.h与ddutil.cpp文件,请自行下载加入工程。

在WindowNT4.0+SP3环境中编译通过,代码已经过整理,包含有注释。

如下所示:


#include 
#include 
#include 
#include 
#include 
#include "ddutil.h"
#define MEAN_GRAY 0//平均值法
#define MAXIMUM_GRAY 1//最大值法
#define WEIGHT_GRAY 2//加权平均值法
#define TITLE "灰度转换" //窗口标题
#define CLASSNAME "Gray" //窗口类名
#define WIDTH 640
#define HEIGHT 480
#define COLORS 8
#define STEP 1
#define SCANLINE 16
HINSTANCE hInst; //应用程序实例句柄
HWND hWndMain; //主窗口句柄
LPDIRECTDRAW      lpDD;      // DirectDraw对象
LPDIRECTDRAWSURFACE   lpDDSPrimary;  // 主页面
LPDIRECTDRAWSURFACE   lpDDSBack;   // 后台缓冲区
LPDIRECTDRAWSURFACE   lpDDSPic1;   // 离屏页面1
LPDIRECTDRAWPALETTE   lpDDPal;    // 调色板
BOOL          bActive;    // 应用程序是否活跃?
int Key=0;
bool Contrast=false;
bool Gray=false;
//函数声明
void FreeObjects( void );
BOOL InitDDraw(void);
BOOL InitPalette(void);
BOOL InitSurfaces(void);
void UpdateFrame(void);
void MakeRect(RECT *rect, long left, long top, long right, long bottom);
void IncreaseContrast(BYTE *pByte,const int Low,const int Hight,
    const float Grad)
{
 if(*pByte<=Low)
 *pByte=0;
 else if((Low<*pByte)&&(*pByteGetEntries(0,0,256,Pal);
 int Low,High;
 float Grad;
 for(int i=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位调色板方式
//返值:无
void ConvertToGrayScale(unsigned short Method,unsigned short Color)
{
 BYTE Convert; 
 int i;
 switch(Color)
 {
 case 8:
 LPPALETTEENTRY Pal = (LPPALETTEENTRY) LocalAlloc( LPTR, sizeof( PALETTEENTRY ) * 256 );
 //获取调色板
 lpDDPal->GetEntries(0,0,256,Pal);
 switch(Method)
 {
 case MAXIMUM_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;
 case MEAN_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;
 case WEIGHT_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对象
void FreeObjects( 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
//功能:页面丢失后,恢复页面内存
HRESULT RestoreAll( void )
{
  HRESULT   ddrval;
 //恢复主页面,这也将恢复换页链中的所有页面
  ddrval = lpDDSPrimary->Restore();
 //恢复离屏页面
  ddrval = lpDDSPic1->Restore();
 //重新绘制页面图象
 InitSurfaces();
  return ddrval;
}
//**************************************
//函数:WindowProc
//功能:主窗口的消息处理过程
LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
  switch( message )
  {
  case WM_SETCURSOR:
 SetCursor(NULL);
 return TRUE;

  case WM_ACTIVATEAPP://应用程序激活消息
    bActive = wParam;
    break;

  case WM_KEYDOWN://击键消息
    switch( wParam )
    {
    case VK_ESCAPE:
      PostMessage(hWnd, WM_CLOSE, 0, 0);
      break;
 case VK_F1:
  Gray=true;
  Key=MEAN_GRAY;
  InitPalette();
  break;
 case VK_F2:
  Gray=true;
  Key=MAXIMUM_GRAY;
  InitPalette();
  break;
 case VK_F3:
  Gray=true;
  Key=WEIGHT_GRAY;
  InitPalette();
  break;
 case VK_F4:
  Gray=false;
  Key=0;
  InitPalette();
  break;
 case VK_F5:
  Contrast=!Contrast;
  if(false==Contrast)
  {
  InitPalette();
  }
  break;
 case VK_F6:
  break;
 }
    break;

  case WM_DESTROY://销毁窗口消息
    FreeObjects();
    PostQuitMessage(0);
    break;
  }

 //调用缺省的过程处理过程
  return DefWindowProc(hWnd, message, wParam, lParam);
}
//*********************************
//函数:InitWindow()
//功能:创建主窗口。

BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ) { WNDCLASS wc; //窗口类结构 //填充窗口类结构 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 ) return FALSE; //显示并更新窗口 ShowWindow( hWndMain, nCmdShow ); return TRUE; } //********************************* //函数:InitDDraw() //功能:初始化DirectDraw环境,创建换页链(主页面,一个后台缓冲区) // 以及创建一个定时器。

BOOL InitDDraw(void) { DDSURFACEDESC ddsd; DDSCAPS ddscaps; HRESULT ddrval; //创建DirectDraw对象 ddrval = DirectDrawCreate( NULL, &lpDD, NULL ); if( ddrval != DD_OK ) return FALSE; //取得全屏独占模式 ddrval = lpDD->SetCooperativeLevel( hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); if( ddrval != DD_OK ) return FALSE; //设置显示器显示模式为640x480x8 ddrval = lpDD->SetDisplayMode( WIDTH, HEIGHT, COLORS); if( ddrval != DD_OK ) return FALSE; //填充换页链结构 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 ) return FALSE; //获得指向后台缓冲区的页面指针 ddscaps.dwCaps = DDSCAPS_BACKBUFFER; ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack); if( ddrval != DD_OK ) return FALSE; //创建离屏页面 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) return FALSE; //调用页面初始化函数 if( !InitSurfaces() ) return FALSE; return TRUE; } //********************************** //函数:WinMain() //功能:应用程序入口 int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow) { MSG msg; hInst=hInstance; //初始化主窗口 if (!InitWindow( hInstance, nCmdShow)) return FALSE; //初始化DirectDraw环境 if (!InitDDraw()) { MessageBox(hWndMain, "初始化DirectDraw过程中出错!", "Error", MB_OK); FreeObjects(); DestroyWindow(hWndMain); return FALSE; } //进入消息循环 while(1) { if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if(!GetMessage(&msg, NULL, 0, 0 )) return msg.wParam; TranslateMessage(&msg); DispatchMessage(&msg); } else if(bActive) { UpdateFrame(); } else WaitMessage(); } return msg.wParam; } BOOL InitPalette(void) { //从磁盘文件中载入调色板 lpDDPal = DDLoadPalette(lpDD, "back.bmp"); //将调色板设置给主页面 if (lpDDPal) { lpDDSPrimary->SetPalette( lpDDPal ); return TRUE; } return FALSE; } //**************************** //函数:InitSurfaces() //功能:初始化页面图象 BOOL InitSurfaces( void ) { HBITMAP hbm; InitPalette(); //从磁盘文件中将我们所需要的图象载入到一个hbm位图对象中 hbm = (HBITMAP)LoadImage(hInst, "back.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE); if (hbm == NULL) return FALSE; DDCopyBitmap(lpDDSPic1, hbm, 0, 0, WIDTH, HEIGHT); //释放hbm位图对象 DeleteObject(hbm); return TRUE; } //更新屏幕 void UpdateFrame( void ) { HRESULT ddrval; //计算刷新率 static int fps=0, frame=0, nt=0, ot=0; frame++; nt=timeGetTime(); if (nt > ot+1000) { ot=nt; fps=frame; frame=0; } //清屏后台缓冲区 DDBLTFX ddBltFx; 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); } RECT srect, drect; MakeRect(&srect, 0, 0, WIDTH, HEIGHT); MakeRect(&drect, 0, 0, WIDTH, HEIGHT); //将背景图象Blit到后台缓冲区 lpDDSBack->Blt(&drect, lpDDSPic1, &srect, DDBLT_WAIT, NULL); //打印刷新率fps HDC hdc; char temp[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; else if( ddrval == DDERR_SURFACELOST )//如果页面丢失,则恢复页面,再继续while循环 RestoreAll(); else break; } } void MakeRect(RECT *rect, long left, long top, long right, long bottom) { rect->left=left; rect->top=top; rect->right=right; rect->bottom=bottom; }

感兴趣的朋友可以调试运行一下本文实例,相信会对大家进行C++项目开发起到一定的帮助作用。

0.240657s