ページ 11

画像認識について

Posted: 2012年7月20日(金) 21:07
by ももっこ
VC++を使って画像認識をしようと思い、下記のURLにある肌色と左右対称性を用いた顔の検出というプログラムを使ってやってみましたが、いまいちやり方が良く分かりませんでした。

もし、下記のソースにmain文をつけたらどのようなプログラムになりますか?
分かる人いたら教えてください
よろしくお願いします

コード:


private: System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {

  Graphics^ gr=e->Graphics;

  int X0=10,X1=340,Y0=10,Y1=260;
  int FACES_MAX=20;      //検出する顔の数の上限を20個とする
  int F_WIDTH=23,F_HEIGHT=29; //フレームのサイズ
  int i,j,p,q,r,g,b,d,n;
  int x,y,xx,yy;
  int x_max,y_max,counter_max;
  int skin_count;
  Color color1,color2;
  int candidate_count;  //フレームと肌色によって検出した顔の数(対称性チェック前)
  int diff;        //対称性を調べるための差分

  array<Point^>^ candidate=gcnew array<Point^>(FACES_MAX);   //顔の候補の座標位置を示す 
  array<int>^ shift=gcnew array<int>{0,-1,1,-2,2,-3,3,-4,4};  //対称性を調べるときの左右のシフト量

  Bitmap^ bmap_skin=gcnew Bitmap(WIDTH,HEIGHT);   //肌色を検出した画像
  Bitmap^ bmap_gray=gcnew Bitmap(WIDTH,HEIGHT);   //肌色部をグレイ化した画像

  //原画像を読み込む
  Bitmap^ bmap_src=gcnew Bitmap("faces.JPG");
  //原画像bmap_srcを左上に表示する
  gr->DrawImage(bmap_src,X0,Y0);
  //肌色を検出した白黒画像bmap_skinとグレイ化画像bmap_grayを得る
  for(y=0;y<HEIGHT;y++)
    for(x=0;x<WIDTH;x++){
      color1=bmap_src->GetPixel(x,y);
      r=color1.R;
      g=color1.G;
      b=color1.B;
      d=(2*r+4*g+b)/7;
      if((r>g*1.1 && r<g*2.4) && (r>b*1.1 && r<b*2.4) && r>90){ //肌色(「易しい画像認識(1)」参照)
        bmap_skin->SetPixel(x,y,Color::White);
        bmap_gray->SetPixel(x,y,Color::FromArgb(d,d,d));
      }
      else{                           //肌色以外
        bmap_skin->SetPixel(x,y,Color::Black);
        bmap_gray->SetPixel(x,y,Color::Black);
      }
    }
  //肌色画像bmap_skinとグレイ画像bmap_grayを右上と左下に表示する
  gr->DrawImage(bmap_skin,X1,Y0);
  gr->DrawImage(bmap_gray,X0,Y1); 
  //白黒画像bmap_skinを二次元データにする
  array<int,2>^ pixel_data=gcnew array<int,2>(WIDTH,HEIGHT);
  pixel_data=getPixelDataFromBitmap(bmap_skin);
  //白黒画像bmap_skinの積分型二次元データを得る
  array<int,2>^ integral_image=gcnew array<int,2>(WIDTH,HEIGHT);
  integral_image=createIntegralImageFromPixelData(pixel_data);
  //積分型二次元データintegral_imageを用いて肌色のピクセル数を求めcount[x,y]に入れる
  array<int,2>^ count=gcnew array<int,2>(WIDTH,HEIGHT);
  for(y=0;y<HEIGHT-F_HEIGHT;y++)
    for(x=0;x<WIDTH-F_WIDTH;x++)
      count[x,y]=0;
      for(y=0;y<HEIGHT-F_HEIGHT;y++)
        for(x=0;x<WIDTH-F_WIDTH;x++){
          skin_count=integral_image[x,y]+integral_image[x+F_WIDTH,y+F_HEIGHT]-integral_image[x+F_WIDTH,y]-integral_image[x,y+F_HEIGHT];
          if(skin_count>267)  count[x,y]=skin_count;  //フレーム内ピクセル数の40%を超えれば
        }
      for(n=0;n<FACES_MAX;n++){
        //肌色のカウント数最大のフレームの位置x_max,y_maxを求める
        counter_max=0;
        for(y=0;y<HEIGHT;y++)
          for(x=0;x<WIDTH;x++){
            if(count[x,y]>counter_max){
              counter_max=count[x,y];
              x_max=x;
              y_max=y; 
            }
          }
        if(counter_max<400) break;  //フレーム内ピクセル数の60%未満は顔と認識しない
        //座標位置を格納する
        candidate[n]=gcnew Point(x_max,y_max);
        //周辺を削除する
        for(p=-15;p<=15;p++)
          for(q=-15;q<=15;q++){
            xx=x_max+q;
            if(xx<0) xx=0;
            if(xx>=WIDTH)   xx=WIDTH-1;
            yy=y_max+p;
            if(yy<0) yy=0;
            if(yy>=HEIGHT)   yy=HEIGHT-1;
            count[xx,yy]=0;
          }

        //白黒画像bmap_skin上に顔候補のフレームを描く
        gr->DrawRectangle(Pens::Red,X1+x_max,Y0+y_max,F_WIDTH,F_HEIGHT);
      }
  candidate_count=n;

  //------------------------- 対称検出処理 ----------------------------- 
  for(i=0;i<candidate_count;i++){
    x=candidate[i]->X;
    y=candidate[i]->Y;
    for(j=0;j<9;j++){
      xx=x+shift[j];
      diff=0;
      for(q=0;q<F_HEIGHT;q++)
        for(p=5;p<F_WIDTH/2;p++){   //左右各5ピクセルは調べない
          color1=bmap_gray->GetPixel(xx+p,y+q);      //左から
          color2=bmap_gray->GetPixel(xx+F_WIDTH-1-p,y+q); //右から
          diff+=Math::Abs(color1.R-color2.R);
        }
      if(diff<5700){   //ピクセル1対当たり平均濃度差約30未満を顔と判定
        //グレイ画像bmap_gray上に新たな判定結果のフレームを描く
        gr->DrawRectangle(Pens::Lime,X0+xx,Y1+y,F_WIDTH,F_HEIGHT);
        break;
      }
    }
  }

}

