Как сделать словарь, который может содержать более 1 данных? - PullRequest
1 голос
/ 18 января 2012

Я пытался изменить программу, чтобы она могла принимать более одной информации для одного символа алфавита, например буква «А».существовала какая-то функция ContainsKey, позволяющая удерживать только одну клавишу на клавиатуре только одной клавишей.Как сделать возможным хранение более чем одной информации?

Я хочу пояснить, что это онлайн-программа распознавания текста, использующая нейронную сеть без присмотра.когда пользователь рисует символ в пространстве для рисования, у него будет возможность добавить символ в обучающие данные для последующего обучения.когда они добавляют символ, они должны определить, какой символ они только что ввели, используя клавишу на клавиатуре.например, они рисуют букву «А», и появится всплывающее окно с просьбой ввести клавишу с клавиатуры для этой буквы.

проблема здесь, когда в обучающих данных уже есть буква «А», я не могу добавить еще одну букву «А», потому что клавиша А уже удерживает предыдущую «А».Я хотел, чтобы ключ 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;
    }

}

Ответы [ 2 ]

2 голосов
/ 19 января 2012

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[]>>.

Надеюсь, это ответит на ваш вопрос.

0 голосов
/ 19 января 2012

Взгляните на класс Lookup в .Net. Это позволяет вам иметь одно и то же значение ключа несколько раз.

...