二つの画像の排他論理和(C)



実行例

effect.c

//

// effect.c

//

// (c)Copyright Spacesoft corp., 2007 All rights reserved.

//                               Hiro KITAYAMA

//

#include <windows.h>

 

 

//---------------------------------------------------------------------------

//

// エフェクト

//

void effect( LPBYTE pAligned[], LONG width, LONG height )

{

    LPBYTE  lpSrc0, lpSrc1, lpDest ;

    int     x, y ;

 

    lpDest = pAligned[0] ;

    lpSrc0 = pAligned[1] ;

    lpSrc1 = pAligned[2] ;

 

    for( y = 0 ; y < height ; y++ )

        for( x = 0 ; x < width*4 ; x++ )

            *lpDest++ = (BYTE)(*lpSrc1++ ^ *lpSrc0++);

}

 

pgm.c

//

// pgm.c

//

// (c)Copyright Spacesoft corp., 2007 All rights reserved.

//                               Hiro KITAYAMA

//

#include <stdio.h>

#include <conio.h>          // kbhit(), getch()

#include <stdlib.h>         // _splitpath()

#include <windows.h>

 

#define SAFE_FREE( p )      if( p ) { free( p ) ; p=NULL ; }

#define SZCLASSNAME         "TEST"

 

// グローバル変数

PBITMAPINFOHEADER   pDib[2] ;       // tolal

LPBYTE              pBitmap[2] ;    // data

 

void effect( LPBYTE pAligned[], LONG width, LONG height );

 

 

//---------------------------------------------------------------------------

//

// ファイル名の取得

//

BOOL getFname( char* inFname )

{

    OPENFILENAME fName ;

    char fileName[256] ;

    const char filefilter[] = "BMPファイル(*.bmp)\0*.bmp\0\0" ;

 

    fileName[0] = '\0' ;

 

    memset( &fName, 0, sizeof(OPENFILENAME) ) ;

    fName.lStructSize    = sizeof(OPENFILENAME) ;

    fName.lpstrFilter    = filefilter ;

    fName.nFilterIndex   = 1 ;

    fName.lpstrFile      = fileName ;

    fName.nMaxFile       = sizeof(fileName) ;

    fName.Flags          = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ;

 

    // 「ファイルを開く」ダイアログ

    if( GetOpenFileName( &fName ) == 0 )

        return FALSE ;

 

    strcpy( inFname, fileName ) ;

 

    return TRUE ;

}

 

//---------------------------------------------------------------------------

//

// ビットッマプヘッダの読み込み

//

BOOL readHeader( FILE* fp, PBITMAPFILEHEADER bmHdr )

{

    // ビットッマプヘッダの読み込み

    if( fread( bmHdr, sizeof(BITMAPFILEHEADER), 1, fp ) !=  1 )

    {

        fprintf( stderr, "エラー:ファイル読み込み.\n" ) ;

        return FALSE ;

    }

 

    // ビットッマプファイルかチェック

    if ( bmHdr -> bfType != 'M'*256+'B' )

    {

        fprintf( stderr, "エラー:BMPフォーマットでは無い.\n" );

        return FALSE ;

    }

    return TRUE ;

}

 

 

//---------------------------------------------------------------------------

//

// ビットッマプ本体の読み込み

//

BOOL readBody( FILE* fp, PBITMAPFILEHEADER bmHdr, PBITMAPINFOHEADER pDib )

{

    int bitmapSize ;

 

    bitmapSize = bmHdr -> bfSize - sizeof(BITMAPFILEHEADER) ;   // 画像の大きさ

 

    // ビットッマプ本体の読み込み

    if( fread( pDib , bitmapSize, 1, fp ) !=  1 )

    {

        fprintf( stderr, "エラー:ファイル読み込み.\n" ) ;

        return FALSE ;

    }

    if( pDib -> biBitCount != 32 )

    {

        fprintf( stderr, "エラー:32ビット ビットッマプではない.\n");

        return FALSE ;

    }

    if( pDib -> biWidth % 4 )

    {

        fprintf( stderr, "エラー:幅が4 バイトの整数倍でない.\n");

        return FALSE ;

    }

    return TRUE ;

}

 

 

//---------------------------------------------------------------------------

//

// ビットッマファイルの読み込み

//

BOOL readBmpFile( PBITMAPINFOHEADER * pDib, PBITMAPFILEHEADER pBmHdr )

