BMP32 Color ⇒ Gray

BMP32 カラー画像をグレースケールに変換します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

Image B32 Class

  1. このコーナーは「BMP24形式」でプログラムしていますが、このページだけは「BMP32形式」を使ってみました。
    グレースケールに変換する専用の ImageB32 Class のヘッダーファイル ImageB32.h です。
    不要なコードを削除して、シンプルに作成してみました。
    //★ IMAGE_B32 Class Header File  前田 稔
    #ifndef     _ImageB32
    #define     _ImageB32
    #include    <windows.h>
    #include    <math.h>
    #pragma     once
    #define     SAFE_DELDC(p)   { if (p) { DeleteDC (p);   (p)=NULL; } }
    #define     SAFE_DELOBJ(p)  { if (p) { DeleteObject(p); (p)=NULL; } }
    #define     MAP(y,x,c)  (Dib.Data[(y*m_Width+x)*4+c])
    
    typedef struct
    {   HBITMAP         hBmp;
        HDC             hBmpDC;
        LPBYTE          Data;           // 32bit DIB の BITMAP DATA
    }   DibStruct;
    
    class IMAGEB32
    { protected:
        HWND        hWnd;
        HBITMAP     hBmp;               //画像の HBITMAP
        HDC         hBmpDC;             //画像の HDC
    
      public:
        long        m_Width;            //画像の幅
        long        m_Height;           //画像の高さ
        int         m_Wbyte;            //幅のバイト数
        DibStruct   Dib;                //RGB 画像解析の構造体
        char        szFile[MAX_PATH];   //オープンするファイル名(パス付き)
    
        IMAGEB32(HWND hWnd);            //Constructor
        virtual ~IMAGEB32();            //Destructor
        HRESULT     LoadBmp(LPSTR szBitmap);
    
        //BitBlt() で描画する
        HRESULT     Show(HDC hdc,long x,long y,long w,long h,long xd,long yd);
        HRESULT     Show(HDC hdc,long x,long y)
                    {  return Show(hdc,x,y,m_Width,m_Height,0,0);  }
    
        //Dib で加工した画像を描画する
        HRESULT     ShowDib(HDC hdc, long x, long y);
    
        //Dib Function
        void        InitDib();
        void        Grayscale();
    
        BOOL        OpenFile();
        void        Adjust(BOOL flag=TRUE);
    };
    
    #endif
    
  2. ImageB32 Class のプログラムファイル ImageB32.cpp のソースコードです。
    // IMAGE_B32 Object Class Library  前田 稔
    #include    "ImageB32.h"
    
    void  Debug(char *msg, int v)
    {
        char    str[80];
        wsprintf(str, "%s=%d\n", msg, v);
        OutputDebugString(str);
    }
    void  VarMsg(HWND hwnd, char *msg, WORD n)
    {   char    str[80];
        wsprintf(str,"%s=%d\n",msg,n);
        SetWindowText(hwnd,(LPCSTR)str);
    }
    
    // IMAGE Object Class 関数
    // コンストラクタ(オブジェクトの初期化)
    IMAGEB32::IMAGEB32(HWND hwnd)
    {   hWnd= hwnd;
        hBmp= NULL;
        hBmpDC= NULL;
        Dib.hBmp = NULL;
        Dib.hBmpDC = NULL;
        m_Width = m_Height = 0;
        szFile[0]= '\0';
    }
    
    // デストラクタ(オブジェクトの終了)
    IMAGEB32::~IMAGEB32()
    {
        SAFE_DELDC(Dib.hBmpDC);
        SAFE_DELDC(hBmpDC);
        SAFE_DELOBJ(Dib.hBmp);
        SAFE_DELOBJ(hBmp);
    }
    
    //★ BMP File のロード
    HRESULT  IMAGEB32::LoadBmp(LPSTR szBitmap)
    {   HDC         hdc;
        BITMAP      bmp;
    
        SAFE_DELDC(Dib.hBmpDC);
        SAFE_DELDC(hBmpDC);
        SAFE_DELOBJ(Dib.hBmp);
        SAFE_DELOBJ(hBmp);
        m_Width = m_Height = 0;
    
        hBmp= (HBITMAP)LoadImage(NULL,szBitmap,IMAGE_BITMAP,0,0,
                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION);
        if (hBmp==NULL)
        {   MessageBox(NULL,szBitmap,"Load BMP Error",MB_OK);
            return  FALSE;
        }
        hdc= GetDC(hWnd);
        hBmpDC= CreateCompatibleDC(hdc);
        SelectObject(hBmpDC, hBmp);
    
        // サイズを保存
        GetObject(hBmp,sizeof(BITMAP),&bmp);
        m_Width= bmp.bmWidth;
        m_Height= bmp.bmHeight;
        m_Wbyte = (m_Width + 7) & 0xfffffff8;
        return TRUE;
    }
    
    //★ 画像を描画する
    HRESULT  IMAGEB32::Show(HDC hdc,long x,long y,long w,long h,long xd,long yd)
    {   if (hBmpDC==NULL)   return FALSE;
        BitBlt(hdc,x,y,w,h,hBmpDC,xd,yd,SRCCOPY);
        return TRUE;
    }
    
    // Dib 構造体を使って処理した画像を描画する 
    HRESULT  IMAGEB32::ShowDib(HDC hdc, long x, long y)
    {
        if (Dib.hBmpDC == NULL) return FALSE;
        BitBlt(hdc, x, y, m_Width, m_Height, Dib.hBmpDC, 0, 0, SRCCOPY);
        return TRUE;
    }
    
    //★ BMP 画像に合わせて 32bit Dib を初期化する
    void  IMAGEB32::InitDib()
    {   HDC      hDC;
        LPBITMAPINFO    Info;   //BITMAP 構造体のヘッダー
    
        hDC = GetDC(hWnd);
        Info = (LPBITMAPINFO)GlobalAlloc(GPTR, sizeof(BITMAPINFO));
        Info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        Info->bmiHeader.biWidth = m_Wbyte;
        Info->bmiHeader.biHeight = m_Height;
        Info->bmiHeader.biPlanes = 1;
        Info->bmiHeader.biBitCount = 32;        // 32 bit
        Info->bmiHeader.biCompression = BI_RGB; // 非圧縮
    
        Dib.hBmp = CreateDIBSection(hDC,Info,0,(void**)&Dib.Data,NULL,0);
        Dib.hBmpDC = CreateCompatibleDC(hDC);
        SelectObject(Dib.hBmpDC,Dib.hBmp);
    
        GlobalFree(Info);
        ReleaseDC(hWnd,hDC);
    }
    
    void  IMAGEB32::Grayscale()
    {   int     x, y;
        WORD    wk;
    
        Show(Dib.hBmpDC, 0, 0);
        for(y=0; y<m_Height; y++)
            for(x=0; x<m_Wbyte; x++)
            {
                wk= (MAP(y,x,2)*2 + MAP(y,x,1)*4 + MAP(y,x,0)) / 7;
                MAP(y,x,0)= (BYTE)wk;
                MAP(y,x,1)= (BYTE)wk;
                MAP(y,x,2)= (BYTE)wk;
            }
    }
    
    // Window Size を画像に合わす
    void  IMAGEB32::Adjust(BOOL flag)
    {   RECT    rc;
        int     x,y;
    
        GetWindowRect(hWnd,&rc);
        x= rc.left;
        y= rc.top;
        rc.right= x + m_Width;
        rc.bottom= y + m_Height;
        AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,flag);
        MoveWindow(hWnd,x,y,rc.right-rc.left,rc.bottom-rc.top,TRUE);
    }
    
    // OPENFILENAME 構造体で画像ファイルを Load する
    BOOL  IMAGEB32::OpenFile()
    {   OPENFILENAME    ofn;
    
        szFile[0]= '\0';
        memset(&ofn,0,sizeof(OPENFILENAME));
        ofn.lStructSize= sizeof(OPENFILENAME);
        ofn.hwndOwner= hWnd;
        ofn.lpstrFilter= "bmp(*.bmp)\0*.bmp\0All files(*.*)\0*.*\0\0";
        ofn.lpstrFile= szFile;
        ofn.lpstrFileTitle= NULL;
        ofn.nMaxFile= MAX_PATH;
        ofn.Flags= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
        ofn.lpstrDefExt= "gif";
        ofn.lpstrTitle= "ファイルオープン!";
        if (GetOpenFileName(&ofn)!=TRUE)    return FALSE;
        LoadBmp(szFile);
        return TRUE;
    }
    

