Image 3原色

3原色を個々に設定して描画します。

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

ImageAI Class Ver-1

  1. テンプレートのプロジェクトは「超初心者のC言語(Windows)」から「Windows10 & Win32 API」で提供しています。
    画像解析に使用する専用の ImageAI Class のヘッダーファイル ImageAI.h です。
    //★ IMAGE_AI_1 Object Header File  前田 稔
    #ifndef     _ImageAI
    #define     _ImageAI
    #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)*3+c])
    
    typedef struct
    {   HBITMAP         hBmp;
        HDC             hBmpDC;
        LPBYTE          Data;           // 24bit DIB の BITMAP DATA
    }   DibStruct;
    
    class IMAGEAI
    { protected:
        HWND        hWnd;
        HBITMAP     hBmp;               //画像の HBITMAP
        HDC         hBmpDC;             //画像の HDC
    
      public:
        long        m_Width;            //画像の幅
        long        m_Height;           //画像の高さ
        DibStruct   Dib;                //RGB 画像解析の構造体
    
        IMAGEAI(HWND hWnd);             //Constructor
        virtual ~IMAGEAI();             //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);  }
        //StretchBlt() で描画する
        HRESULT     Show(HDC hdc,long x,long y,long w,long h,long sx,long sy,long sw,long sh);
        HRESULT     Show(HDC hdc,POINTS beg,POINTS end);
    
        //DibStruct を描画する
        HRESULT     ShowDib(HDC hdc, long x, long y);
    
        //Dib Function
        void        InitDib();
        void        SetRGB(int mode);
        void        Light(WORD val);
    
        void        Adjust(BOOL flag=TRUE);
    };
    
    #endif
    
  2. ImageAI Class のプログラムファイル ImageAI.cpp のソースコードです。
    // IMAGE_AI_1 Object Class Library  前田 稔
    #include    "ImageAI.h"
    
    // IMAGE Object Class 関数
    // コンストラクタ(オブジェクトの初期化)
    IMAGEAI::IMAGEAI(HWND hwnd)
    {   hWnd= hwnd;
        hBmp= NULL;
        hBmpDC= NULL;
        Dib.hBmpDC = NULL;
        Dib.hBmp = NULL;
        m_Width = m_Height = 0;
    }
    
    // デストラクタ(オブジェクトの終了)
    IMAGEAI::~IMAGEAI()
    {
        SAFE_DELDC(Dib.hBmpDC);
        SAFE_DELDC(hBmpDC);
        SAFE_DELOBJ(Dib.hBmp);
        SAFE_DELOBJ(hBmp);
    }
    
    //★ BMP File のロード
    HRESULT  IMAGEAI::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;
        return TRUE;
    }
    
    //★ 画像を描画する
    HRESULT  IMAGEAI::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;
    }
    
    HRESULT  IMAGEAI::Show(HDC hdc,long x,long y,long w,long h,long sx,long sy,long sw,long sh)
    {   if (hBmpDC==NULL)   return FALSE;
        StretchBlt(hdc,x,y,w,h,hBmpDC,sx,sy,sw,sh,SRCCOPY);
        return TRUE;
    }
    
    HRESULT  IMAGEAI::Show(HDC hdc,POINTS beg,POINTS end)
    {   if (hBmpDC==NULL)   return FALSE;
        StretchBlt(hdc,0,0,m_Width,m_Height,hBmpDC,beg.x,beg.y,end.x-beg.x,end.y-beg.y,SRCCOPY);
        return TRUE;
    }
    
    // Dib 構造体を使って処理した画像を描画する 
    HRESULT  IMAGEAI::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 画像に合わせて 24bit Dib を初期化する
    void  IMAGEAI::InitDib()
    {   HDC      hDC;
        LPBITMAPINFO    Info;   // BITMAP 構造体のヘッダー
    
        hDC = GetDC(hWnd);
        Info = (LPBITMAPINFO)GlobalAlloc(GPTR, sizeof(BITMAPINFO));
        Info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        Info->bmiHeader.biWidth = m_Width;
        Info->bmiHeader.biHeight = m_Height;
        Info->bmiHeader.biPlanes = 1;
        Info->bmiHeader.biBitCount = 24;        // 24 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);
    }
    
    // Image 画像を Dib.hBmp に転送して mode の色に設定する関数
    void  IMAGEAI::SetRGB(int mode)
    {   int     x, y;
    
        Show(Dib.hBmpDC, 0, 0);
        // mode の色に設定する
        for (y = 0; y<m_Height; y++)
            for (x = 0; x<m_Width; x++)
            {
                if ((mode & 1) == 0)    MAP(y, x, 0) = 0;
                if ((mode & 2) == 0)    MAP(y, x, 1) = 0;
                if ((mode & 4) == 0)    MAP(y, x, 2) = 0;
            }
    }
    
    // Image 画像を Dib.hBmp に転送して val(100~600) の明るさに設定する関数
    void  IMAGEAI::Light(WORD val)
    {   int     x, y, cp;
        WORD    wk;
    
        Show(Dib.hBmpDC, 0, 0);
        for (y = 0; y<m_Height; y++)
            for (x = 0; x<m_Width; x++)
                for (cp = 0; cp<3; cp++)
                {
                    wk= MAP(y, x, cp);
                    wk= (wk*val)/100;
                    if (wk > 255)   wk = 255;
                    MAP(y, x, cp) = (BYTE)wk;
                }
    }
    
    // Window Size を画像に合わす
    void  IMAGEAI::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);
    }
    
  3. 3原色を個々に設定して描画する Main.cpp のソースコードです。
    //★ 画像の色モードを設定する    2018/03/15  前田 稔
    #define     NAME    "BMP Fade"
    #include    <windows.h>
    #include    "ImageAI.h"
    #pragma     once
    #define     SAFE_DELETE(p)  { if (p) { delete (p);     (p)=NULL; } }
    
    HINSTANCE       g_hInst;
    HWND            g_hWnd;
    HDC             hdc;
    IMAGEAI         *ImageAI= NULL;         // IMAGE-AI Object Class
    char            ImgFile[]= "c:\\data\\test\\ffx2s.bmp";
    int             mode= 7;                // 色モード(0~7)
    
    // 画像をロードして、24bit DIB を作成
    LRESULT  AppInit(HWND hwnd)
    {
        ImageAI= new IMAGEAI(hwnd);
        if (ImageAI->LoadBmp(ImgFile)==false)   return false;
        ImageAI->InitDib();
        ImageAI->SetRGB(7);
        return true;
    }
    
    // プロシージャ
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
    {   PAINTSTRUCT ps;
    
        switch(msg)
        {   case WM_CREATE:         // 初期化
                if (AppInit(hWnd)==FALSE)   PostQuitMessage(0);
                break;
            case WM_PAINT:          // Dib の画像を描画
                hdc = BeginPaint(hWnd,&ps);
                if (ImageAI)   ImageAI->ShowDib(hdc,30,20);
                EndPaint(hWnd, &ps);
                break;
            case WM_LBUTTONDOWN:    // 左ボタンをクリック
                mode= (mode+1)%8;
                // Dib.hBmp の色を mode に設定
                ImageAI->SetRGB(mode);
                InvalidateRect(hWnd,NULL,FALSE);
                break;
            case WM_RBUTTONDOWN:    // 右ボタンをクリック
                mode= 7;
                ImageAI->Show(ImageAI->Dib.hBmpDC, 0, 0);
                InvalidateRect(hWnd,NULL,FALSE);
                break;
            case WM_CLOSE:          // クローズ
                SAFE_DELETE(ImageAI);
                DestroyWindow(hWnd);
                break;
            case WM_DESTROY: 
                PostQuitMessage(0);
                break;
            default:
                return(DefWindowProc(hWnd, msg, wp, lp));
        }
        return (0L);
    }
    
    //★ Windows Main 関数
    int APIENTRY  WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)
    {   MSG     msg;
    
        g_hInst= hInst;
        WNDCLASS wc = { CS_CLASSDC,WndProc,0L,0L,hInst,NULL,LoadCursor(NULL,IDC_ARROW),
                        (HBRUSH)GetStockObject(BLACK_BRUSH),NULL,NAME };
        if (RegisterClass(&wc)==0)    return FALSE;
        g_hWnd= CreateWindow(NAME,NAME,WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT,CW_USEDEFAULT,600,400,
                             NULL,NULL,hInst,NULL);
        if (!g_hWnd)  return FALSE;
    
        ShowWindow(g_hWnd,nCmdShow);    //Window を表示
        UpdateWindow(g_hWnd);           //表示を初期化
        SetFocus(g_hWnd);               //フォーカスを設定
        while (GetMessage(&msg,NULL,0,0))
        {   TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return S_OK;                    //return 0
    }
    

3原色で描画

  1. BMP 画像の横幅(Width)は【8の倍数】に合わせて下さい。
    (バウンダリが合わない画像の扱いは Face Image を参照)
    画像の色(ピクセル)は、3原色(赤緑青)を8ビット(256階調)の組み合わせで表します。
    青色(B)の8ビット 緑色(G)の8ビット 赤色(R)の8ビット
    このプログラムでは、3原色を個々に設定して描画します。
    "c:\\data\\test\\ffx2s.bmp" がテストに使用した画像です。
    mode が色の組み合わせを指定する領域で「0~7」で指定します。
    char    ImgFile[]= "c:\\data\\test\\ffx2s.bmp";
    int     mode= 7;                // 色モード(0~7)
    
    1: が青色に対応するビットで、2: が緑色に対応するビットで、4: が赤色に対応するビットです。
    例えば 1: は青色になり、6: は緑と赤の組み合わせで黄色になります。
  2. LoadBmp() で画像をロードした後で InitDib() で DibStruct を初期化して下さい。
    SetRGB(7) で最初は画像の色を本来の色に設定します。
    // 画像をロードして、24bit DIB を作成
    LRESULT  AppInit(HWND hwnd)
    {   HDC      hDC;
    
        ImageAI= new IMAGEAI(hwnd);
        if (ImageAI->LoadBmp(ImgFile)==false)  return false;
        ImageAI->InitDib();
        ImageAI->SetRGB(7);
        return true;
    }
    
  3. マウスの左クリックで mode の値を0~7で繰り返します。
    0: で真っ暗になり、7: で本来の色で描画されます。
            case WM_LBUTTONDOWN:    // 左ボタンをクリック
                mode= (mode+1)%8;
                // Dib.hBmp の色を mode に設定
                ImageAI->SetRGB(mode);
                InvalidateRect(hWnd,NULL,FALSE);
                break;
    
  4. SetRGB() が赤緑青の色を mode に従って設定する関数です。
    Show(Dib.hBmpDC, 0, 0); で入力した画像を DibStruct の hBmpDC に転送します。
    そして Dib.hBmpDC のイメージを mode に従って色ごとに off(ゼロ) にします。
    ゼロに設定された色は無くなるので、例えば mode=1 では青色だけで描画されます。
    実行結果を見ていただきたいのですが、カラー写真の画像などでは面白い画像になります。
    // Image 画像を Dib.hBmp に転送して mode の色に設定する関数
    void  IMAGEAI::SetRGB(int mode)
    {   LONG    dx, dy;
    
        Show(Dib.hBmpDC, 0, 0);
        // mode の色に設定する
        for (dy = 0; dy<m_Height; dy++)
            for (dx = 0; dx<m_Width; dx++)
            {
                if ((mode & 1) == 0)    MAP(dy, dx, 0) = 0;
                if ((mode & 2) == 0)    MAP(dy, dx, 1) = 0;
                if ((mode & 4) == 0)    MAP(dy, dx, 2) = 0;
            }
    }
    
  5. WM_PAINT では mode に従って色を off(ゼロ) に設定した画像を ShowDib() で描画します。
            case WM_PAINT:          // Dib の画像を描画
                hdc = BeginPaint(hWnd,&ps);
                if (ImageAI)   ImageAI->ShowDib(hdc,30,20);
                EndPaint(hWnd, &ps);
                break;
    
  6. Dib.hBmpDC の画像を描画する ShowDib() 関数です。
    // Dib 構造体を使って処理した画像を描画する 
    HRESULT  IMAGEAI::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;
    }
    
  7. C# でも同様のプログラム Win32 3原色 を作成しています。

[Next Chapter ↓] Light
[Previous Chapter ↑] 画像解析ガイド

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