{

    char  fName[_MAX_PATH] ;

    char  dfFile[_MAX_PATH], dfName[_MAX_FNAME], dfExt[_MAX_EXT ] ;

    FILE* fp ;

    int   bitmapSize ;

 

    if( FALSE == getFname( fName ) )

        return FALSE ;

 

    // ビットマップファイルのオープン

    if( (fp = fopen( fName, "rb" )) == NULL )

    {

        fprintf( stderr, "エラー:ファイルのオープンに失敗.\n" ) ;

        return FALSE ;

    }

 

    // ファイル名の表示

    _splitpath( fName, NULL, NULL, dfName, dfExt ) ;

    strcpy( dfFile, dfName ) ;

    strcat( dfFile, dfExt ) ;

    fprintf( stdout, "ファイル名 = [%s]\n", dfFile ) ;

 

    // ヘッダの読み込み

    if( !readHeader( fp, pBmHdr ) )

    {

        fclose( fp ) ;      // ファイルクローズ

        return FALSE ;

    }

 

    // ビットマップ本体のサイズ

    bitmapSize = pBmHdr->bfSize - sizeof(BITMAPFILEHEADER) ;

 

    // メモリ確保

    *pDib = (BITMAPINFOHEADER *)malloc( bitmapSize ) ;

 

    // 本体読み込み

    if( !readBody( fp, pBmHdr, *pDib ) )

    {

        SAFE_FREE( *pDib ) ;    // メモリ解放

        fclose( fp ) ;          // ファイルクローズ

        return FALSE ;

    }

 

    fclose( fp ) ;              // ファイルクローズ

 

    // 画像サイズの表示

    fprintf( stdout, "ビットマップサイズ= %d x %d\n",

                                (*pDib) -> biWidth, (*pDib) -> biHeight ) ;

 

    return TRUE ;

}

 

 

//---------------------------------------------------------------------------

//

// window procedure

//

LRESULT CALLBACK WindProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam )

{

    PAINTSTRUCT ps ;

 

    switch( uMessage )

    {

        case WM_PAINT:

            BeginPaint( hWnd, &ps ) ;

            SetDIBitsToDevice( ps.hdc, 0, 0,        // copy BMP

                                pDib[0] -> biWidth, pDib[0] -> biHeight,

                                    0, 0, 0, pDib[0] -> biHeight, pBitmap[0],

                                        (BITMAPINFO*)pDib[0], DIB_RGB_COLORS ) ;

            EndPaint( hWnd, &ps ) ;

            break ;

 

        case WM_DESTROY:

            PostQuitMessage( 0 ) ;

            break ;

 

        default:

            return DefWindowProc( hWnd, uMessage, wParam, lParam ) ;

    }

    return 0 ;

}

 

//---------------------------------------------------------------------------

//

// create window

//

HWND createWindow( PBITMAPINFOHEADER pDib )

{

    HINSTANCE hInstanse ;

    WNDCLASSEX  wcx ;

    HWND hWnd = NULL ;

    int  ttlHeight, frameWidth, frameHeight ;

    int  windowWidth, windowHeight ;

 

    hInstanse = (HINSTANCE)GetWindowLong( NULL, GWL_HINSTANCE ) ;

 

    memset( &wcx, 0, sizeof(WNDCLASSEX) ) ;

    wcx.cbSize        = sizeof(WNDCLASSEX) ;

    wcx.lpfnWndProc   = WindProc ;                      // ウィンドウプロシージャ

    wcx.hInstance     = hInstanse ;

    wcx.hCursor       = LoadCursor( NULL, IDC_ARROW ) ;

    wcx.lpszClassName = SZCLASSNAME ;                   // ウィンドウクラス名

    if( !RegisterClassEx( &wcx ) )                      // ウィンドウクラスの登録

        return NULL ;                                   // 失敗

 

    ttlHeight   = GetSystemMetrics( SM_CYCAPTION ) ;    // ウィンドウタイトルの高さ

    frameWidth  = GetSystemMetrics( SM_CXFIXEDFRAME ) ; // ウィンドウフレームの幅

    frameHeight = GetSystemMetrics( SM_CYFIXEDFRAME ) ; // ウィンドウフレームの高さ

 

    windowWidth = pDib -> biWidth  + (frameWidth * 2),  // ウィンドウの幅

    windowHeight= pDib -> biHeight

                    + ttlHeight + (frameHeight * 2) ;   // ウィンドウの高さ

 

    hWnd = CreateWindow( SZCLASSNAME,                   // ウィンドウクラス名

                "表示ウィンドウ",                       // ウィンドウタイトル

                WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE,// ウィンドウスタイル

                CW_USEDEFAULT, CW_USEDEFAULT,           // ウィンドウ位置

                windowWidth,windowHeight,               // ウィンドウサイズ

                HWND_DESKTOP, NULL, hInstanse, NULL ) ;

 

    return hWnd ;

}

 

 

