我一直在尝试修改程序,以便它可以接受单个字母字符的多个数据,例如字母“A”。有某种ContainsKey函数只允许键盘中的一个键只保存一个数据。如何能够保存多个数据?
我要说得很清楚,这是一个使用无监督神经网络的在线OCR程序。当用户在绘图空间中绘制角色时,他们可以选择将角色添加到学习数据中以便稍后训练。当他们添加一个角色时,他们必须使用键盘上的键来定义他们刚输入的角色。例如,他们绘制字母'A',弹出窗口将显示要求用户从键盘输入该字母的密钥。
这里的问题是,当学习数据中已经有一个字母'A'时,我不能添加另一个字母'A',因为密钥A已经保留了之前的'A'。我想让钥匙A能够容纳多个字母'A'。
我要在这里发布该程序的整个代码,我希望你们能忍受我。这不是我的程序,它来自Heaton Research,我打算修改它。提前谢谢。
public partial class Form1 : Form
{
/**
* The downsample width for the application.
*/
const int DOWNSAMPLE_WIDTH = 10;
/**
* The down sample height for the application.
*/
const int DOWNSAMPLE_HEIGHT = 12;
private Bitmap entryImage;
private Graphics entryGraphics;
private int entryLastX;
private int entryLastY;
private Pen blackPen;
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
private double[][] trainingSet;
private SelfOrganizingMap network;
public Form1()
{
InitializeComponent();
blackPen = new Pen(Color.Black);
entryImage = new Bitmap(entry.Width, entry.Height);
entryGraphics = Graphics.FromImage(entryImage);
downsampled = new bool[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
ClearEntry();
}
private void entry_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(entryImage, 0, 0);
Pen blackPen = new Pen(Color.Black);
g.DrawRectangle(blackPen, 0, 0, entry.Width - 1, entry.Height - 1);
}
private void btnDelete_Click(object sender, EventArgs e)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.letterData.Remove(ch);
this.letters.Items.Remove(str);
ClearEntry();
}
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
TextReader f = new StreamReader(openFileDialog1.FileName);
String line;
this.letterData.Clear();
this.letters.Items.Clear();
while ((line = f.ReadLine()) != null)
{
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
char ch = char.ToUpper(line[0]);
bool[] sample = new bool[sampleSize];
int idx = 2;
for (int i = 0; i < sampleSize; i++)
{
if (line[idx++] == '1')
sample[i] = true;
else
sample[i] = false;
}
this.letterData.Add(ch, sample);
this.letters.Items.Add("" + ch);
}
f.Close();
}
MessageBox.Show(this, "File Loaded");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
TextWriter f = new StreamWriter(saveFileDialog1.FileName);
int size = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
for (int i = 0; i < this.letters.Items.Count; i++)
{
char ch = ((string)this.letters.Items[i])[0];
bool[] data = this.letterData[ch];
f.Write(ch + ":");
for (int j = 0; j < size; j++)
{
f.Write(data[j] ? "1" : "0");
}
f.WriteLine("");
}
f.Close();
MessageBox.Show("File Saved");
}
}
catch (Exception e2)
{
MessageBox.Show("Error: " + e2.Message, "Training");
}
}
private void btnBeginTraining_Click(object sender, EventArgs e)
{
int inputCount = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
int letterCount = this.letters.Items.Count;
this.trainingSet = new double[letterCount][];
int index = 0;
foreach (char ch in this.letterData.Keys)
{
this.trainingSet[index] = new double[inputCount];
bool[] data = this.letterData[ch];
for (int i = 0; i < inputCount; i++)
{
this.trainingSet[index][i] = data[i] ? 0.5 : -0.5;
}
index++;
}
network = new SelfOrganizingMap(inputCount, letterCount, NormalizationType.Z_AXIS);
this.ThreadProc();
}
private void btnAdd_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
String Prompt = "Enter the letter you just draw (from the keyboard)";
String Title = "Letter definition Required";
String Default = " ";
Int32 XPos = ((SystemInformation.WorkingArea.Width / 2) - 200);
Int32 YPos = ((SystemInformation.WorkingArea.Height / 2) - 100);
bool valid = false;
for (int i = 0; i < this.downsampled.Length; i++)
{
if (this.downsampled[i])
{
valid = true;
}
}
if (!valid)
{
MessageBox.Show("Please draw a letter before adding it.");
return;
}
String Result = Microsoft.VisualBasic.Interaction.InputBox(Prompt, Title, Default, XPos, YPos);
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
//else if (this.letterData.ContainsKey(Result[0]))
//{
// MessageBox.Show("That letter is already defined, please delete first.");
//}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() {this.downsampled});
}
this.letters.Items.Add(Result);
//this.letterData.Add(Result[0], this.downsampled);
this.ClearEntry();
}
}
}
private void btnRecognize_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
if (this.network == null)
{
MessageBox.Show("The program needs to be trained first");
return;
}
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
double[] input = new double[sampleSize];
for (int i = 0; i < sampleSize; i++)
{
input[i] = this.downsampled[i] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
char[] map = mapNeurons();
this.result.Text = " " + map[best];
MessageBox.Show(" " + map[best] + " (Neuron #"
+ best + " fired)", "That Letter You Enter Is");
//ClearEntry();
}
private void btnClear_Click(object sender, EventArgs e)
{
ClearEntry();
}
private void btnSample_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
public void ClearEntry()
{
Brush whiteBrush = new SolidBrush(Color.White);
entryGraphics.FillRectangle(whiteBrush, 0, 0, entry.Width, entry.Height);
entry.Invalidate();
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
private void entry_MouseDown(object sender, MouseEventArgs e)
{
entry.Capture = true;
entryLastX = e.X;
entryLastY = e.Y;
}
private void entry_MouseUp(object sender, MouseEventArgs e)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entry.Capture = false;
}
private void entry_MouseMove(object sender, MouseEventArgs e)
{
if (entry.Capture == true)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entryLastX = e.X;
entryLastY = e.Y;
}
}
private void sample_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
int x, y;
int vcell = sample.Height / Form1.DOWNSAMPLE_HEIGHT;
int hcell = sample.Width / Form1.DOWNSAMPLE_WIDTH;
Brush whiteBrush = new SolidBrush(Color.White);
Brush blackBrush = new SolidBrush(Color.Black);
Pen blackPen = new Pen(Color.Black);
g.FillRectangle(whiteBrush, 0, 0, sample.Width, sample.Height);
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
g.DrawLine(blackPen, 0, y * vcell, sample.Width, y * vcell);
}
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
g.DrawLine(blackPen, x * hcell, 0, x * hcell, sample.Height);
}
int index = 0;
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
if (this.downsampled[index++])
{
g.FillRectangle(blackBrush, x * hcell, y * vcell, hcell, vcell);
}
}
}
g.DrawRectangle(blackPen, 0, 0, sample.Width - 1, sample.Height - 1);
}
private void letters_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.letters.SelectedIndex >= 0)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.downsampled = this.letterData[ch];
this.sample.Invalidate();
}
}
public void ThreadProc()
{
TrainSelfOrganizingMap train = new TrainSelfOrganizingMap(
this.network, this.trainingSet, TrainSelfOrganizingMap.LearningMethod.SUBTRACTIVE, 0.5);
int tries = 1;
do
{
train.Iteration();
this.txtTries.Text = "" + tries;
this.txtBestError.Text = "" + train.BestError;
this.txtLastError.Text = "" + train.TotalError;
tries++;
Application.DoEvents();
} while (train.TotalError > 0.01 && (tries <= 100));
MessageBox.Show("Training complete.");
}
/**
* Used to map neurons to actual letters.
*
* @return The current mapping between neurons and letters as an array.
*/
public char[] mapNeurons()
{
char[] map = new char[this.letters.Items.Count];
for (int i = 0; i < map.Length; i++)
{
map[i] = '?';
}
for (int i = 0; i < this.letters.Items.Count; i++)
{
double[] input = new double[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
char ch = ((string)(this.letters.Items[i]))[0];
bool[] data = this.letterData[ch];
for (int j = 0; j < input.Length; j++)
{
input[j] = data[j] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
map[best] = ch;
}
return map;
}
}
答案 0 :(得分:2)
Dictionary<>
的创建方式使您可以以最有效的方式访问键值对。现在在Dictionary<>
中,你不能拥有两对相同的密钥。为此,
你可以做什么,你创建了一个像Dictionary<char, List<bool[]>>
这样的字典,现在在这个词典中你可以存储一个具有多个值的键。
<强>更新强>
如果您将字典更改为Dictionary<char, List<bool[]>>
,那么要存储一个具有多个值的键,您必须按如下方式
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
//
// Your Code
//
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() { this.downsampled });
}
this.letters.Items.Add(Result);
this.ClearEntry();
}
}
如果您想string
作为键,而不是char
,请使用Dictionary<string, List<bool[]>>
。
希望这能回答你的问题。
答案 1 :(得分:0)
查看.Net中的Lookup课程。这使您可以多次使用相同的“键”值。