何となく Blog by Jitta
Microsoft .NET 考

目次

Blog 利用状況
  • 投稿数 - 761
  • 記事 - 18
  • コメント - 36877
  • トラックバック - 222
ニュース
  • IE7以前では、表示がおかしい。div の解釈に問題があるようだ。
    IE8の場合は、「互換」表示を OFF にしてください。
  • 検索エンジンで来られた方へ:
    お望みの情報は見つかりましたか? よろしければ、コメント欄にどのような情報を探していたのか、ご記入ください。
It's ME!
  • はなおか じった
  • 世界遺産の近くに住んでます。
  • Microsoft MVP for Visual Developer ASP/ASP.NET 10, 2004 - 9, 2011
広告

記事カテゴリ

書庫

日記カテゴリ

ギャラリ

その他

わんくま同盟

同郷

 

ネタもと:http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=25346&forum=7

①ある画像に背景(緑)とは異なった色の点(赤)を4つ記し,その4点をVBによって認識し,四角形を作成したい。
②その四角形を領域とし,その領域内を2値化するプログラムを作成したい。

4点を抽出する方法を説明します。

 まず、抽出しやすくします。1つの画像から4点を抽出しようとするから、難しいのです。「その点が、4点のうちどれにあたるか」などを考えないといけませんから。なので、1つの画像から1つの点を抽出することを考えます。
 この事例では、4点は「画像の4角近くにある」ことが期待できます。ですから、画像を左上、右上、左下、右下の4つに分割します。
 これで1つの画像から1点のみ、抽出すればいいことになります。そして、元の画像の配置を考えれば、点の位置関係を復元することが出来ます。


// originalImage に、元の画像があるとする
int holizontal = originalImage.Width / 2;
int vertical = originalImage.Height / 2;
Bitmap[] img = new Bitmap[4];
img[0] = new Bitmap(holizontal, vertical);
img[1] = new Bitmap(originalImage.Width - holizontal, vertical);
img[2] = new Bitmap(holizontal, originalImage.Height - vertical);
img[3] = new Bitmap(originalImage.Width - holizontal, originalImage.Height - vertical);
Graphics original = Graphics.FromImage(originalImage);
Graphics[] grp = new Graphics[4];
grp[0] = Graphics.FromImage(img[0]);
grp[1] = Graphics.FromImage(img[1]);
grp[2] = Graphics.FromImage(img[2]);
grp[3] = Graphics.FromImage(img[3]);
grp[0].DrawImage(originalImage
 , new Rectangle(0, 0, img[0].Width, img[0].Height)
 , new Rectangle(0, 0, holizontal, vertical)
 , GraphicsUnit.Pixel);
grp[1].DrawImage(originalImage
 , new Rectangle(0, 0, img[1].Width, img[1].Height)
 , new Rectangle(holizontal, 0, originalImage.Width - holizontal, vertical)
 , GraphicsUnit.Pixel);
grp[2].DrawImage(originalImage
 , new Rectangle(0, 0, img[2].Width, img[2].Height)
 , new Rectangle(0, vertical, holizontal, originalImage.Height - vertical)
 , GraphicsUnit.Pixel);
grp[3].DrawImage(originalImage
 , new Rectangle(0, 0, img[3].Width, img[3].Height)
 , new Rectangle(holizontal, vertical, originalImage.Width - holizontal
  , originalImage.Height - vertical)
 , GraphicsUnit.Pixel);


抽出するべき点(探索始点)を探す方法を説明します。

 まぁ、左上から順に探せばいいのですが、画像の中心付近にあるだろうという仮定の下、中心から探すことにします。
 ここでは、HSV で分析して、点を探すことにします。Hue の範囲を0~15と、290~360にしました。「赤みがかった」と思える範囲です。また、Britness が 0.5 を下回ると「黒」とほとんど見分けが付かないので棄てます。また、0.9 以上、明るすぎるところも棄てています。彩度も、0.2 以下は棄てます。この辺は「調整の必要がある」ということで。


private bool IsSearchingColor(Color c) {
 if (c.GetHue() < 15.0 || c.GetHue() > 290.0) {
  if (c.GetBrightness() < 0.9 && c.GetBrightness() > 0.5
   && c.GetSaturation() > 0.2) {
   return true;
  }
 }
 return false;
}
private Point SearchPoint(Bitmap image) {
 int w = (int)Math.Ceiling(image.Width / 2.0);
 int h = (int)Math.Ceiling(image.Height / 2.0);
 for (int idxH = 0; idxH < h; idxH++) {
  int y01 = h - idxH;
  int y23 = h + idxH > image.Height ? image.Height : h + idxH;
  for (int idxW = 0; idxW < w; idxW++) {
   int x02 = w - idxW;
   int x13 = w + idxW > image.Width ? image.Width : w + idxW;
   Point[] p = new Point[4];
   p[0] = new Point(x02, y01);
   p[1] = new Point(x13, y01);
   p[2] = new Point(x02, y23);
   p[3] = new Point(x13, y23);
   for (int idxP = 0; idxP < 4; idxP++) {
    Color c = image.GetPixel(p[idxP].X, p[idxP].Y);
    if (IsSearchingColor(c)) { return p[idxP]; }
   }
  }
 }
 return new Point(-1, -1);
}