BMP32 カラー ⇒ グレースケール

  1. BMP24 の画像は RGB を8ビットずつ(1ピクセル=24ビット)で記録されています。
    それに対して BMP32 の画像は RGBA を8ビットずつ(1ピクセル=32ビット)で記録されています。
    BMP32 の画像の詳細は プログラムの設計 などを参照して下さい。
    Alpha(A)の8ビット 青色(B)の8ビット 緑色(G)の8ビット 赤色(R)の8ビット
    これをグレースケールの「256階調に変換」します。
    少し工夫すれば「セピア色(RGB=107,74,43)」の画像も作成することが出来ます。
  2. グレースケールに変換する Grayscale() 関数です。
    hBmpDC に転送された画像をピクセル毎に演算して、256階調のグレースケールに変換します。
    RGB を単純に加えて3で割る方法では、色に対する明るさが考慮されていません。
    そこでウエイトを掛けて演算しています。
    #define     MAP(y,x,c)  (Dib.Data[(y*m_Width+x)*4+c])
    
    // Image 画像を Dib.hBmp に転送して Grayscale に変換する
    void  IMAGEB32::Grayscale()
    {   int     x, y;
        WORD    wk;
    
        Show(Dib.hBmpDC, 0, 0);
        for(y=0; y<m_Height; y++)
            for(x=0; x<m_Wbyte; x++)
            {
                wk= (MAP(y,x,2)*2 + MAP(y,x,1)*4 + MAP(y,x,0)) / 7;
                MAP(y,x,0)= (BYTE)wk;
                MAP(y,x,1)= (BYTE)wk;
                MAP(y,x,2)= (BYTE)wk;
            }
    }
    
  3. Main.cpp の AppInit() から OpenFile() で画像ファイルを選択します。
    InitDib() で DibStruct を初期化して下さい。
    WM_PAINT では Dib.hBmpDC の画像を描画するので Show() で最初の画像を設定します。
    // 画像をロードして、32bit DIB を作成
    LRESULT  AppInit(HWND hwnd)
    {
        ImageAI= new IMAGEB32(hwnd);
        if (ImageAI->OpenFile()==false) return false;
        ImageAI->Adjust(false);
        ImageAI->InitDib();
        ImageAI->Show(ImageAI->Dib.hBmpDC, 0, 0);
        return true;
    }
    
  4. WM_PAINT では ShowDib() で Dib.hBmpDC の画像を描画します。
            case WM_PAINT:          // Grayscale を描画
                hdc = BeginPaint(hWnd,&ps);
                if (ImageAI)
                {   ImageAI->ShowDib(hdc, 0, 0);  }
                EndPaint(hWnd, &ps);
                break;
    
  5. WM_LBUTTONDOWN では、カラー画像をグレースケールに変換します。
            case WM_LBUTTONDOWN:    // 左ボタンをクリック
                // Grayscale に変換
                ImageAI->Grayscale();
                InvalidateRect(hWnd,NULL,FALSE);
                break;
    
  6. WM_RBUTTONDOWN: では、新しい画像ファイルを入力します。
            case WM_RBUTTONDOWN:    // 右ボタンをクリック
                if (ImageAI->OpenFile()==false) return false;
                ImageAI->Adjust(false);
                ImageAI->InitDib();
                ImageAI->Show(ImageAI->Dib.hBmpDC, 0, 0);
                InvalidateRect(hWnd,NULL,FALSE);
                break;
    
  7. BMP24 カラー画像をグレースケールに変換するプログラムは Color ⇒ Grayscale を参照して下さい。

[Next Chapter ↓] りんご, バナナ, みかん
[Previous Chapter ↑] クリックで果物を抽出

超初心者のプログラム入門(Win32API C++)