您的位置:首页 > 编程语言 > C语言/C++

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

2014-08-11 12:04 826 查看

本文实例讲述了基于Directx MMX 编写的实现图像灰度处理的方法,要编译此程序需DirectX SDK5.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"
#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)&&(*pByte<Hight))
*pByte=(BYTE)((*pByte-Low)/Grad);
else
*pByte=255;
}
void ChangeContrast(int nDelta)
{
LPPALETTEENTRY Pal = (LPPALETTEENTRY) LocalAlloc( LPTR, sizeof( PALETTEENTRY ) * 256 );
//获取调色板
lpDDPal->GetEntries(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++项目开发起到一定的帮助作用。

您可能感兴趣的文章:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ Directx MMX
相关文章推荐