//---------------------------------------------------------------------------

//

// get counter

//

UINT64 getCurCounter(void)

{

    UINT64 counter ;         // 性能表示

 

    _asm

    {

        rdtsc

        mov     dword ptr [counter+0], eax

        mov     dword ptr [counter+4], edx

    }

 

    return counter;

}

 

 

//---------------------------------------------------------------------------

//

// main

//

int main( void )

{

    HWND  hWnd ;

    MSG   msg ;

    BITMAPFILEHEADER bmHdr[2] ;

    int    loop, imgSize ;

    LPBYTE pAligned[3] ;                        // SIMD用バッファ

    UINT64 begin, finish, elapsed ;         // 性能表示

 

    if( !readBmpFile( &pDib[0], &bmHdr[0] ) )

    {

        SAFE_FREE( pDib[0] ) ;      // メモリ解放

        return -1;

    }

 

    if( !readBmpFile( &pDib[1], &bmHdr[1] ) )

    {

        SAFE_FREE( pDib[1] ) ;      // メモリ解放

        return -1;

    }

    if( pDib[0] -> biWidth != pDib[1] -> biWidth ||

            pDib[0] -> biHeight != pDib[1] -> biHeight )

    {

        fprintf( stderr, "エラー:画像のサイズが異なります.\n" ) ;

        SAFE_FREE( pDib[1] ) ;      // メモリ解放

        SAFE_FREE( pDib[0] ) ;      // メモリ解放

        return -1;

    }

 

    // ポインタをビットマップ本体位置へ移動

    pBitmap[0] = (BYTE *)(pDib[0]) + bmHdr->bfOffBits - sizeof(BITMAPFILEHEADER) ;

    pBitmap[1] = (BYTE *)(pDib[1]) + bmHdr->bfOffBits - sizeof(BITMAPFILEHEADER) ;

 

    imgSize=pDib[0]->biWidth * pDib[0]->biHeight * 4;

 

    // alignされたメモリを確保

    pAligned[0] = (LPBYTE)_aligned_malloc(imgSize*3, 16);   // dest

    pAligned[1] = pAligned[0] + imgSize;                    // src0

    pAligned[2] = pAligned[1] + imgSize;                    // src1

 

    // alignされたエリアにコピー

    memcpy(pAligned[1], pBitmap[0], imgSize);               // src0

    memcpy(pAligned[2], pBitmap[1], imgSize);               // src1

 

 

 

    begin = getCurCounter();

 

    //画像処理

    for(loop=0;loop<100;loop++) //キャッシュなどの影響を排除するため100回実行

        effect( pAligned, pDib[0] -> biWidth, pDib[0] -> biHeight ) ;

 

    finish = getCurCounter();

    elapsed = finish > begin ? finish - begin : begin - finish ;

    printf( "counter= %I64u\n", elapsed ) ;

 

 

    // alignされたエリアからbitmapへコピー

    memcpy(pBitmap[0], pAligned[0], imgSize);

 

 

 

    // ウィンドウ表示

    hWnd = createWindow( pDib[0] ) ;

 

    fprintf( stdout, "Enterキーを押せば終わります..." ) ;

 

    // メッセージループ

    msg.message = WM_CREATE ;               // dummy for while

    while( msg.message != WM_QUIT )

    {

        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )

        {

            TranslateMessage( &msg ) ;

            DispatchMessage( &msg ) ;

        }

 

        // Enterキーを押されたらQuit

        if( kbhit() )

        {

            PostMessage( hWnd, (UINT)WM_DESTROY, (UINT)0, (LONG)0 ) ;

            getch() ;

        }

    }

 

    SAFE_FREE( pDib[0] ) ;      // メモリ解放

    SAFE_FREE( pDib[1] ) ;      // メモリ解放

    _aligned_free(pAligned[0]); // メモリ解放

 

    return 0;

}