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;
}
}