抽出するべき点を拡大する方法を説明します。

 先に出した探索始点(*)の周り8点が、抽出すべき色かどうかを調べ、登録します。inArea には「抽出するべき色だった点」、points には、「次に調べる中心となる点」が入ります。次の図で、3を中心に調査するとき、4が重複しますが、HashTable.Contains により、登録を省きます。


private Rectangle Extent(Bitmap image, Point startPoint) {
 System.Collections.Hashtable inArea = SearchPointsInArea(image, startPoint);
 System.Collections.IEnumerator ipt = inArea.GetEnumerator();
 Point topLeft = new Point(startPoint.X, startPoint.Y);
 Point bottomRight = new Point(startPoint.X, startPoint.Y);
 while (ipt.MoveNext()) {
  Point pt = (Point)inArea[((System.Collections.DictionaryEntry)ipt.Current).Key];
  if (topLeft.X > pt.X) { topLeft.X = pt.X; }
  if (topLeft.Y > pt.Y) { topLeft.Y = pt.Y; }
  if (bottomRight.X < pt.X) { bottomRight.X = pt.X; }
  if (bottomRight.Y < pt.Y) { bottomRight.Y = pt.Y; }
 }
 return new Rectangle(topLeft.X, topLeft.Y
  , bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
}
public System.Collections.Hashtable SearchPointsInArea(Bitmap image, Point startPoint) {
 System.Collections.Hashtable inArea = new System.Collections.Hashtable();
 System.Collections.Queue points = new System.Collections.Queue();
 points.Enqueue(startPoint);
 while (points.Count > 0) {
  Point center = (Point)points.Dequeue();
  for (int idx = 0; idx < 8; idx++) {
   Point inspect = RoundPoint(center, idx);
   Color c = image.GetPixel(inspect.X, inspect.Y);
   if (IsSearchingColor(c)) {
    if (!inArea.Contains(inspect)) {
     inArea.Add(inspect, inspect);
     points.Enqueue(inspect);
    }
   }
  }
 }
 return inArea;
}
private Point RoundPoint(Point center, int index) {
 switch (index) {
  case 0:
   return new Point(center.X, center.Y + 1);
  case 1:
   return new Point(center.X - 1, center.Y + 1);
  case 2:
   return new Point(center.X - 1, center.Y);
  case 3:
   return new Point(center.X - 1, center.Y - 1);
  case 4:
   return new Point(center.X, center.Y - 1);
  case 5:
   return new Point(center.X + 1, center.Y - 1);
  case 6:
   return new Point(center.X + 1, center.Y);
  case 7:
   return new Point(center.X + 1, center.Y + 1);
  case 8:
   return new Point(center.X, center.Y);
 }
 return center;
}

これで4点の抽出が出来ました。結果は次のようになりました。右上に当たるところが、ゴミを拾ってしまっています。また、探索始点の探索を、横方向を優先して行っていますが、縦方向を優先すると、左上以外はゴミを拾ってしまいます。


 領域にするには、マーカーのある領域が出てきましたから、どういう範囲を領域にするかを決めます。つまり、各マーカーの中心を結ぶとか、マーカーを含まない内側とか。決めた点を Polygon クラス(を作って) に放り込めば、領域ができあがります。

投稿日時 : 2005年10月25日 19:12
コメント
  • # re: 4点の抽出
    ☆VB初心者☆
    Posted @ 2005/11/17 16:12
    ご無沙汰しております,☆VB初心者☆です。
    わざわざVCでプログラムを作って頂き有難うございました。
    今,画像を加工して白黒の反転をしているところです。(最近まで私情でPCでの作業があまり出来なかったため前の段階から全く進んでいません^^;)

    そんな段階でこのような質問は失礼かもしれませんが,反転した画像(私が『プリント』を使って芝生のみを黒にした画像)とVBのプログラムによって抽出した画像を比較して,どれだけプログラムが精密に抽出しているか?というのをVBで判定出来るものなのでしょうか?
    ご指導の旨,宜しくお願い致します。
  • # re: 4点の抽出
    Jitta
    Posted @ 2005/11/18 5:08
    > 反転した画像(VBのプログラムによって抽出した画像を比較

     同じ大きさであれば、容易ですよ。
     for 文でぐるぐる回して、同じ位置の色を比較すればいいですから。


     あと、「領域内の判定」を作っていませんが、三角形の中にあるかどうか、という判定を2回やれば、わかります。
タイトル
名前
Url
コメント