C++ based on Directx MMX image grayscale conversion code

  • 2020-04-02 02:32:50
  • OfStack

The example of this article describes the method of image grayscale processing based on Directx MMX, to compile this program requires Directx SDK5.0, the code required ddutil. H and ddutil. CPP file, please download the project. Compiled in WindowNT4.0+SP3 environment, the code has been sorted, including comments. As follows:


#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <ddraw.h>
#include <math.h>
#include "ddutil.h"
#define MEAN_GRAY 0//The average method
#define MAXIMUM_GRAY 1//The maximum value method
#define WEIGHT_GRAY 2// The weighted The average method
#define TITLE " Gray level transformation " //The window title
#define CLASSNAME "Gray" //The window class name
#define WIDTH 640
#define HEIGHT 480
#define COLORS 8
#define STEP 1
#define SCANLINE 16
HINSTANCE hInst; //Application instance handle
HWND hWndMain; //Handle to the main window
LPDIRECTDRAW      lpDD;      //DirectDraw object
LPDIRECTDRAWSURFACE   lpDDSPrimary;  //The main page
LPDIRECTDRAWSURFACE   lpDDSBack;   //Background buffer
LPDIRECTDRAWSURFACE   lpDDSPic1;   //Off screen 1
LPDIRECTDRAWPALETTE   lpDDPal;    //The palette
BOOL          bActive;    //Application is active ?
int Key=0;
bool Contrast=false;
bool Gray=false;
//Function declaration
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 );
 //Gets the palette
 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;
 }
 }
 //Update the palette
 lpDDPal->SetEntries(0,0,256,Pal);
}
//Gray conversion function - the key of this procedure
//Function: ConvertToGrayScale
//Parameter: Method is the way to convert grayscale, and the value can be:
// MAXIMUM_GRAY=The maximum value method,MEAN_GRAY=The average method,
// WEIGHT_GRAY= The weighted The average method
//Color is currently limited to 8 which means it can only handle 8-bit palettes
//Return value: none
void ConvertToGrayScale(unsigned short Method,unsigned short Color)
{
 BYTE Convert; 
 int i;
 switch(Color)
 {
 case 8:
 LPPALETTEENTRY Pal = (LPPALETTEENTRY) LocalAlloc( LPTR, sizeof( PALETTEENTRY ) * 256 );
 //Gets the palette
 lpDDPal->GetEntries(0,0,256,Pal);
 switch(Method)
 {
 case MAXIMUM_GRAY:
  //The maximum value method conversion 
  for(i=0; i<256; i++)
  {
  //The formula of calculation is: 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:
  //The average method conversion 
  for(i=0; i<256; i++)
  {
  //The calculation formula is: 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:
  // The weighted The average method conversion 
  for(i=0; i<256; i++)
  {
  //The calculation formula is: R=G=B=(R*0.3+G*0.59+B*0.11)
  //To avoid floating point multiplication, the formula is:
  //R=G=B=(R*3+G*6+B)/10
  //The margin of error is negligible
  Convert=( Pal[i].peRed * 3 + Pal[i].peGreen *6 + Pal[i].peBlue ) / 10; 
  Pal[i].peRed=Pal[i].peGreen=Pal[i].peBlue=Convert;
  } 
  break;  
 }
 //Update the palette
 lpDDPal->SetEntries(0,0,256,Pal);
 break;
 }
}
//**********************************
//Function: FreeObject
//Function: releases all DirectDraw objects
void FreeObjects( void )
{
  if( lpDD != NULL )//Release the DirectDraw object
  {
    if( lpDDSPrimary != NULL )//Release main page
    {
      lpDDSPrimary->Release();
      lpDDSPrimary = NULL;
    }
    if( lpDDSPic1 != NULL )//Release off screen 1
    {
      lpDDSPic1->Release();
      lpDDSPic1 = NULL;
    }
    if( lpDDPal != NULL )//Release the palette
    {
      lpDDPal->Release();
      lpDDPal = NULL;
    }
    lpDD->Release();
    lpDD = NULL;
  }
} 
//************************************
//Function: RestoreAll
//Function: restore page memory after page loss
HRESULT RestoreAll( void )
{
  HRESULT   ddrval;
 //Restore the main page, which will also restore all pages in the page-changing chain
  ddrval = lpDDSPrimary->Restore();
 //Restore the off - screen page
  ddrval = lpDDSPic1->Restore();
 //Redraw the page image
 InitSurfaces();
  return ddrval;
}
//**************************************
//Function: WindowProc
//Function: message processing for the main window
LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
  switch( message )
  {
  case WM_SETCURSOR:
 SetCursor(NULL);
 return TRUE;

  case WM_ACTIVATEAPP://Application activation messages
    bActive = wParam;
    break;

  case WM_KEYDOWN://Keystroke messages
    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://Destroy window message
    FreeObjects();
    PostQuitMessage(0);
    break;
  }

 //Invokes the default procedure handler
  return DefWindowProc(hWnd, message, wParam, lParam);
}
//*********************************
//Function: InitWindow ()
//Function: create the main window.
BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
{
  WNDCLASS wc; //Window class structure
 // fill Window class structure
  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);//Select the black brush as the window background
  wc.lpszMenuName = NULL;
 wc.lpszClassName = CLASSNAME;
 //Register window class
  RegisterClass( &wc );
  //Create the main window
  hWndMain= CreateWindowEx(
 0,
 CLASSNAME, //The class name of the window must be the same as the wc.lpszclassname above
 TITLE, //The title name of the window
 WS_POPUP,
 0,
 0,
 GetSystemMetrics( SM_CXSCREEN ),
 GetSystemMetrics( SM_CYSCREEN ),
 NULL,
 NULL,
 hInstance,
 NULL );
  if( !hWndMain ) 
 return FALSE;
 //Displays and updates the window
  ShowWindow( hWndMain, nCmdShow );
 return TRUE;
}
//*********************************
//Function: InitDDraw ()
//Function: initialize DirectDraw environment, create pager (main page, a background buffer)
//And create a timer.
BOOL InitDDraw(void)
{
  DDSURFACEDESC    ddsd;
  DDSCAPS       ddscaps;
  HRESULT       ddrval;

  //Create a DirectDraw object
 ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
  if( ddrval != DD_OK )
    return FALSE;
  //Get full screen exclusive mode
  ddrval = lpDD->SetCooperativeLevel( hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
  if( ddrval != DD_OK )
    return FALSE;
  //Set the display mode to 640x480x8
  ddrval = lpDD->SetDisplayMode( WIDTH, HEIGHT, COLORS);
  if( ddrval != DD_OK )
    return FALSE;
  //Fill in the paging chain structure
  ddsd.dwSize = sizeof( ddsd );
  ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
             DDSCAPS_FLIP |
             DDSCAPS_COMPLEX;
 //The number of background buffers is 1
  ddsd.dwBackBufferCount = 1;
 //Create a swap chain that includes the main page and its background buffer
  ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
  if( ddrval != DD_OK )
    return FALSE;
  //Gets a page pointer to the background buffer
 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);
  if( ddrval != DD_OK )
    return FALSE;
 //Create an off-screen page
 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;
 //Call the page initialization function
 if( !InitSurfaces() )
    return FALSE;
  return TRUE;
}
//**********************************
//Function: the WinMain ()
//Function: application entry
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
  MSG msg;
 hInst=hInstance;
 //Initializes the main window
 if (!InitWindow( hInstance, nCmdShow))
  return FALSE;
 //Initialize the DirectDraw environment
 if (!InitDDraw())
 {
 MessageBox(hWndMain, " Initialize the DirectDraw Error in the process! ", "Error", MB_OK);
 FreeObjects();
 DestroyWindow(hWndMain);
 return FALSE;
 }
 //Enter the message loop
 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)
{
  //Load the palette from the disk file
 lpDDPal = DDLoadPalette(lpDD, "back.bmp");
 //Set the palette to the main page
  if (lpDDPal)
 {
    lpDDSPrimary->SetPalette( lpDDPal );
 return TRUE;
 }
 return FALSE;
}
//****************************
//Function: InitSurfaces ()
//Function: initialize page image
BOOL InitSurfaces( void )
{
  HBITMAP hbm;
 InitPalette();
  //Load the image we need from the disk file into an HBM bitmap object
  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);
 //Frees the HBM bitmap object
  DeleteObject(hbm);
  return TRUE;
}
//Update the screen
void UpdateFrame( void )
{
 HRESULT ddrval;
 //Calculate the refresh rate
 static int fps=0, frame=0, nt=0, ot=0;
 frame++;
 nt=timeGetTime(); 
 if (nt > ot+1000)
 {
 ot=nt;
 fps=frame;
 frame=0;
 }
 //Clear the background buffer
 DDBLTFX ddBltFx;
 ddBltFx.dwSize = sizeof(DDBLTFX);
 ddBltFx.dwFillColor = DDColorMatch(lpDDSBack, RGB(0,0,0));
 lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx);
 //Call the grayscale implementation function
 if(true==Gray)
 {
 ConvertToGrayScale(Key,COLORS);
 Gray=false;
 }
 //Increase contrast
 if(true==Contrast)
 {
 ChangeContrast(2);
 }

 RECT srect, drect;
 MakeRect(&srect, 0, 0, WIDTH, HEIGHT);
 MakeRect(&drect, 0, 0, WIDTH, HEIGHT);
 //Blit the background image to the background buffer
 lpDDSBack->Blt(&drect, lpDDSPic1, &srect, DDBLT_WAIT, NULL);
 //Print refresh rate 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," Image effects ---- Gray level transformation ");
 TextOut(hdc, 30, 400, temp, strlen(temp));
 lpDDSBack->ReleaseDC(hdc);
  //Change the page
  while( 1 )
  {
    ddrval = lpDDSPrimary->Flip( NULL, DDFLIP_WAIT );//Call the page-changing function
    if( ddrval == DD_OK )//Success exits the while loop
      break;
    else if( ddrval == DDERR_SURFACELOST )//If the page is lost, the page is restored and the while loop continues
      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;
}

Interested friends can debug the running of this example, I believe it will help you to carry out C++ project development.


Related articles: