顔画像の識別


複数枚の顔画像を記録して、示された画像の番号を当てます。
顔認証システムの基礎のそのまた基礎です。

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

顔画像の識別

  1. 顔画像の識別は、色やサイズで識別することは出来ないので、パーツの相対位置や大きさや特徴を利用します。
    Main.cpp で顔の画像を記録する10枚分のランドマークの領域を定義します。
    m_idx は記録する顔の画像の Index です。
    str は MessageBox で表示するメッセージの領域です。
    FACE        *Face= NULL;    // FACE Object Class
    bool        flag = false;
    POINT       m_t[10][5];     //Land Mark Table
    int         m_idx;          //m_t Index
    char        str[80];
    
  2. WM_CREATE では FACE Class を生成して Initialize します。
        {   case WM_CREATE:         // 初期化
                Face = new FACE(hWnd);
                m_idx= 0;
                str[0] = '\0';
                break;
    
  3. WM_PAINT ではプログラムの開始メッセージまたは、画像がロードされているときは Dib.hBmpDC の画像を描画します。
    また str にメッセージが設定されていれば MessageBox を実行します。
            case WM_PAINT:
                hdc = BeginPaint(hWnd,&ps);
                if (flag)   Face->ShowDib(hdc, 0, 0);
                else
                    TextOut(hdc,50,100,(LPCTSTR)"画像を登録して、識別します。", 28);
                EndPaint(hWnd, &ps);
                if (str[0]!='\0')   MessageBox(NULL, str, "画像の識別", MB_OK);
                break;
    
  4. 左ボタンのクリックで選択した画像のランドマークを取得して m_t に記録します。
    入力するのは Face Image でサイズを 256*256 に整えた画像です。
    閾値を 12000 で Edge() 関数を呼び出して Mask 画像を作成します。
    マスク画像を使って LandMark() 関数でランドマークを検出します。
    Face->pt_t[i] に格納されたランドマークを m_t に記録します。
    顔の画像によっては、ランドマークが正しく設定されていない場合もありますが、顔画像を識別するだけのときは気にしなくても構いません。
            case WM_LBUTTONDOWN:    // 左ボタンをクリック
                if (Face->OpenFile()==false)    return false;
                Face->InitDib();
                Face->Adjust(false);
                Face->Show(Face->Dib.hBmpDC, 0, 0);
                flag = true;
                Face->Edge(12000);
                Face->LandMark();
                for(i=0; i<5; i++)  m_t[m_idx][i]= Face->pt_t[i];
                m_idx++;
                wsprintf(str, "顔の画像を登録します");
                InvalidateRect(hWnd, NULL, FALSE);
                break;
    
  5. 右ボタンのクリックで選択した画像が何番目の画像かを当てます。
    左クリックの場合と同様にランドマークを検出して m_t と照合します。
    一致した画像が見つかればその番号を、みつから無ければ「登録されていません」を表示します。
            case WM_RBUTTONDOWN:    // 右ボタンをクリック
                if (Face->OpenFile()==false)    return false;
                Face->InitDib();
                Face->Adjust(false);
                Face->Show(Face->Dib.hBmpDC, 0, 0);
                flag = true;
                Face->Edge(12000);
                Face->LandMark();
                for (j = 0; j < m_idx; j++)
                {   for (i = 0; i < 5; i++)
                        if (m_t[j][i].x != Face->pt_t[i].x || m_t[j][i].y != Face->pt_t[i].y)   break;
                    if (i>=5)   break;
                }
                if (j<m_idx)    wsprintf(str, "%d 番目の画像です", j+1);
                else    wsprintf(str, "登録されていません");
                InvalidateRect(hWnd, NULL, FALSE);
                break;
    
  6. プログラムの開始時にメッセージを表示するので、ウインドウの背景色を白色に設定しています。
    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(WHITE_BRUSH),NULL,NAME };
    
  7. ランドマークを検出する LandMark() 関数です。
    見つけた5個の座標を POINT pt_t[5] に記録します。
    // Mark 検索パラメータを使って pt_t[5] にマーク座標を格納する
    void  FACE::LandMark()
    {   for(int n=0; n<5; n++)
        {   LandMK(mkt[n]);
            pt_t[n]= pt;
            Mark(pt.x, pt.y);
        }
        Mark(128, 128);
        Mark(128, 192);
    }
    
  8. プログラムを起動して、左クリックから3枚の画像を登録して下さい。
    右クリックで登録済の画像を選択すると、登録した番号が表示されます。
    4枚目の画像を選択すると「登録されていません」が表示されます。
    左クリックから4枚目の画像を登録すると識別されるようになります。
    5個のランドマークを使っているのですが、画像を識別するには十分なようです。
  9. 顔認証のプログラムは、ここからが本番です。
    顔認証に利用するには、正確に Land Mark を設定しなければなりません。
    左右の対称性や座標の妥当性などもチェックする必要があるでしょう。
    用途によっては、正面以外の顔や髪や眼鏡で隠れた場合の対策も必要です。
    顔の表情によって、マークが移動する許容範囲を考慮することも必要です。
    人物の違いにより、マーク間の距離や相対座標のバラツキも調べる必要があり、実用的なシステムでは数千枚の顔の画像を調べて 「正しく認証されるか、違った人物を認証しないか」をテストする必要があるようです。

[Previous Chapter ↑] Mark Rect

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