//画像をピクセルデータ化する(「易しい画像処理(9)」を参考)
private: array<int,2>^ getPixelDataFromBitmap(Bitmap^ bmap){

  int width=bmap->Width;
  int height=bmap->Height;

  Color color1;
  array<int,2>^ p_data=gcnew array<int,2>(width,height);

  for(int j=0;j<height;j++)
    for(int i=0;i<width;i++){
  color1=bmap->GetPixel(i,j);
  if(color1.R<128)  p_data[i,j]=0; //黒は0に
  else        p_data[i,j]=1; //白は1に
    }
  return p_data;

}

//ピクセルデータから積分形二次元配列データを求める(「易しい画像処理(9)」より)
private: array<int,2>^ createIntegralImageFromPixelData(array<int,2>^ p_data){

  array<int,2>^ integral=gcnew array<int,2>(WIDTH,HEIGHT);
  int sum=0;

  //一番上の行
  for(int i=1;i<WIDTH;i++){
    sum+=p_data[i,0];
    integral[i,0]=sum;
  }
  //二番目以降の行
  for(int j=1;j<HEIGHT;j++){
    sum=0;
    for(int i=0;i<WIDTH;i++){
      sum+=p_data[i,j];
      integral[i,j]=integral[i,j-1]+sum;
    }
  }
  return integral;

}

Re: 画像認識について

Posted: 2012年7月20日(金) 21:14
by softya(ソフト屋)
このコードは、VC++ので使える3つの言語
1.C言語
2.C++
3.C++/CLI (.NET FrameWork)
のうちの3のC++/CLIを使っていてフォームアプリケーション用のコードとなっています。

なので普通のmainが出てくる事自体がありません。
理解している言語と試そうとしているサンプルにズレはありませんか?

【補足】
サイトは、こちらですね?
「Visual C++ 2010 Express を用いた易しい画像認識(3)―― 肌色と左右対称性を用いた顔の検出 ――」
http://homepage3.nifty.com/ishidate/vcp ... p10_r3.htm


上記ページの目次です。基本的にC++/CLIを使った.NET FrameWorkで記述されています。
「Visual C++ の勉強部屋」
http://homepage3.nifty.com/ishidate/vcpp.htm

Re: 画像認識について

Posted: 2012年7月20日(金) 22:35
by momokko
ありがとうございました

Re: 画像認識について

Posted: 2012年7月20日(金) 22:39
by softya(ソフト屋)
momokko さんが書きました:ありがとうございました
解決したら、どう解決したのか説明と解決チェックをお願いします。
後代案とかいらないのでしょうか?

Re: 画像認識について

Posted: 2012年7月21日(土) 04:06
by pp
りょーかい 

Re: 画像認識について

Posted: 2012年7月21日(土) 14:24
by asd
pp さんが書きました:りょーかい 
ここはももっこさんのスレッドなので、無関係なppさんが勝手に解決チェックをつけないようお願いします。
それとも名前を統一させていないだけで、最初の質問をしたももっこさんなのでしょうか?

その場合「りょーかい」ではどのように解決したのか全く理解できません。
それとも次以降あなたが質問してきた場合「りょーかい」と書きこめばそれですべて理解していただけるのでしょうか?