物置‎ > ‎

TemplateMatching2

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TemplateMatching
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
      stopWatch = new System.Diagnostics.Stopwatch();
    }

    private void searchLoadButton_Click(object sender, EventArgs e)
    {
      OpenFileDialog ofd = new OpenFileDialog();
      ofd.Filter = "BMP|*.BMP|すべてのファイル|*.*";
      if (ofd.ShowDialog() == DialogResult.OK)
      {
        this.searchTextBox.Text = ofd.FileName;
      }
    }

    private void templateLoadButton_Click(object sender, EventArgs e)
    {
      OpenFileDialog ofd = new OpenFileDialog();
      ofd.Filter = "BMP|*.BMP|すべてのファイル|*.*";
      if (ofd.ShowDialog() == DialogResult.OK)
      {
        this.templateTextBox.Text = ofd.FileName;
      }
    }

    //戻り値:一致した場合は true を返す。
    private bool match(long maxSAD)
    {
      maxSAD++;

      try
      {
        stopWatch.Restart();
        searchBmp = new Bitmap(searchTextBox.Text);
        templateBmp = new Bitmap(templateTextBox.Text);

        if (searchBmp.Width < templateBmp.Width ||
          searchBmp.Height < templateBmp.Height)
        {
          MessageBox.Show("検索画像がテンプレ画像より高さまたは幅が小さいです。");
          return false;
        }

        resultLabel.Text = "しばらくお待ち下さい。";
        resultLabel.Update();

        long minSAD = maxSAD; // SAD は Sum of Absolute Differences の略。
        leftTopMatchCount = 0;
        bool onlyMatchLeftTop = onlyMatchLeftTopCheckBox.Checked;

        for (int x = 0; x <= searchBmp.Width - templateBmp.Width; x++)
        {
          for (int y = 0; y <= searchBmp.Height - templateBmp.Height; y++)
          {
            long SAD = 0;

            // [テンプレ画像の左上一致時のみ処理]チェックボックスがチェックされている場合、
            // 実行に時間がかかるので、左上が一致した場合だけ処理する。
            if (searchBmp.GetPixel(x, y) != templateBmp.GetPixel(0, 0))
            {
              if (onlyMatchLeftTop) continue;
            }
            else
            {
              leftTopMatchCount++;
            }

            for (int i = 0; i < templateBmp.Width; i++)
            {
              for (int j = 0; j < templateBmp.Height; j++)
              {
                Color s = searchBmp.GetPixel(x + i, y + j);
                Color t = templateBmp.GetPixel(i, j);
                SAD += Math.Abs(s.R - t.R) + Math.Abs(s.G - t.G) + Math.Abs(s.B - t.B);
              }
              if (minSAD < SAD)
              {
                break;  // 高速化!
              }
            }

            if (minSAD > SAD)
            {
              minSAD = SAD;
              bestX = x;
              bestY = y;
            }
          }
        }

        stopWatch.Stop();
        if (minSAD == maxSAD)
        {
          resultLabel.Text = "一致パターンはありません。";
        }
        else
        {
          resultLabel.Text = "一致しました。\r\n\r\nX座標=" + bestX + "\r\nY座標=" + bestY + "\r\nSAD=" + minSAD +
            "\r\n左上一致回数=" + leftTopMatchCount + "\r\n処理時間=" + stopWatch.ElapsedMilliseconds + "ミリ秒";
          saveBmp = searchBmp;
          return true;
        }
      }
      catch
      {
        MessageBox.Show("画像ファイルパスを正しく入力してください。");
      }
      return false;
    }

    private bool go()
    {
      try
      {
        long sad = long.Parse(maxSADTextBox.Text);
        return match(sad);
      }
      catch
      {
        MessageBox.Show("最大許容値を正しく入力してください。");
      }
      return false;
    }

    private void save()
    {
      SaveFileDialog ofd = new SaveFileDialog();
      ofd.Filter = "BMP|*.BMP|PNG|*.PNG|JPEG|*.JPEG";
      if (ofd.ShowDialog() == DialogResult.OK)
      {
        for (int i = 0; i < templateBmp.Width; i++)
        {
          saveBmp.SetPixel(bestX + i, bestY, Color.Black);
          saveBmp.SetPixel(bestX + i, bestY + templateBmp.Height - 1, Color.Black);
        }
        for (int i = 0; i < templateBmp.Height; i++)
        {
          saveBmp.SetPixel(bestX, bestY + i, Color.Black);
          saveBmp.SetPixel(bestX + templateBmp.Width - 1, bestY + i, Color.Black);
        }
        string ext;
        ext = System.IO.Path.GetExtension(ofd.FileName);
        if (string.Compare(ext, ".BMP", true) == 0)
        {
          saveBmp.Save(ofd.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
        }
        else if (string.Compare(ext, ".PNG", true) == 0)
        {
          saveBmp.Save(ofd.FileName, System.Drawing.Imaging.ImageFormat.Png);
        }
        else if (string.Compare(ext, ".JPEG", true) == 0)
        {
          saveBmp.Save(ofd.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
      }
    }

    private void goButton_Click(object sender, EventArgs e)
    {
      go();
    }

    private void goAndSavebutton_Click(object sender, EventArgs e)
    {
      if (go())
      {
        save();
      }
    }

    private int bestX;
    private int bestY;
    private Bitmap saveBmp;
    private Bitmap searchBmp;
    private Bitmap templateBmp;

    private int leftTopMatchCount;
    private System.Diagnostics.Stopwatch stopWatch;
  }
}

Form1.Designer.cs
namespace TemplateMatching
{
  partial class Form1
  {
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows フォーム デザイナーで生成されたコード

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      this.searchLoadButton = new System.Windows.Forms.Button();
      this.templateLoadButton = new System.Windows.Forms.Button();
      this.searchTextBox = new System.Windows.Forms.TextBox();
      this.templateTextBox = new System.Windows.Forms.TextBox();
      this.resultLabel = new System.Windows.Forms.Label();
      this.goButton = new System.Windows.Forms.Button();
      this.label1 = new System.Windows.Forms.Label();
      this.maxSADTextBox = new System.Windows.Forms.TextBox();
      this.goAndSavebutton = new System.Windows.Forms.Button();
      this.onlyMatchLeftTopCheckBox = new System.Windows.Forms.CheckBox();
      this.SuspendLayout();
      // 
      // searchLoadButton
      // 
      this.searchLoadButton.Location = new System.Drawing.Point(12, 12);
      this.searchLoadButton.Name = "searchLoadButton";
      this.searchLoadButton.Size = new System.Drawing.Size(119, 31);
      this.searchLoadButton.TabIndex = 0;
      this.searchLoadButton.Text = "検索画像読み込み";
      this.searchLoadButton.UseVisualStyleBackColor = true;
      this.searchLoadButton.Click += new System.EventHandler(this.searchLoadButton_Click);
      // 
      // templateLoadButton
      // 
      this.templateLoadButton.Location = new System.Drawing.Point(13, 49);
      this.templateLoadButton.Name = "templateLoadButton";
      this.templateLoadButton.Size = new System.Drawing.Size(119, 31);
      this.templateLoadButton.TabIndex = 0;
      this.templateLoadButton.Text = "テンプレ画像読み込み";
      this.templateLoadButton.UseVisualStyleBackColor = true;
      this.templateLoadButton.Click += new System.EventHandler(this.templateLoadButton_Click);
      // 
      // searchTextBox
      // 
      this.searchTextBox.Location = new System.Drawing.Point(157, 18);
      this.searchTextBox.Name = "searchTextBox";
      this.searchTextBox.Size = new System.Drawing.Size(273, 19);
      this.searchTextBox.TabIndex = 1;
      // 
      // templateTextBox
      // 
      this.templateTextBox.Location = new System.Drawing.Point(158, 55);
      this.templateTextBox.Name = "templateTextBox";
      this.templateTextBox.Size = new System.Drawing.Size(273, 19);
      this.templateTextBox.TabIndex = 1;
      // 
      // resultLabel
      // 
      this.resultLabel.AutoSize = true;
      this.resultLabel.Location = new System.Drawing.Point(156, 154);
      this.resultLabel.Name = "resultLabel";
      this.resultLabel.Size = new System.Drawing.Size(48, 12);
      this.resultLabel.TabIndex = 2;
      this.resultLabel.Text = "出力なし";
      // 
      // goButton
      // 
      this.goButton.Location = new System.Drawing.Point(13, 147);
      this.goButton.Name = "goButton";
      this.goButton.Size = new System.Drawing.Size(119, 26);
      this.goButton.TabIndex = 3;
      this.goButton.Text = "実行";
      this.goButton.UseVisualStyleBackColor = true;
      this.goButton.Click += new System.EventHandler(this.goButton_Click);
      // 
      // label1
      // 
      this.label1.AutoSize = true;
      this.label1.Location = new System.Drawing.Point(56, 89);
      this.label1.Name = "label1";
      this.label1.Size = new System.Drawing.Size(96, 12);
      this.label1.TabIndex = 4;
      this.label1.Text = "最大許容値(SAD)";
      // 
      // maxSADTextBox
      // 
      this.maxSADTextBox.ImeMode = System.Windows.Forms.ImeMode.Disable;
      this.maxSADTextBox.Location = new System.Drawing.Point(158, 86);
      this.maxSADTextBox.Name = "maxSADTextBox";
      this.maxSADTextBox.Size = new System.Drawing.Size(273, 19);
      this.maxSADTextBox.TabIndex = 1;
      this.maxSADTextBox.Text = "10";
      // 
      // goAndSavebutton
      // 
      this.goAndSavebutton.Location = new System.Drawing.Point(13, 191);
      this.goAndSavebutton.Name = "goAndSavebutton";
      this.goAndSavebutton.Size = new System.Drawing.Size(118, 26);
      this.goAndSavebutton.TabIndex = 5;
      this.goAndSavebutton.Text = "実行して保存";
      this.goAndSavebutton.UseVisualStyleBackColor = true;
      this.goAndSavebutton.Click += new System.EventHandler(this.goAndSavebutton_Click);
      // 
      // onlyMatchLeftTopCheckBox
      // 
      this.onlyMatchLeftTopCheckBox.AutoSize = true;
      this.onlyMatchLeftTopCheckBox.Checked = true;
      this.onlyMatchLeftTopCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
      this.onlyMatchLeftTopCheckBox.Location = new System.Drawing.Point(13, 114);
      this.onlyMatchLeftTopCheckBox.Name = "onlyMatchLeftTopCheckBox";
      this.onlyMatchLeftTopCheckBox.Size = new System.Drawing.Size(199, 16);
      this.onlyMatchLeftTopCheckBox.TabIndex = 6;
      this.onlyMatchLeftTopCheckBox.Text = "テンプレ画像の左上一致時のみ処理";
      this.onlyMatchLeftTopCheckBox.UseVisualStyleBackColor = true;
      // 
      // Form1
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(453, 256);
      this.Controls.Add(this.onlyMatchLeftTopCheckBox);
      this.Controls.Add(this.goAndSavebutton);
      this.Controls.Add(this.label1);
      this.Controls.Add(this.goButton);
      this.Controls.Add(this.resultLabel);
      this.Controls.Add(this.maxSADTextBox);
      this.Controls.Add(this.templateTextBox);
      this.Controls.Add(this.searchTextBox);
      this.Controls.Add(this.templateLoadButton);
      this.Controls.Add(this.searchLoadButton);
      this.Name = "Form1";
      this.Text = "Form1";
      this.ResumeLayout(false);
      this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.Button searchLoadButton;
    private System.Windows.Forms.Button templateLoadButton;
    private System.Windows.Forms.TextBox searchTextBox;
    private System.Windows.Forms.TextBox templateTextBox;
    private System.Windows.Forms.Label resultLabel;
    private System.Windows.Forms.Button goButton;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.TextBox maxSADTextBox;
    private System.Windows.Forms.Button goAndSavebutton;
    private System.Windows.Forms.CheckBox onlyMatchLeftTopCheckBox;
  }
}