Zaku認識(2)

前回のZaku認識(1)の続きです。
http://www.moonmile.net/blog/archives/576

物体/動体認識をするときに、白黒を使うことが多いのですが、残念ながら、これでは「シャアザク」と「ザク」の区別がつきません。何故、この2つを区別しなければいけないのか、、、は脇に置いて、区別できる方法で、認識をさせます。

RGB(赤/緑/青)の3値から、白黒画像を作る場合は、YCbCr(YIQ)画像に変換して、Y値だけ残します。

まず、次の画像を見てください。

<001>
20100208_001

真ん中にあるガンダムの左上にシャアがいますね。
これをグレー色調にすると、

<002>
20100208_002

こんな風に、シャアがザクに隠れてしまいます。
これでは、シャアザクだけを攻撃することはできませんね(笑)。

そんな訳で、YIQからHSV表示に変換して、H値(色相)だけ残します。

<003>
20100208_003

サーモグラフィのような画像になりますが、シャアザクの位置が、なんとなくわかります。

同様に次の3つを見比べると、ガンダムの右にシャアがいそうな感じ、ってくぐらいは分かります。

<004>
20100208_004

<005>
20100208_005

<006>
20100208_006

色が単純化されるのは、色相のみ残して、輝度、彩度を一定値にしているからです。
これを使うと、緑の量産ザクと、赤のシャアザクが区別できるんですね。
グレーの場合は、赤緑色盲と一緒で、輝度が同じなので区別がつきません。

RGB/YIQ/HSV表示の相互変換は、こちら

namespace zaku.monoeye
{
 // RGB表示系クラス
 // r: 赤
 // g: 緑
 // b: 青
 public class RGB
 {
  public double r;
  public double g;
  public double b;
  
  public RGB()
  {
   r = g = b = 0;
  }

        // 正規化されたRGB値(0.0-1.0)
  public RGB( double r, double g, double b )
  {
   this.r = r;
   this.g = g;
   this.b = b;
  }
        // ディスプレイのRGB値(0-255)
        public RGB(Color col)
        {
            this.r = ((double)col.R) / 255.0;
            this.g = ((double)col.G) / 255.0;
            this.b = ((double)col.B) / 255.0;
        }

        public Color ToColor()
        {
            int r, g, b;
            r = (int)(this.r * 255);
            g = (int)(this.g * 255);
            b = (int)(this.b * 255);
         if ( r < 0 ) r = 0;
         if ( g < 0 ) g = 0;
         if ( b < 0 ) b = 0;
            if (r > 255) r = 255;
            if (g > 255) g = 255;
            if (b > 255) b = 255;

            Color col = Color.FromArgb(255, r, g, b );
            return col;
        }

  
  public YIQ ToYIQ()
  {
   YIQ yiq = new YIQ(
    0.2990 * r + 0.5870 * g + 0.1140 * b,
    0.5959 * r - 0.2750 * g - 0.3210 * b,
    0.2065 * r - 0.4969 * g + 0.2904 * b );
   
   return yiq;
  }
 }
 
 // YIQ表示系クラス
 // y: 輝度
 // i: 青み成分
 // q: 赤み成分
 public class YIQ
 {
  public double y;
  public double i;
  public double q;
  
  public YIQ()
  {
   y = i = q = 0.0;
  }
  public YIQ( double y, double i, double q )
  {
   this.y = y;
   this.i = i;
   this.q = q;
  }
  
  public RGB ToRGB()
  {
   RGB rgb = new RGB(
    1.001 * y + 0.955 * i + 0.622 * q,
    0.999 * y - 0.272 * i - 0.648 * q,
    1.004 * y - 1.106 * i + 1.704 * q );
   return rgb;
  }
  public HSV ToHSV()
  {
   HSV hsv = new HSV();
            hsv.h = Math.Atan2(i, q);
            hsv.s = Math.Sqrt(i * i + q * q);
   hsv.v = y;
            return hsv;
  }
 }
 
 // HSV表示系クラス
 // h: 色相
 // s: 彩度
 // v: 輝度
 public class HSV
 {
  public double h;
  public double s;
  public double v;
  
  public HSV()
  {
   h = s = v = 0.0;
  }
  public HSV( double h, double s, double v )
  {
   this.h = h;
   this.s = s;
   this.v = v;
  }
  public YIQ ToYIQ()
  {
   YIQ yiq = new YIQ();
   yiq.y = v;
   yiq.i = s * Math.Sin( h );
            yiq.q = s * Math.Cos(h);
            return yiq;
  }
 }
}

次回は、背景から動体抽出ですね~。

カテゴリー: 雑談 パーマリンク