Land Mark

検索範囲を矩形で設定して Land Mark を検出します。

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

プログラムの説明

  1. Land Mark を検出する image.cs のソースコードです。
    //★ Win32 API  Land Mark    前田 稔
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    struct BITMAPINFOHEADER
    {
        public UInt32 biSize;
        public Int32  biWidth;
        public Int32  biHeight;
        public UInt16 biPlanes;
        public UInt16 biBitCount;
        public UInt32 biCompression;
        public UInt32 biSizeImage;
        public Int32  biXPelsPerMeter;
        public Int32  biYPelsPerMeter;
        public UInt32 biClrUsed;
        public UInt32 biClrImportant;
    };
    unsafe struct BITMAPINFO
    {
        public BITMAPINFOHEADER bmih;
        public fixed UInt32 bmiColors[1];
    };
    
    public class MyForm : Form
    {   Face    App;
    
        public MyForm()
        {
            App = new Face();
            App.OpenFile();
            Width = App.m_bmp.Width;
            Height = App.m_bmp.Height+32;
            App.InitDib();
            App.CopyBmp(App.m_DibDC);
            App.CopyBmp(App.m_MaskDC);
            Paint += new PaintEventHandler(MyHandler);
            MouseDown += new MouseEventHandler(OnMyMouseDown);
        }
    
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g; 
            g = e.Graphics;
            if (App.m_bmp == null)  Application.Exit();
            App.ViewMask(g,0,0);
            App.DrawRect(g);
            App.DrawMark(g);
        }
    
        private void OnMyMouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)  //マウスの左ボタン
            {   App.Edge(33000);
            }
            if (e.Button == MouseButtons.Right) //マウスの右ボタン
            {   App.LandMark();
                App.CopyBmp(App.m_MaskDC);
            }
            Invalidate();
        }
    
        public void VerMsg(string msg, int v)
        {
            string wstr;
            wstr = msg + v.ToString();
            this.Text = wstr;
        }
    }
    
    //☆ Face Object Class
    unsafe class Face
    {
        ・・・
    
         Face Object Class のソースは Mark Rect を参照して下さい。
         
        ・・・
    
  2. Face Object Class のソースは Mark Rect に掲載しています。
    MyForm では Face Class を生成してから OpenFile(); で顔の画像を選択して入力します。
    入力する画像は Face Image Size で、鼻の頭を中心に 256*256 に整えた画像です。
    m_DibDC と m_MaskDC に App.CopyBmp(); で画像を転送します。
    m_DibDC の画像は濃淡の違いを調べるときに Sobel() 関数から参照します。
    MyHandler から描画する画像は m_MaskDC に作成された画像です。
    public class MyForm : Form
    {   Face    App;
    
        public MyForm()
        {
            App = new Face();
            App.OpenFile();
            Width = App.m_bmp.Width;
            Height = App.m_bmp.Height+32;
            App.InitDib();
            App.CopyBmp(App.m_DibDC);
            App.CopyBmp(App.m_MaskDC);
            Paint += new PaintEventHandler(MyHandler);
            MouseDown += new MouseEventHandler(OnMyMouseDown);
        }
    
  3. MyHandler() では App.ViewMask(g,0,0); で m_MaskDC の画像を描画します。
    顔の画像に重ねて App.DrawRect(g); で Land Mark を検出する矩形領域を表示します。
    顔の画像に重ねて App.DrawMark(g); で、検出された Land Mark を表示します。
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g; 
            g = e.Graphics;
            if (App.m_bmp == null)  Application.Exit();
            App.ViewMask(g,0,0);
            App.DrawRect(g);
            App.DrawMark(g);
        }
    
  4. マウスの左クリックで App.Edge(33000); でエッジを検出します。
    マウスの右クリックで Land Mark を検出して Point[] m_pt に格納します。
        private void OnMyMouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)  //マウスの左ボタン
            {   App.Edge(33000);
            }
            if (e.Button == MouseButtons.Right) //マウスの右ボタン
            {   App.LandMark();
                App.CopyBmp(App.m_MaskDC);
            }
            Invalidate();
        }
    
  5. m_pt が Land Mark を格納する配列で、鼻の頭と眉間と検出する5件の座標を格納します。
    1個目に鼻の頭の座標を、2個目に眉間の座標を格納します。
    3個目から5個の座標を LandMK() 関数で検索して格納します。
    mkt[5,5] から5件の矩形領域を t[5] にコピーして LandMK(t) 関数を呼び出します。
    LandMK(t) 関数では Point pt; に検索した Land Mark を設定してくれます。
        public Point[]  m_pt = new Point[7];    //Land Mark Table
    
        // Mark 検索パラメータを使って pt_t[7] にマーク座標を格納する
        public void LandMark()
        {
            int[] t = new int[5];
            m_pt[0].X = 128;
            m_pt[0].Y = 128;
            m_pt[1].X = 128;
            m_pt[1].Y = 192;
            for(int n=0; n<5; n++)
            {   for(int i=0; i<5; i++)  t[i] = mkt[n, i];
                LandMK(t);
                m_pt[n+2]= pt;
            }
        }
    
  6. Land Mark を検索する LandMK() 関数です。
    LandMK(int[] t) で渡されるパラメータ配列は、次のような意味を持ちます。
    パラメータ 説明
    t[0], t[1] 矩形領域の左下座標
    t[2], t[3] 矩形領域の右上座標
    t[4] 検索の方向(0:上, 1:下, 2:右, 3:左)
    ソースコードは長いのですが、検索の方向別に分けて考えてみて下さい。
    検索の方向が 0(上),1(下) のときはX座標は中央から左右交互に、2(右).3(左)のときはY座標は中央から上下交互に調べます。
        // m_Mask の画像から t[5] の範囲で Land Mark を検出する
        // t[0],t[1]=左下座標(X,Y),  t[2],t[3]=右上座標(X,Y), t[4]=検索方向
        public void LandMK(int[] t)
        {   int w,h,cx,cy,x,y,x1,x2,y1,y2;
    
            pt.X = pt.Y = 0;
            w= t[2]-t[0];
            h= t[3]-t[1];
            cx= t[0]+w/2;
            cy= t[1]+h/2;
    
            switch(t[4])
            {   case 0:     //上方向
                    for(y=0; y<h; y++)
                        for(x=0; x<w/2; x++)
                        {
                            y1= t[1]+y;
                            x1= cx+x;
                            x2= cx-x;
                            if (MASK(x1,y1,0)==0)
                            {   pt.X= x1;
                                pt.Y= y1;
                                return;
                            }
                            if (MASK(x2,y1,0)==0)
                            {   pt.X= x2;
                                pt.Y= y1;
                                return;
                            }
                        }
                    break;
                case 1:     //下方向
                    for(y=0; y<h; y++)
                        for(x=0; x<w/2; x++)
                        {
                            y1= t[3]-y;
                            x1= cx+x;
                            x2= cx-x;
                            if (MASK(x1,y1,0)==0)
                            {   pt.X= x1;
                                pt.Y= y1;
                                return;
                            }
                            if (MASK(x2,y1,0)==0)
                            {   pt.X= x2;
                                pt.Y= y1;
                                return;
                            }
                        }
                    break;
                case 2:     //右方向
                    for(x=0; x<w; x++)
                        for(y=0; y<h/2; y++)
                        {
                            x1= t[0]+x;
                            y1= cy+y;
                            y2= cy-y;
                            if (MASK(x1,y1,0)==0)
                            {   pt.X= x1;
                                pt.Y= y1;
                                return;
                            }
                            if (MASK(x1,y2,0)==0)
                            {   pt.X= x1;
                                pt.Y= y2;
                                return;
                            }
                        }
                    break;
                case 3:     //左方向
                    for(x=0; x<w; x++)
                        for(y=0; y<h/2; y++)
                        {
                            x1= t[2]-x;
                            y1= cy+y;
                            y2= cy-y;
                            if (MASK(x1,y1,0)==0)
                            {   pt.X= x1;
                                pt.Y= y1;
                                return;
                            }
                            if (MASK(x1,y2,0)==0)
                            {   pt.X= x1;
                                pt.Y= y2;
                                return;
                            }
                        }
                    break;
            }
        }
    }
    
  7. C言語(Windows)のプログラムは Mark Rect を参照して下さい。

[Next Chapter ↓] 顔画像の識別
[Previous Chapter ↑] Mark Rect

超初心者のプログラム入門(C# Frame Work)