C++基於Directx MMX完成的圖象灰度轉換代碼。本站提示廣大學習愛好者:(C++基於Directx MMX完成的圖象灰度轉換代碼)文章只能為提供參考,不一定能成為您想要的結果。以下是C++基於Directx MMX完成的圖象灰度轉換代碼正文
本文實例講述了基於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++項目開辟起到必定的贊助感化。