Advertisement

Neural Network outputs not correct

Started by September 14, 2005 03:04 AM
-1 comments, last by chadjohnson 19 years, 2 months ago
I'm working on a handwriting recognition program (I know, it's not a game - hope no one minds), and when I train my feedforward neural network using the different characteristics for each image as inputs, all the outputs (26 in all) eventually become flat zero (after a couple hundred thousand training sessions). In training, for example, when training on the letter S I set every output neuron's target value to -1 except for the one corresponding to S which I set to 1. This seems to do nothing though. I have used this network library (I wrote it) to train a network to learn a continuous function, and it worked great - and I ran it through several million training sessions (using a low learning rate). Does anyone have any helpful hints as to why it might not be working in this case? I'm having the program look at the following characteristics: number of intersections (on a grid), closest distances to image on all sides (normalized), and the percentages of colored pixels in four quadrants (using monochrome bitmaps for training). BTW, is it better to do recognition by using a block grid and just using each grid square as an input? Here's some code (it uses the wxWidgets library for the GUI). There is a lot of redundancy - I'll fix that later:
// handwriting.cpp

#include <wx/wxprec.h>

#ifndef WX_PRECOMP
    #include <wx/wx.h>
#endif

#include "handwriting.h"

IMPLEMENT_APP(Handwriting)

BEGIN_EVENT_TABLE(MainFrame, wxFrame)
    EVT_INIT_DIALOG(MainFrame::OnInitDialog)
    EVT_CLOSE(MainFrame::OnClose)
    EVT_MENU(MENU_FILE_EXIT, MainFrame::OnFileExit)
    EVT_MENU(MENU_TOOLS_TRAINING, MainFrame::OnToolsTraining)
    EVT_MENU(MENU_HELP_ABOUT, MainFrame::OnHelpAbout)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(DrawCanvas, wxScrolledWindow)
    EVT_MOTION(DrawCanvas::OnMouseMove)
    EVT_LEFT_DOWN(DrawCanvas::OnLeftMouseDown)
    EVT_LEFT_UP(DrawCanvas::OnLeftMouseUp)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(TrainingDialog, wxDialog)
    EVT_INIT_DIALOG(TrainingDialog::OnInitDialog)
    EVT_CLOSE(TrainingDialog::OnClose)
    EVT_BUTTON(BUTTON_ADD, TrainingDialog::OnAddButton)
    EVT_BUTTON(BUTTON_TEST, TrainingDialog::OnTestButton)
    EVT_BUTTON(BUTTON_REMOVE, TrainingDialog::OnRemoveButton)
    EVT_BUTTON(BUTTON_START, TrainingDialog::OnStartButton)
    EVT_BUTTON(BUTTON_CLOSE, TrainingDialog::OnCloseButton)
END_EVENT_TABLE()

/*****************************************************************************/
// Handwriting class functions
/*****************************************************************************/
bool Handwriting::OnInit()
{
    // Create a neural network instance
    m_neuralNetwork = new NeuralNetwork();

    // Create an input layer, one hidden layer, and an output layer
    m_neuralNetwork->AddLayer(INPUT_NEURON_COUNT+1);
    m_neuralNetwork->AddLayer(HIDDEN_NEURON_COUNT);
    m_neuralNetwork->AddLayer(OUTPUT_NEURON_COUNT);

    // Set a bias value
    m_neuralNetwork->SetInputValue(INPUT_NEURON_COUNT, 1);

    m_mainFrame = new MainFrame("Handwriting Recognition", 320, 320);
    m_mainFrame->Centre();
    m_mainFrame->Show(TRUE);

    return true;
}

NeuralNetwork *Handwriting::GetNeuralNetwork() const
{
    return m_neuralNetwork;
}

MainFrame *Handwriting::GetMainFrame() const
{
    return m_mainFrame;
}
/*****************************************************************************/
// MainFrame class functions
/*****************************************************************************/
MainFrame::MainFrame(const wxString &title, int width, int height)
        : wxFrame((wxFrame*) NULL, -1, title, wxDefaultPosition, wxSize(width, height), wxDEFAULT_FRAME_STYLE & ~ (wxRESIZE_BORDER | wxRESIZE_BOX | wxMAXIMIZE_BOX))
{
    // File menu
    m_menuFile = new wxMenu();
    m_menuFile->Append(MENU_FILE_EXIT, _T("E&xit"));

    // Tools menu
    m_menuTools = new wxMenu();
    m_menuTools->Append(MENU_TOOLS_TRAINING, _T("T&raining..."));

    // Help menu
    m_menuHelp = new wxMenu();
    m_menuHelp->Append(MENU_HELP_ABOUT, _T("About..."));

    m_menuBar = new wxMenuBar();
    m_menuBar->Append(m_menuFile, _T("&File"));
    m_menuBar->Append(m_menuTools, _T("&Tools"));
    m_menuBar->Append(m_menuHelp, _T("&Help"));
    SetMenuBar(m_menuBar);

    m_panel = new wxPanel(this, -1);
    m_textMain = new wxTextCtrl(m_panel, -1, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
    m_canvas = new DrawCanvas(m_panel, wxDefaultPosition, wxSize(100, 100), wxSIMPLE_BORDER);

    wxFlexGridSizer *sizer = new wxFlexGridSizer(2, 1, 0, 0);
    sizer->Add(m_textMain, 0, wxALL|wxEXPAND, 4);
    sizer->Add(m_canvas, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_CENTER, 4);
    sizer->AddGrowableRow(0);
    sizer->AddGrowableCol(0);

    m_panel->SetSizer(sizer);
    m_panel->SetAutoLayout(true);
    m_panel->Layout();

    InitDialog();
}

void MainFrame::OnInitDialog(wxInitDialogEvent &event)
{
}

void MainFrame::OnClose(wxCloseEvent &event)
{
    //SaveDataToFile();
    Destroy();
}

void MainFrame::OnFileExit(wxCommandEvent &event)
{
    Close();
}

void MainFrame::OnToolsTraining(wxCommandEvent &event)
{
    TrainingDialog *dlg = new TrainingDialog(this);
    dlg->ShowModal();
}

void MainFrame::OnHelpAbout(wxCommandEvent &event)
{
    wxMessageBox(_T("Copyright 2005 Chad Johnson (chad.d.johnson@gmail.com)"), "About");
}
/*****************************************************************************/
// DrawCanvas class functions
/*****************************************************************************/
DrawCanvas::DrawCanvas(wxWindow *parent, wxPoint pos, wxSize size, long style)
        : wxScrolledWindow(parent, -1, pos, size, style)
{
    SetBackgroundColour(wxColour(*wxWHITE));
}

void DrawCanvas::OnMouseMove(wxMouseEvent& event)
{
    wxClientDC dc(this);
    DoPrepareDC(dc);

    wxPoint pt(event.GetLogicalPosition(dc));

    if (lastX > -1 && lastY > -1 && event.Dragging() && event.LeftIsDown())
    {
        wxPen pen;
        pen.SetWidth(2);
        pen.SetColour(0,0,255);

        dc.SetPen(pen);
        dc.DrawLine(lastX, lastY, pt.x, pt.y);
    }

    lastX = pt.x;
    lastY = pt.y;
}

void DrawCanvas::OnLeftMouseDown(wxMouseEvent &event)
{
}

void DrawCanvas::OnLeftMouseUp(wxMouseEvent &event)
{
    int i = 0, j = 0, k = 0;
    unsigned char *imageData;
    wxColour pixelColor;
    int imageWidth = 0;
    int imageHeight = 0;

    wxClientDC dc(this);
    DoPrepareDC(dc);

    // Get the width and height of the drawing canvas
    imageWidth = GetSize().GetWidth();
    imageHeight = GetSize().GetHeight();

    // Allocate memory for the image data
    imageData = new unsigned char[imageWidth*imageHeight];

    // Go through the pixels of the drawing canvas and put the data into the image buffer
    for (j=0; j<imageHeight; j++)
    {
        for (i=0; i<imageWidth; i++)
        {
            dc.GetPixel(i, j, &pixelColor);

            // Use 1 for colored, 0 for non-colored
            if (pixelColor.Red() == 255 && pixelColor.Green() == 255 && pixelColor.Blue() == 255)
                imageData[k] = 0;
            else
                imageData[k] = 1;

            k++;
        }
    }

    // Crop the image
    imageData = CropImage(imageData, imageWidth, imageHeight);

    // Append the recognized character to the main text box
    ((MainFrame*)wxGetTopLevelParent(this))->m_textMain->AppendText(
            wxString::Format("%c", wxGetApp().GetNeuralNetwork()->RecognizeCharacter(
                    imageData,
                    imageWidth,
                    imageHeight)));

    // Clear the drawing canvas
    Refresh();
}

int DrawCanvas::GetX()
{
    return lastX;
}

int DrawCanvas::GetY()
{
    return lastY;
}

void DrawCanvas::SetX(int x)
{
    lastX = x;
}

void DrawCanvas::SetY(int y)
{
    lastY = y;
}

// TODO need to just modify image data pointer instead of returning new pointer
unsigned char *DrawCanvas::CropImage(unsigned char *imageData, int &width, int &height)
{
    int i = 0, j = 0, k = 0;
    int startX = 0;
    int startY = 0;
    int endX = 0;
    int endY = 0;
    unsigned char *croppedImageData;

    // Find the first x column containing a colored pixel
    for (i=0; i<width; i++)
    {
        for (j=0; j<height; j++)
        {
            if (imageData == <span class="cpp-number">1</span>)
            {
                startX = i;

                <span class="cpp-comment">// Set i = width in order to break out of the outer loop as well</span>
                i = width;
                <span class="cpp-keyword">break</span>;
            }
        }
    }

    <span class="cpp-comment">// Find the last x column containing a colored pixel</span>
    <span class="cpp-keyword">for</span> (i=width-<span class="cpp-number">1</span>; i&gt;=<span class="cpp-number">0</span>; i–)
    {
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;height; j++)
        {
            <span class="cpp-keyword">if</span> (imageData == <span class="cpp-number">1</span>)
            {
                endX = i;

                <span class="cpp-comment">// Set i = width in order to break out of the outer loop as well</span>
                i = <span class="cpp-number">0</span>;
                <span class="cpp-keyword">break</span>;
            }
        }
    }

    <span class="cpp-comment">// Find the first y row containing a colored pixel</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;height; i++)
    {
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;width; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
            {
                startY = i;

                <span class="cpp-comment">// Set i = height in order to break out of the outer loop as well</span>
                i = height;
                <span class="cpp-keyword">break</span>;
            }
        }
    }

    <span class="cpp-comment">// Find the last y row containing a colored pixel</span>
    <span class="cpp-keyword">for</span> (i=height-<span class="cpp-number">1</span>; i&gt;=<span class="cpp-number">0</span>; i–)
    {
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;width; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
            {
                endY = i;

                <span class="cpp-comment">// Set i = height in order to break out of the outer loop as well</span>
                i = <span class="cpp-number">0</span>;
                <span class="cpp-keyword">break</span>;
            }
        }
    }

    croppedImageData = <span class="cpp-keyword">new</span> <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span>[((endX+<span class="cpp-number">1</span>)-startX) * ((endY+<span class="cpp-number">1</span>)-startY)];

    <span class="cpp-comment">// Copy the data from the original image data array to the new one using the</span>
    <span class="cpp-comment">// cropped beginning and end columns and rows</span>
    <span class="cpp-keyword">for</span> (j=startY; j&lt;endY+<span class="cpp-number">1</span>; j++)
    {
        <span class="cpp-keyword">for</span> (i=startX; i&lt;endX+<span class="cpp-number">1</span>; i++)
            croppedImageData[k++] = imageData;
    }

    width = (endX+<span class="cpp-number">1</span>) - startX;
    height = (endY+<span class="cpp-number">1</span>) - startY;

    <span class="cpp-keyword">delete</span> [] imageData;

    <span class="cpp-keyword">return</span> croppedImageData;
}

<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// TrainingDialog class functions</span>
<span class="cpp-comment">/*****************************************************************************/</span>
TrainingDialog::TrainingDialog(wxWindow *parent) : wxDialog(parent, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">"Train From Image(s)"</span>), wxDefaultPosition, wxSize(<span class="cpp-number">350</span>, <span class="cpp-number">350</span>))
{
    m_trainingGroupBox = <span class="cpp-keyword">new</span> wxStaticBox(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">"Training Data"</span>));
    m_fileList = <span class="cpp-keyword">new</span> wxListBox(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>);
    m_buttonTest = <span class="cpp-keyword">new</span> wxButton(<span class="cpp-keyword">this</span>, BUTTON_TEST, _T(<span class="cpp-literal">"&amp;Test"</span>));
    m_buttonAdd = <span class="cpp-keyword">new</span> wxButton(<span class="cpp-keyword">this</span>, BUTTON_ADD, _T(<span class="cpp-literal">"&amp;Add File(s)…"</span>));
    m_buttonRemove = <span class="cpp-keyword">new</span> wxButton(<span class="cpp-keyword">this</span>, BUTTON_REMOVE, _T(<span class="cpp-literal">"Remove"</span>));
    m_textTrainingCount = <span class="cpp-keyword">new</span> wxTextCtrl(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">"1000"</span>), wxDefaultPosition, wxSize(<span class="cpp-number">50</span>, -<span class="cpp-number">1</span>));
    m_textOutput = <span class="cpp-keyword">new</span> wxTextCtrl(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">""</span>), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
    m_startButton = <span class="cpp-keyword">new</span> wxButton(<span class="cpp-keyword">this</span>, BUTTON_START, _T(<span class="cpp-literal">"Start"</span>));
    m_closeButton = <span class="cpp-keyword">new</span> wxButton(<span class="cpp-keyword">this</span>, BUTTON_CLOSE, _T(<span class="cpp-literal">"Close"</span>));

    m_startButton-&gt;SetDefault();

    <span class="cpp-comment">// Create the sizers for the dialog - what a mess!</span>
    wxStaticBoxSizer *mainSizerSub1 = <span class="cpp-keyword">new</span> wxStaticBoxSizer(m_trainingGroupBox, wxVERTICAL);
    wxBoxSizer *mainSizerSub1Sub1 = <span class="cpp-keyword">new</span> wxBoxSizer(wxVERTICAL);

    wxBoxSizer *mainSizerSub1Sub1Sub2 = <span class="cpp-keyword">new</span> wxBoxSizer(wxHORIZONTAL);
    mainSizerSub1Sub1Sub2-&gt;Add(<span class="cpp-keyword">new</span> wxStaticText(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">"Training Sessions:"</span>)), <span class="cpp-number">0</span>, wxALIGN_CENTER_VERTICAL|wxRIGHT, <span class="cpp-number">3</span>);
    mainSizerSub1Sub1Sub2-&gt;Add(m_textTrainingCount);

    mainSizerSub1Sub1-&gt;Add(mainSizerSub1Sub1Sub2, <span class="cpp-number">0</span>, wxBOTTOM, <span class="cpp-number">3</span>);
    mainSizerSub1Sub1-&gt;Add(<span class="cpp-keyword">new</span> wxStaticText(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">"Image File(s):"</span>)), <span class="cpp-number">0</span>, wxEXPAND|wxBOTTOM, <span class="cpp-number">3</span>);
    mainSizerSub1Sub1-&gt;Add(m_fileList, <span class="cpp-number">0</span>, wxEXPAND);

    wxBoxSizer *mainSizerSub1Sub1Sub1 = <span class="cpp-keyword">new</span> wxBoxSizer(wxHORIZONTAL);
    mainSizerSub1Sub1Sub1-&gt;Add(m_buttonTest);
    mainSizerSub1Sub1Sub1-&gt;Add(m_buttonAdd);
    mainSizerSub1Sub1Sub1-&gt;Add(m_buttonRemove);

    mainSizerSub1Sub1-&gt;Add(mainSizerSub1Sub1Sub1, <span class="cpp-number">0</span>, wxALIGN_RIGHT);
    mainSizerSub1-&gt;Add(mainSizerSub1Sub1, <span class="cpp-number">0</span>, wxEXPAND|wxALL, <span class="cpp-number">3</span>);

    wxBoxSizer *mainSizer = <span class="cpp-keyword">new</span> wxBoxSizer(wxVERTICAL);
    mainSizer-&gt;Add(mainSizerSub1, <span class="cpp-number">0</span>, wxALL|wxEXPAND, <span class="cpp-number">6</span>);
    mainSizer-&gt;Add(<span class="cpp-keyword">new</span> wxStaticText(<span class="cpp-keyword">this</span>, -<span class="cpp-number">1</span>, _T(<span class="cpp-literal">"Output:"</span>)), <span class="cpp-number">0</span>, wxLEFT|wxRIGHT|wxTOP, <span class="cpp-number">6</span>);
    <span class="cpp-comment">// TODO add a spacer here</span>
    mainSizer-&gt;Add(m_textOutput, <span class="cpp-number">0</span>, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, <span class="cpp-number">6</span>);

    wxBoxSizer *mainSizerSub2 = <span class="cpp-keyword">new</span> wxBoxSizer(wxHORIZONTAL);
    mainSizerSub2-&gt;Add(m_startButton);
    mainSizerSub2-&gt;Add(m_closeButton);
    mainSizer-&gt;Add(mainSizerSub2, <span class="cpp-number">0</span>, wxALL|wxALIGN_RIGHT, <span class="cpp-number">6</span>);

    mainSizer-&gt;SetMinSize(<span class="cpp-number">375</span>, -<span class="cpp-number">1</span>);

    SetSizerAndFit(mainSizer);
    SetAutoLayout(<span class="cpp-keyword">true</span>);
    Layout();

    InitDialog();
}

<span class="cpp-keyword">void</span> TrainingDialog::OnInitDialog(wxInitDialogEvent &amp;event)
{
}

<span class="cpp-keyword">void</span> TrainingDialog::OnClose(wxCloseEvent &amp;event)
{
    Destroy();
}

<span class="cpp-keyword">void</span> TrainingDialog::OnStartButton(wxCommandEvent &amp;event)
{
    <span class="cpp-keyword">long</span> trainingCount = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">char</span> curChar = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Go through the file list if it's not empty and perform training for each image</span>
    <span class="cpp-comment">// the number of times the user has specified</span>
    <span class="cpp-keyword">if</span> (m_fileList-&gt;GetCount() &gt; <span class="cpp-number">0</span>)
    {
        <span class="cpp-comment">// If the training count field is blank, default to 1000 training sessions</span>
        <span class="cpp-keyword">if</span> (m_textTrainingCount-&gt;GetValue().Length() &gt; <span class="cpp-number">0</span>)
            m_textTrainingCount-&gt;GetValue().ToLong(&amp;trainingCount);
        <span class="cpp-keyword">else</span>
        {
            m_textTrainingCount-&gt;SetValue(<span class="cpp-literal">"1000"</span>);
            trainingCount = <span class="cpp-number">1000</span>;
        }

        <span class="cpp-comment">// Go through the list and perform the specified number of training sessions</span>
        <span class="cpp-comment">// for each image</span>
        <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;m_fileList-&gt;GetCount()*trainingCount; i++)
        {
            wxGetApp().GetNeuralNetwork()-&gt;TrainFromImage(m_fileList-&gt;GetString(j),
                                                          GetFileFirstCharacter(m_fileList-&gt;GetString(j)));

            j++;

            <span class="cpp-keyword">if</span> (j % m_fileList-&gt;GetCount() == <span class="cpp-number">0</span>)
                j = <span class="cpp-number">0</span>;
        }
    }
}

<span class="cpp-keyword">void</span> TrainingDialog::OnCloseButton(wxCommandEvent &amp;event)
{
    Destroy();
}

<span class="cpp-keyword">void</span> TrainingDialog::OnTestButton(wxCommandEvent &amp;event)
{
    m_textOutput-&gt;AppendText(wxGetApp().GetNeuralNetwork()-&gt;ShowOutput(m_fileList-&gt;GetString(m_fileList-&gt;GetSelection()),
                                                                       GetFileFirstCharacter(m_fileList-&gt;GetString(m_fileList-&gt;GetSelection()))));
}

<span class="cpp-keyword">void</span> TrainingDialog::OnAddButton(wxCommandEvent &amp;event)
{
    wxFileDialog *dlg = <span class="cpp-keyword">new</span> wxFileDialog(<span class="cpp-keyword">this</span>, _T(<span class="cpp-literal">"Select File(s)"</span>), <span class="cpp-literal">""</span>, <span class="cpp-literal">""</span>, <span class="cpp-literal">"*.bmp"</span>, wxOPEN|wxMULTIPLE);
    wxArrayString filenames;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-keyword">if</span> (dlg-&gt;ShowModal() == wxID_OK)
    {
        dlg-&gt;GetPaths(filenames);

        <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;filenames.Count(); i++)
        {
            <span class="cpp-comment">// Add the file to the file list if it's not already in the list</span>
            <span class="cpp-keyword">if</span> (m_fileList-&gt;FindString(filenames<span style="font-weight:bold;">) == wxNOT_FOUND)
                m_fileList-&gt;Append(filenames<span style="font-weight:bold;">);
        }
    }
}

<span class="cpp-keyword">void</span> TrainingDialog::OnRemoveButton(wxCommandEvent &amp;event)
{
    <span class="cpp-keyword">if</span> (m_fileList-&gt;GetCount() &gt; <span class="cpp-number">1</span> &amp;&amp; m_fileList-&gt;GetSelection() != wxNOT_FOUND)
        m_fileList-&gt;<span class="cpp-keyword">Delete</span>(m_fileList-&gt;GetSelection());
}

<span class="cpp-keyword">char</span> TrainingDialog::GetFileFirstCharacter(wxString filename)
{
    wxFileName temp(filename);

    <span class="cpp-keyword">return</span> temp.GetName().GetChar(<span class="cpp-number">0</span>);
}



</pre></div><!–ENDSCRIPT–>

<!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><span class="cpp-comment">// neuralnetwork.h</span>

<span class="cpp-directive">#ifndef</span> NEURALNETWORK
<span class="cpp-directive">#define</span> NEURALNETWORK

<span class="cpp-directive">#include</span> &lt;iostream&gt;
<span class="cpp-directive">#include</span> &lt;vector&gt;
<span class="cpp-directive">#include</span> &lt;cmath&gt;
<span class="cpp-directive">#include</span> &lt;ctime&gt;
<span class="cpp-directive">#include</span> &lt;stdlib.h&gt;

<span class="cpp-keyword">using</span> <span class="cpp-keyword">namespace</span> std;

<span class="cpp-comment">// Constants</span>
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> GRIDLINES_COUNT_X = <span class="cpp-number">6</span>;
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> GRIDLINES_COUNT_Y = <span class="cpp-number">10</span>;
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> DISTANCES_COUNT_X = GRIDLINES_COUNT_X * <span class="cpp-number">2</span>;
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> DISTANCES_COUNT_Y = GRIDLINES_COUNT_Y * <span class="cpp-number">2</span>;
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> INPUT_NEURON_COUNT = DISTANCES_COUNT_X + DISTANCES_COUNT_Y + <span class="cpp-number">7</span>;
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> HIDDEN_NEURON_COUNT = <span class="cpp-number">30</span>;
<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> OUTPUT_NEURON_COUNT = <span class="cpp-number">26</span>;

<span class="cpp-comment">// Class prototypes</span>
<span class="cpp-keyword">class</span> NeuralNetwork;
<span class="cpp-keyword">class</span> NeuronLayer;
<span class="cpp-keyword">class</span> Neuron;

<span class="cpp-comment">// function prototypes</span>
<span class="cpp-keyword">double</span> RandomDouble(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> min, <span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> max);

<span class="cpp-keyword">class</span> NeuralNetwork
{
 <span class="cpp-keyword">private</span>:
    vector&lt;NeuronLayer*&gt; m_layers;
    <span class="cpp-keyword">double</span> m_outerLearningRate;
    <span class="cpp-keyword">double</span> m_innerLearningRate;

 <span class="cpp-keyword">public</span>:
    NeuralNetwork();
    <span class="cpp-keyword">void</span> AddLayer(<span class="cpp-keyword">int</span> neurons);
    <span class="cpp-keyword">void</span> AddNeuron(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> layer);
    <span class="cpp-keyword">int</span> GetLayerCount() <span class="cpp-keyword">const</span>;
    <span class="cpp-keyword">void</span> SetLearningRates(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> inner, <span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> outer);
    <span class="cpp-keyword">double</span> GetInputValue(<span class="cpp-keyword">int</span> neuron);
    <span class="cpp-keyword">void</span> SetInputValue(<span class="cpp-keyword">int</span> neuron, <span class="cpp-keyword">double</span> input);
    <span class="cpp-keyword">void</span> SetInputVector(vector&lt;<span class="cpp-keyword">double</span>&gt; inputVector);
    vector&lt;<span class="cpp-keyword">double</span>&gt; GetInputVector();
    <span class="cpp-keyword">double</span> GetTargetValue(<span class="cpp-keyword">int</span> neuron);
    vector&lt;<span class="cpp-keyword">double</span>&gt; GetTargetVector();
    <span class="cpp-keyword">void</span> SetTargetValue(<span class="cpp-keyword">int</span> neuron, <span class="cpp-keyword">double</span> target);
    <span class="cpp-keyword">void</span> SetTargetVector(vector&lt;<span class="cpp-keyword">double</span>&gt; targetVector);
    <span class="cpp-keyword">double</span> GetOutputValue(<span class="cpp-keyword">int</span> neuron);
    vector&lt;<span class="cpp-keyword">double</span>&gt; GetOutputVector();
    <span class="cpp-keyword">double</span> GetNeuronOutput(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> layer, <span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron) <span class="cpp-keyword">const</span>;
    <span class="cpp-keyword">void</span> Propagate();
    <span class="cpp-keyword">void</span> BackPropagate();
    <span class="cpp-keyword">double</span> TransferFunction(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> value) <span class="cpp-keyword">const</span>;
    <span class="cpp-keyword">void</span> TrainFromImage(wxString filename, <span class="cpp-keyword">char</span> charIndex);
    wxString ShowOutput(wxString filename, <span class="cpp-keyword">char</span> targetChar);
    <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *SimplifyImageData(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height);
    <span class="cpp-keyword">int</span> *GetXDistances(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceX, <span class="cpp-keyword">int</span> gridStartX);
    <span class="cpp-keyword">int</span> *GetYDistances(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceY, <span class="cpp-keyword">int</span> gridStartY);
    <span class="cpp-keyword">int</span> GetXIntersections(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceX, <span class="cpp-keyword">int</span> gridStartX);
    <span class="cpp-keyword">int</span> GetYIntersections(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceY, <span class="cpp-keyword">int</span> gridStartY);
    <span class="cpp-keyword">int</span> GetColoredPixelCountTopLeft(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height);
    <span class="cpp-keyword">int</span> GetColoredPixelCountTopRight(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height);
    <span class="cpp-keyword">int</span> GetColoredPixelCountBottomRight(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height);
    <span class="cpp-keyword">int</span> GetColoredPixelCountBottomLeft(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height);
    <span class="cpp-keyword">char</span> RecognizeCharacter(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height);
};

<span class="cpp-keyword">class</span> NeuronLayer
{
 <span class="cpp-keyword">private</span>:
    vector&lt;Neuron*&gt; m_neurons;

 <span class="cpp-keyword">public</span>:
    NeuronLayer();
    <span class="cpp-keyword">void</span> AddNeuron();
    Neuron *GetNeuron(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron);
    <span class="cpp-keyword">int</span> GetNeuronCount();
};

<span class="cpp-comment">// Holds weight values between neuron layers</span>
<span class="cpp-keyword">class</span> Neuron
{
 <span class="cpp-keyword">private</span>:
    <span class="cpp-keyword">double</span> m_value;
    <span class="cpp-keyword">double</span> m_deltaValue;
    <span class="cpp-keyword">double</span> m_targetValue;
    vector&lt;<span class="cpp-keyword">double</span>&gt; m_connections;

 <span class="cpp-keyword">public</span>:
    Neuron();
    <span class="cpp-keyword">double</span> GetValue();
    <span class="cpp-keyword">void</span> SetValue(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> value);
    <span class="cpp-keyword">double</span> GetDeltaValue();
    <span class="cpp-keyword">void</span> SetDeltaValue(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> value);
    <span class="cpp-keyword">double</span> GetTargetValue();
    <span class="cpp-keyword">void</span> SetTargetValue(<span class="cpp-keyword">double</span> targetValue);
    <span class="cpp-keyword">void</span> AddConnection(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> weight);
    <span class="cpp-keyword">double</span> GetConnectionWeight(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron);
    <span class="cpp-keyword">void</span> SetConnectionWeight(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron, <span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> weight);
};

<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// Generic functions</span>
<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// Generates a random number given a minimum and maximum</span>
<span class="cpp-keyword">double</span> RandomDouble(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> min, <span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> max)
{
    <span class="cpp-keyword">static</span> <span class="cpp-keyword">int</span> init = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Only seed the generator if it has not already been seeded</span>
    <span class="cpp-keyword">if</span> (init == <span class="cpp-number">0</span>)
    {
        srand((<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">int</span>)time(NULL));
        init = <span class="cpp-number">1</span>;
    }

    <span class="cpp-keyword">return</span> (max - min) * (<span class="cpp-keyword">double</span>)rand() / (<span class="cpp-keyword">double</span>)RAND_MAX + min;
}

<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// NeuralNetwork class functions</span>
<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// Constructor</span>
NeuralNetwork::NeuralNetwork()
{
    <span class="cpp-comment">// Give the network a default learning rate</span>
    SetLearningRates(<span class="cpp-number">0</span>.<span class="cpp-number">2</span>, <span class="cpp-number">0</span>.<span class="cpp-number">15</span>);
}

<span class="cpp-comment">// Adds a layer to the network by adding another element to the layer vector</span>
<span class="cpp-keyword">void</span> NeuralNetwork::AddLayer(<span class="cpp-keyword">int</span> neurons = <span class="cpp-number">0</span>)
{
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    m_layers.push_back(<span class="cpp-keyword">new</span> NeuronLayer());

    <span class="cpp-comment">// Add the the number of neurons specified in the constructor to this layer</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;neurons; i++)
        AddNeuron(GetLayerCount()-<span class="cpp-number">1</span>);
}

<span class="cpp-comment">// Adds a neuron to a given layer</span>
<span class="cpp-keyword">void</span> NeuralNetwork::AddNeuron(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> layer)
{
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Add a neuron to this layer</span>
    m_layers[layer]-&gt;AddNeuron();

    <span class="cpp-comment">// Add connections from all neurons in the previous layer to the this</span>
    <span class="cpp-comment">// neuron if this is not the first layer</span>
    <span class="cpp-keyword">if</span> (layer &gt; <span class="cpp-number">0</span>)
    {
        <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;m_layers[layer-<span class="cpp-number">1</span>]-&gt;GetNeuronCount(); i++)
            m_layers[layer-<span class="cpp-number">1</span>]-&gt;GetNeuron(i)-&gt;AddConnection(RandomDouble(-<span class="cpp-number">0</span>.<span class="cpp-number">01</span>, <span class="cpp-number">0</span>.<span class="cpp-number">01</span>));
    }
}

<span class="cpp-keyword">int</span> NeuralNetwork::GetLayerCount() <span class="cpp-keyword">const</span>
{
    <span class="cpp-keyword">return</span> m_layers.size();
}

<span class="cpp-comment">// Sets the learning rate for the neural network</span>
<span class="cpp-keyword">void</span> NeuralNetwork::SetLearningRates(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> inner, <span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> outer)
{
    m_outerLearningRate = inner;
    m_innerLearningRate = outer;
}

<span class="cpp-comment">// Returns the input value for a given input neuron</span>
<span class="cpp-keyword">double</span> NeuralNetwork::GetInputValue(<span class="cpp-keyword">int</span> neuron)
{
    <span class="cpp-keyword">return</span> m_layers[<span class="cpp-number">0</span>]-&gt;GetNeuron(neuron)-&gt;GetValue();
}

<span class="cpp-comment">// Sets the input value for a given input neuron</span>
<span class="cpp-keyword">void</span> NeuralNetwork::SetInputValue(<span class="cpp-keyword">int</span> neuron, <span class="cpp-keyword">double</span> input)
{
    m_layers[<span class="cpp-number">0</span>]-&gt;GetNeuron(neuron)-&gt;SetValue(input);
}

<span class="cpp-comment">// Sets the values for the input neurons</span>
<span class="cpp-keyword">void</span> NeuralNetwork::SetInputVector(vector&lt;<span class="cpp-keyword">double</span>&gt; inputVector)
{
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;inputVector.size(); i++)
        m_layers[<span class="cpp-number">0</span>]-&gt;GetNeuron(i)-&gt;SetValue(inputVector<span style="font-weight:bold;">);
}

<span class="cpp-comment">// Returns the input vector to the network</span>
vector&lt;<span class="cpp-keyword">double</span>&gt; NeuralNetwork::GetInputVector()
{
    vector&lt;<span class="cpp-keyword">double</span>&gt; temp;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;m_layers[<span class="cpp-number">0</span>]-&gt;GetNeuronCount(); i++)
        temp.push_back(m_layers[<span class="cpp-number">0</span>]-&gt;GetNeuron(i)-&gt;GetValue());

    <span class="cpp-keyword">return</span> temp;
}

<span class="cpp-comment">// Returns the target value for a given output neuron</span>
<span class="cpp-keyword">double</span> NeuralNetwork::GetTargetValue(<span class="cpp-keyword">int</span> neuron)
{
    <span class="cpp-keyword">return</span> m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuron(neuron)-&gt;GetTargetValue();
}

<span class="cpp-comment">// Sets the target value for a given output neuron</span>
<span class="cpp-keyword">void</span> NeuralNetwork::SetTargetValue(<span class="cpp-keyword">int</span> neuron, <span class="cpp-keyword">double</span> target)
{
    m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuron(neuron)-&gt;SetTargetValue(target);
}

<span class="cpp-comment">// Sets the target vector for the neural network. Used in backpropagation</span>
<span class="cpp-keyword">void</span> NeuralNetwork::SetTargetVector(vector&lt;<span class="cpp-keyword">double</span>&gt; targetVector)
{
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;targetVector.size(); i++)
        m_layers<span style="font-weight:bold;">-&gt;GetNeuron(i)-&gt;SetTargetValue(targetVector<span style="font-weight:bold;">);
}

<span class="cpp-comment">// Returns the target output value for the network</span>
vector&lt;<span class="cpp-keyword">double</span>&gt; NeuralNetwork::GetTargetVector()
{
    vector&lt;<span class="cpp-keyword">double</span>&gt; temp;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuronCount(); i++)
        temp.push_back(m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuron(i)-&gt;GetTargetValue());

    <span class="cpp-keyword">return</span> temp;
}

<span class="cpp-comment">// Returns the output value for a given output neuron</span>
<span class="cpp-keyword">double</span> NeuralNetwork::GetOutputValue(<span class="cpp-keyword">int</span> neuron)
{
    <span class="cpp-keyword">return</span> m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuron(neuron)-&gt;GetValue();
}

<span class="cpp-comment">// Returns a vector containing the values of the neurons in the output layer</span>
vector&lt;<span class="cpp-keyword">double</span>&gt; NeuralNetwork::GetOutputVector()
{
    vector&lt;<span class="cpp-keyword">double</span>&gt; temp;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuronCount(); i++)
        temp.push_back(m_layers[GetLayerCount()-<span class="cpp-number">1</span>]-&gt;GetNeuron(i)-&gt;GetValue());

    <span class="cpp-keyword">return</span> temp;
}

<span class="cpp-comment">// Returns the summation of the products of the input value and the weights for</span>
<span class="cpp-comment">// a given neuron</span>
<span class="cpp-keyword">double</span> NeuralNetwork::GetNeuronOutput(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> layer, <span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron) <span class="cpp-keyword">const</span>
{
    <span class="cpp-keyword">return</span> m_layers[layer]-&gt;GetNeuron(neuron)-&gt;GetValue();
}

<span class="cpp-comment">// Feeds the input values through the network and calculates the output value</span>
<span class="cpp-comment">// for the network</span>
<span class="cpp-keyword">void</span> NeuralNetwork::Propagate()
{
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> j = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> k = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> weight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> input = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> newValue = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Loop through the layers starting at the second layer (first hidden layer)</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">1</span>; i&lt;GetLayerCount(); i++)
    {
        <span class="cpp-comment">// Loop through the neurons in the current layer</span>
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;m_layers<span style="font-weight:bold;">-&gt;GetNeuronCount(); j++)
        {
            newValue = <span class="cpp-number">0</span>;

            <span class="cpp-comment">// Loop through the neurons from the previous layer (which connect</span>
            <span class="cpp-comment">// to the neurons in the current layer</span>
            <span class="cpp-keyword">for</span> (k=<span class="cpp-number">0</span>; k&lt;m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuronCount(); k++)
            {
                <span class="cpp-comment">// get the connection weight from the current neuron in the</span>
                <span class="cpp-comment">// previous layer to the current neuron in the current layer</span>
                weight = m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuron(k)-&gt;GetConnectionWeight(j);

                <span class="cpp-comment">// get the value for the current neuron in the previous layer</span>
                input = m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuron(k)-&gt;GetValue();

                <span class="cpp-comment">// add the product of the weight and the input to the summation</span>
                newValue += weight * input;
            }

            <span class="cpp-comment">// Run the new value through the transfer function</span>
            newValue = TransferFunction(newValue);

            <span class="cpp-comment">// set the value for the current neuron to the sum of the weights</span>
            <span class="cpp-comment">// and inputs coming into that neuron</span>
            m_layers<span style="font-weight:bold;">-&gt;GetNeuron(j)-&gt;SetValue(newValue);
        }
    }
}

<span class="cpp-comment">// Adjusts the weights for the connections to improve the network's accuracy</span>
<span class="cpp-keyword">void</span> NeuralNetwork::BackPropagate()
{
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> j = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> k = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> l = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> delta = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> deltaTemp = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> previousNeuronOutput = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> currentNeuronOutput = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> currentConnectionWeight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">double</span> changeInConnectionWeight = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Loop through the layers starting at the output layer and ending at the</span>
    <span class="cpp-comment">// first hidden layer</span>
    <span class="cpp-keyword">for</span> (i=GetLayerCount()-<span class="cpp-number">1</span>; i&gt;=<span class="cpp-number">1</span>; i–)
    {
        <span class="cpp-comment">// Loop through the neurons in the current layer</span>
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;m_layers<span style="font-weight:bold;">-&gt;GetNeuronCount(); j++)
        {
            currentNeuronOutput = m_layers<span style="font-weight:bold;">-&gt;GetNeuron(j)-&gt;GetValue();

            <span class="cpp-comment">// Loop through the neurons from the previous layer (which connect</span>
            <span class="cpp-comment">// to the neurons in the current layer</span>
            <span class="cpp-keyword">for</span> (k=<span class="cpp-number">0</span>; k&lt;m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuronCount(); k++)
            {
                previousNeuronOutput = m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuron(k)-&gt;GetValue();

                <span class="cpp-comment">// Test whether the loop is at the output connection layer. If it's</span>
                <span class="cpp-comment">// not at the output layer it's at a hidden layer</span>
                <span class="cpp-keyword">if</span> (i == GetLayerCount()-<span class="cpp-number">1</span>)
                {
                    delta = currentNeuronOutput * (<span class="cpp-number">1</span> - currentNeuronOutput) * (m_layers<span style="font-weight:bold;">-&gt;GetNeuron(j)-&gt;GetTargetValue() - currentNeuronOutput);

                    <span class="cpp-comment">// calculate change in weight for output connection layer</span>
                    changeInConnectionWeight = m_outerLearningRate * delta * previousNeuronOutput;
                }
                <span class="cpp-keyword">else</span>
                {
                    deltaTemp = <span class="cpp-number">0</span>;

                    <span class="cpp-comment">// Get the delta values for all neurons in the next layer</span>
                    <span class="cpp-keyword">for</span> (l=<span class="cpp-number">0</span>; l&lt;m_layers[i+<span class="cpp-number">1</span>]-&gt;GetNeuronCount(); l++)
                        deltaTemp += m_layers[i+<span class="cpp-number">1</span>]-&gt;GetNeuron(l)-&gt;GetDeltaValue();

                    delta = currentNeuronOutput * (<span class="cpp-number">1</span> - currentNeuronOutput) * deltaTemp;

                    <span class="cpp-comment">// calculate change in weight for hidden connection layer</span>
                    changeInConnectionWeight = m_innerLearningRate * delta * previousNeuronOutput;
                }

                <span class="cpp-comment">// Get the weight of the connection from the current neuron in</span>
                <span class="cpp-comment">// the previous layer to the current neuron in the current layer</span>
                currentConnectionWeight = m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuron(k)-&gt;GetConnectionWeight(j);

                <span class="cpp-comment">// Add the change in weight to the current neuron's weight</span>
                m_layers[i-<span class="cpp-number">1</span>]-&gt;GetNeuron(k)-&gt;SetConnectionWeight(j, currentConnectionWeight + changeInConnectionWeight);
            }
        }
    }
}

<span class="cpp-comment">// Transfer (activation) function using the Sigmoid function</span>
<span class="cpp-keyword">double</span> NeuralNetwork::TransferFunction(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> value) <span class="cpp-keyword">const</span>
{
    <span class="cpp-keyword">return</span> <span class="cpp-number">1</span> / (<span class="cpp-number">1</span> + exp(-<span class="cpp-number">1</span> * value));
}

<span class="cpp-keyword">void</span> NeuralNetwork::TrainFromImage(wxString filename, <span class="cpp-keyword">char</span> targetChar)
{
    wxImage *image = <span class="cpp-keyword">new</span> wxImage();
    <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData;
    <span class="cpp-keyword">int</span> *distances_x;
    <span class="cpp-keyword">int</span> *distances_y;
    <span class="cpp-keyword">int</span> intersections_x = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> intersections_y = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountTopLeft = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountTopRight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountBottomLeft = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountBottomRight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> totalColoredPixelCount = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> imageWidth = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> imageHeight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridSpaceX = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridSpaceY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridStartX = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridStartY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> neuronIndex = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// TODO Make sure image only has two colors</span>

    <span class="cpp-comment">// Load the image file into memory</span>
    image-&gt;LoadFile(filename);

    imageWidth = image-&gt;GetWidth();
    imageHeight = image-&gt;GetHeight();

    <span class="cpp-comment">// Get the image's pixel data</span>
    imageData = SimplifyImageData(image-&gt;GetData(), imageWidth, imageHeight);

    gridSpaceX = floor((<span class="cpp-keyword">float</span>)imageWidth / GRIDLINES_COUNT_X);
    gridSpaceY = floor((<span class="cpp-keyword">float</span>)imageHeight / GRIDLINES_COUNT_Y);
    gridStartX = gridSpaceX / <span class="cpp-number">2</span>;
    gridStartY = gridSpaceY / <span class="cpp-number">2</span>;

    <span class="cpp-comment">// Get the closest distances to the image at certain intervals in the x and y directions</span>
    distances_x = GetXDistances(imageData, imageWidth, imageHeight, gridSpaceX, gridStartX);
    distances_y = GetYDistances(imageData, imageWidth, imageHeight, gridSpaceY, gridStartY);

    <span class="cpp-comment">// Get counts of the intersections in the x and y directions</span>
    intersections_x = GetXIntersections(imageData, imageWidth, imageHeight, gridSpaceX, gridStartX);
    intersections_y = GetYIntersections(imageData, imageWidth, imageHeight, gridSpaceY, gridStartY);

    <span class="cpp-comment">// Get the Counts of pixels</span>
    coloredPixelCountTopLeft = GetColoredPixelCountTopLeft(imageData, imageWidth, imageHeight);
    coloredPixelCountTopRight = GetColoredPixelCountTopRight(imageData, imageWidth, imageHeight);
    coloredPixelCountBottomLeft = GetColoredPixelCountBottomLeft(imageData, imageWidth, imageHeight);
    coloredPixelCountBottomRight = GetColoredPixelCountBottomRight(imageData, imageWidth, imageHeight);

    totalColoredPixelCount = coloredPixelCountTopLeft + coloredPixelCountTopRight + coloredPixelCountBottomLeft + coloredPixelCountBottomRight;

    <span class="cpp-comment">// Set the target output values to the neural network according to the character specified</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;OUTPUT_NEURON_COUNT; i++)
    {
        <span class="cpp-comment">// TODO better method of accessing correct character</span>
        <span class="cpp-keyword">if</span> (i == targetChar-<span class="cpp-number">65</span>)
            SetTargetValue(i, <span class="cpp-number">1</span>);
        <span class="cpp-keyword">else</span>
            SetTargetValue(i, -<span class="cpp-number">1</span>);
    }

    neuronIndex = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Set input values to the neural network using the data just collected</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;DISTANCES_COUNT_X; i++)
        SetInputValue(neuronIndex++, distances_x<span style="font-weight:bold;">);

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;DISTANCES_COUNT_Y; i++)
        SetInputValue(neuronIndex++, distances_y<span style="font-weight:bold;">);

    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_x);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_y);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_x+intersections_y);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountTopLeft / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountTopRight / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountBottomLeft / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountBottomRight / totalColoredPixelCount);

    Propagate();
    BackPropagate();

    <span class="cpp-keyword">delete</span> image;
    <span class="cpp-keyword">delete</span> [] imageData;
    <span class="cpp-keyword">delete</span> [] distances_x;
    <span class="cpp-keyword">delete</span> [] distances_y;
}

wxString NeuralNetwork::ShowOutput(wxString filename, <span class="cpp-keyword">char</span> targetChar)
{
    wxImage *image = <span class="cpp-keyword">new</span> wxImage();
    <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData;
    <span class="cpp-keyword">int</span> *distances_x;
    <span class="cpp-keyword">int</span> *distances_y;
    <span class="cpp-keyword">int</span> intersections_x = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> intersections_y = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountTopLeft = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountTopRight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountBottomLeft = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountBottomRight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> totalColoredPixelCount = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> imageWidth = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> imageHeight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridSpaceX = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridSpaceY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridStartX = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridStartY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> neuronIndex = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;
    wxString outputString;

    <span class="cpp-comment">// TODO Make sure image only has two colors</span>

    <span class="cpp-comment">// Load the image file into memory</span>
    image-&gt;LoadFile(filename);

    imageWidth = image-&gt;GetWidth();
    imageHeight = image-&gt;GetHeight();

    <span class="cpp-comment">// Get the image's pixel data</span>
    imageData = SimplifyImageData(image-&gt;GetData(), imageWidth, imageHeight);

    gridSpaceX = floor((<span class="cpp-keyword">float</span>)imageWidth / GRIDLINES_COUNT_X);
    gridSpaceY = floor((<span class="cpp-keyword">float</span>)imageHeight / GRIDLINES_COUNT_Y);
    gridStartX = gridSpaceX / <span class="cpp-number">2</span>;
    gridStartY = gridSpaceY / <span class="cpp-number">2</span>;

    <span class="cpp-comment">// Get the closest distances to the image at certain intervals in the x and y directions</span>
    distances_x = GetXDistances(imageData, imageWidth, imageHeight, gridSpaceX, gridStartX);
    distances_y = GetYDistances(imageData, imageWidth, imageHeight, gridSpaceY, gridStartY);

    <span class="cpp-comment">// Get counts of the intersections in the x and y directions</span>
    intersections_x = GetXIntersections(imageData, imageWidth, imageHeight, gridSpaceX, gridStartX);
    intersections_y = GetYIntersections(imageData, imageWidth, imageHeight, gridSpaceY, gridStartY);

    <span class="cpp-comment">// Get the Counts of pixels</span>
    coloredPixelCountTopLeft = GetColoredPixelCountTopLeft(imageData, imageWidth, imageHeight);
    coloredPixelCountTopRight = GetColoredPixelCountTopRight(imageData, imageWidth, imageHeight);
    coloredPixelCountBottomLeft = GetColoredPixelCountBottomLeft(imageData, imageWidth, imageHeight);
    coloredPixelCountBottomRight = GetColoredPixelCountBottomRight(imageData, imageWidth, imageHeight);

    totalColoredPixelCount = coloredPixelCountTopLeft + coloredPixelCountTopRight + coloredPixelCountBottomLeft + coloredPixelCountBottomRight;

    <span class="cpp-comment">// Set the target output values to the neural network according to the character specified</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;OUTPUT_NEURON_COUNT; i++)
    {
        <span class="cpp-comment">// TODO better method of accessing correct character</span>
        <span class="cpp-keyword">if</span> (i == targetChar-<span class="cpp-number">65</span>)
            SetTargetValue(i, <span class="cpp-number">1</span>);
        <span class="cpp-keyword">else</span>
            SetTargetValue(i, -<span class="cpp-number">1</span>);
    }

    neuronIndex = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Set input values to the neural network using the data just collected</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;DISTANCES_COUNT_X; i++)
        SetInputValue(neuronIndex++, distances_x<span style="font-weight:bold;">);

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;DISTANCES_COUNT_Y; i++)
        SetInputValue(neuronIndex++, distances_y<span style="font-weight:bold;">);

    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_x);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_y);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_x+intersections_y);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountTopLeft / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountTopRight / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountBottomLeft / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountBottomRight / totalColoredPixelCount);

    Propagate();

    outputString = <span class="cpp-literal">"CHARACTER\tTARGET\tOUTPUT\n"</span>;

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;OUTPUT_NEURON_COUNT; i++)
        outputString &lt;&lt; wxString::Format(<span class="cpp-literal">"%c\t\t%f\t%f\n"</span>, i+<span class="cpp-number">65</span>, GetTargetValue(i), GetOutputValue(i));

    <span class="cpp-keyword">delete</span> image;
    <span class="cpp-keyword">delete</span> [] imageData;
    <span class="cpp-keyword">delete</span> [] distances_x;
    <span class="cpp-keyword">delete</span> [] distances_y;

    <span class="cpp-keyword">return</span> outputString;
}

<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *NeuralNetwork::SimplifyImageData(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height)
{
    <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *simplifiedData;
    <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> r = <span class="cpp-number">0</span>, g = <span class="cpp-number">0</span>, b = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    simplifiedData = <span class="cpp-keyword">new</span> <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span>[width*height];

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;width*height*<span class="cpp-number">3</span>; i+=<span class="cpp-number">3</span>)
    {
        r = imageData<span style="font-weight:bold;">;
        g = imageData[i+<span class="cpp-number">1</span>];
        b = imageData[i+<span class="cpp-number">2</span>];

        <span class="cpp-comment">// Use 1 for colored, 0 for non-colored</span>
        <span class="cpp-keyword">if</span> (r == <span class="cpp-number">255</span> &amp;&amp; g == <span class="cpp-number">255</span> &amp;&amp; b == <span class="cpp-number">255</span>)
            simplifiedData[j] = <span class="cpp-number">0</span>;
        <span class="cpp-keyword">else</span>
            simplifiedData[j] = <span class="cpp-number">1</span>;

        j++;
    }

    <span class="cpp-keyword">return</span> simplifiedData;
}

<span class="cpp-keyword">int</span> *NeuralNetwork::GetXDistances(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceX, <span class="cpp-keyword">int</span> gridStartX)
{
    <span class="cpp-keyword">int</span> *distances;
    <span class="cpp-keyword">bool</span> intersection_found = <span class="cpp-keyword">false</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>, k =<span class="cpp-number">0</span>;

    distances = <span class="cpp-keyword">new</span> <span class="cpp-keyword">int</span>[DISTANCES_COUNT_X];

    <span class="cpp-comment">// Go through the image data and measure the x distances</span>
    <span class="cpp-keyword">for</span> (i=gridStartX; i&lt;width-gridSpaceX; i+=gridSpaceX)
    {
        intersection_found = <span class="cpp-keyword">false</span>;

        <span class="cpp-comment">// Go down the current column and find the first intersection</span>
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;height; j++)
        {
            <span class="cpp-keyword">if</span> (imageData == <span class="cpp-number">1</span>)
            {
                distances[k] = j;
                intersection_found = <span class="cpp-keyword">true</span>;
                <span class="cpp-keyword">break</span>;
            }
        }

        <span class="cpp-comment">// If no intersection was found, set the distance to -1</span>
        <span class="cpp-keyword">if</span> (!intersection_found)
            distances[k] = -<span class="cpp-number">1</span>;

        k++;
        intersection_found = <span class="cpp-keyword">false</span>;

        <span class="cpp-comment">// Go up the current column and find the last intersection</span>
        <span class="cpp-keyword">for</span> (j=height-<span class="cpp-number">1</span>; j&gt;=<span class="cpp-number">0</span>; j–)
        {
            <span class="cpp-keyword">if</span> (imageData == <span class="cpp-number">1</span>)
            {
                distances[k] = j;
                intersection_found = <span class="cpp-keyword">true</span>;
                <span class="cpp-keyword">break</span>;
            }
        }

        <span class="cpp-comment">// If no intersection was found, set the distance to -1</span>
        <span class="cpp-keyword">if</span> (!intersection_found)
            distances[k] = -<span class="cpp-number">1</span>;

        k++;
    }

    <span class="cpp-keyword">return</span> distances;
}

<span class="cpp-keyword">int</span> *NeuralNetwork::GetYDistances(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceY, <span class="cpp-keyword">int</span> gridStartY)
{
    <span class="cpp-keyword">int</span> *distances;
    <span class="cpp-keyword">bool</span> intersection_found = <span class="cpp-keyword">false</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>, k = <span class="cpp-number">0</span>;

    distances = <span class="cpp-keyword">new</span> <span class="cpp-keyword">int</span>[DISTANCES_COUNT_Y];

    <span class="cpp-comment">// Go through the image data and measure the y distances</span>
    <span class="cpp-keyword">for</span> (i=gridStartY; i&lt;height-gridSpaceY; i+=gridSpaceY)
    {
        intersection_found = <span class="cpp-keyword">false</span>;

        <span class="cpp-comment">// Go down the current row and find the first intersection</span>
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;width; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
            {
                distances[k] = j;
                intersection_found = <span class="cpp-keyword">true</span>;
                <span class="cpp-keyword">break</span>;
            }
        }

        <span class="cpp-comment">// If no intersection was found, set the distance to -1</span>
        <span class="cpp-keyword">if</span> (!intersection_found)
            distances[k] = -<span class="cpp-number">1</span>;

        k++;
        intersection_found = <span class="cpp-keyword">false</span>;

        <span class="cpp-comment">// Go up the current row and find the last intersection</span>
        <span class="cpp-keyword">for</span> (j=width-<span class="cpp-number">1</span>; j&gt;=<span class="cpp-number">0</span>; j–)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
            {
                distances[k] = j;
                intersection_found = <span class="cpp-keyword">true</span>;
                <span class="cpp-keyword">break</span>;
            }
        }

        <span class="cpp-comment">// If no intersection was found, set the distance to -1</span>
        <span class="cpp-keyword">if</span> (!intersection_found)
            distances[k] = -<span class="cpp-number">1</span>;

        k++;
    }

    <span class="cpp-keyword">return</span> distances;
}

<span class="cpp-keyword">int</span> NeuralNetwork::GetXIntersections(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceX, <span class="cpp-keyword">int</span> gridStartX)
{
    <span class="cpp-keyword">int</span> intersections = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Go through the image data and find the x intersections</span>
    <span class="cpp-keyword">for</span> (i=gridStartX; i&lt;width; i+=gridSpaceX)
    {
        <span class="cpp-comment">// Go down the current row and find the first intersection</span>
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;height; j++)
        {
            <span class="cpp-comment">// Only count an intersection if the previous pixel was not also</span>
            <span class="cpp-comment">// colored or the current pixel is the first pixel</span>
            <span class="cpp-keyword">if</span> (imageData == <span class="cpp-number">1</span> &amp;&amp; (imageData != <span class="cpp-number">1</span> || (j == <span class="cpp-number">0</span> &amp;&amp; imageData == <span class="cpp-number">1</span>)))
                intersections++;
        }
    }

    <span class="cpp-keyword">return</span> intersections;
}

<span class="cpp-keyword">int</span> NeuralNetwork::GetYIntersections(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height, <span class="cpp-keyword">int</span> gridSpaceY, <span class="cpp-keyword">int</span> gridStartY)
{
    <span class="cpp-keyword">int</span> intersections = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Go through the image data and find the y intersections</span>
    <span class="cpp-keyword">for</span> (i=gridStartY; i&lt;height; i+=gridSpaceY)
    {
        <span class="cpp-comment">// Go down the current row and find the first intersection</span>
        <span class="cpp-keyword">for</span> (j=<span class="cpp-number">0</span>; j&lt;width; j++)
        {
            <span class="cpp-comment">// Only count an intersection if the previous pixel was not also</span>
            <span class="cpp-comment">// colored or the current pixel is the first pixel</span>
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span> &amp;&amp; (imageData[(j-<span class="cpp-number">1</span>) + (i * width)] != <span class="cpp-number">1</span> || (j == <span class="cpp-number">0</span> &amp;&amp; imageData[j + (i * width)] == <span class="cpp-number">1</span>)))
                intersections++;
        }
    }

    <span class="cpp-keyword">return</span> intersections;
}

<span class="cpp-keyword">int</span> NeuralNetwork::GetColoredPixelCountTopLeft(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height)
{
    <span class="cpp-keyword">int</span> coloredPixels = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> startX = <span class="cpp-number">0</span>, startY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> endX = <span class="cpp-number">0</span>, endY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    startX = <span class="cpp-number">0</span>;
    startY = <span class="cpp-number">0</span>;
    endX = floor((<span class="cpp-keyword">float</span>)width / <span class="cpp-number">2</span>);
    endY = floor((<span class="cpp-keyword">float</span>)height / <span class="cpp-number">2</span>);

    <span class="cpp-keyword">for</span> (i=startY; i&lt;endY; i++)
    {
        <span class="cpp-keyword">for</span> (j=startX; j&lt;endX; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
                coloredPixels++;
        }
    }

    <span class="cpp-keyword">return</span> coloredPixels;
}

<span class="cpp-keyword">int</span> NeuralNetwork::GetColoredPixelCountTopRight(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height)
{
    <span class="cpp-keyword">int</span> coloredPixels = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> startX = <span class="cpp-number">0</span>, startY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> endX = <span class="cpp-number">0</span>, endY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    startX = floor((<span class="cpp-keyword">float</span>)width / <span class="cpp-number">2</span>);
    startY = <span class="cpp-number">0</span>;
    endX = width;
    endY = floor((<span class="cpp-keyword">float</span>)height / <span class="cpp-number">2</span>);

    <span class="cpp-keyword">for</span> (i=startY; i&lt;endY; i++)
    {
        <span class="cpp-keyword">for</span> (j=startX; j&lt;endX; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
                coloredPixels++;
        }
    }

    <span class="cpp-keyword">return</span> coloredPixels;
}

<span class="cpp-keyword">int</span> NeuralNetwork::GetColoredPixelCountBottomLeft(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height)
{
    <span class="cpp-keyword">int</span> coloredPixels = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> startX = <span class="cpp-number">0</span>, startY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> endX = <span class="cpp-number">0</span>, endY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    startX = <span class="cpp-number">0</span>;
    startY = floor((<span class="cpp-keyword">float</span>)height / <span class="cpp-number">2</span>);
    endX = floor((<span class="cpp-keyword">float</span>)width / <span class="cpp-number">2</span>);
    endY = height;

    <span class="cpp-keyword">for</span> (i=startY; i&lt;endY; i++)
    {
        <span class="cpp-keyword">for</span> (j=startX; j&lt;endX; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
                coloredPixels++;
        }
    }

    <span class="cpp-keyword">return</span> coloredPixels;
}


<span class="cpp-keyword">int</span> NeuralNetwork::GetColoredPixelCountBottomRight(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height)
{
    <span class="cpp-keyword">int</span> coloredPixels = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> startX = <span class="cpp-number">0</span>, startY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> endX = <span class="cpp-number">0</span>, endY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;

    startX = floor((<span class="cpp-keyword">float</span>)width / <span class="cpp-number">2</span>);
    startY = floor((<span class="cpp-keyword">float</span>)height / <span class="cpp-number">2</span>);
    endX = width;
    endY = height;

    <span class="cpp-keyword">for</span> (i=startY; i&lt;endY; i++)
    {
        <span class="cpp-keyword">for</span> (j=startX; j&lt;endX; j++)
        {
            <span class="cpp-keyword">if</span> (imageData[j + (i * width)] == <span class="cpp-number">1</span>)
                coloredPixels++;
        }
    }

    <span class="cpp-keyword">return</span> coloredPixels;
}

<span class="cpp-keyword">char</span> NeuralNetwork::RecognizeCharacter(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">char</span> *imageData, <span class="cpp-keyword">int</span> width, <span class="cpp-keyword">int</span> height)
{
    <span class="cpp-keyword">int</span> *distances_x;
    <span class="cpp-keyword">int</span> *distances_y;
    <span class="cpp-keyword">int</span> intersections_x;
    <span class="cpp-keyword">int</span> intersections_y;
    <span class="cpp-keyword">int</span> coloredPixelCountTopLeft = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountTopRight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountBottomLeft = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> coloredPixelCountBottomRight = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> totalColoredPixelCount = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridSpaceX = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridSpaceY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridStartX = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> gridStartY = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> neuronIndex = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>, j = <span class="cpp-number">0</span>;
    <span class="cpp-keyword">float</span> maxNeuronOutput = <span class="cpp-number">0</span>.<span class="cpp-number">0</span>;
    <span class="cpp-keyword">int</span> maxNeuronOutputIndex = <span class="cpp-number">0</span>;

    gridSpaceX = floor((<span class="cpp-keyword">float</span>)width / GRIDLINES_COUNT_X);
    gridSpaceY = floor((<span class="cpp-keyword">float</span>)height / GRIDLINES_COUNT_Y);
    gridStartX = gridSpaceX / <span class="cpp-number">2</span>;
    gridStartY = gridSpaceY / <span class="cpp-number">2</span>;

    <span class="cpp-comment">// Get the closest distances to the image at certain intervals in the x and y directions</span>
    distances_x = GetXDistances(imageData, width, height, gridSpaceX, gridStartX);
    distances_y = GetYDistances(imageData, width, height, gridSpaceY, gridStartY);

    <span class="cpp-comment">// Get counts of the intersections in the x and y directions</span>
    intersections_x = GetXIntersections(imageData, width, height, gridSpaceX, gridStartX);
    intersections_y = GetYIntersections(imageData, width, height, gridSpaceY, gridStartY);

    <span class="cpp-comment">// Get the Counts of pixels</span>
    coloredPixelCountTopLeft = GetColoredPixelCountTopLeft(imageData, width, height);
    coloredPixelCountTopRight = GetColoredPixelCountTopRight(imageData, width, height);
    coloredPixelCountBottomLeft = GetColoredPixelCountBottomLeft(imageData, width, height);
    coloredPixelCountBottomRight = GetColoredPixelCountBottomRight(imageData, width, height);

    totalColoredPixelCount = coloredPixelCountTopLeft + coloredPixelCountTopRight + coloredPixelCountBottomLeft + coloredPixelCountBottomRight;

    neuronIndex = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// Set input values to the neural network using the data just collected</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;DISTANCES_COUNT_X; i++)
        SetInputValue(neuronIndex++, distances_x<span style="font-weight:bold;">);

    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;DISTANCES_COUNT_Y; i++)
        SetInputValue(neuronIndex++, distances_y<span style="font-weight:bold;">);

    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_x);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_y);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)intersections_x+intersections_y);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountTopLeft / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountTopRight / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountBottomLeft / totalColoredPixelCount);
    SetInputValue(neuronIndex++, (<span class="cpp-keyword">double</span>)coloredPixelCountBottomRight / totalColoredPixelCount);

    Propagate();

    <span class="cpp-keyword">delete</span> [] distances_x;
    <span class="cpp-keyword">delete</span> [] distances_y;

    <span class="cpp-comment">// Go through the output neurons and determine which has the highest output</span>
    <span class="cpp-keyword">for</span> (i=<span class="cpp-number">0</span>; i&lt;OUTPUT_NEURON_COUNT; i++)
    {
        <span class="cpp-keyword">if</span> (GetOutputValue(i) &gt; maxNeuronOutput)
        {
            maxNeuronOutput = GetOutputValue(i);
            maxNeuronOutputIndex = i;
        }
    }

    <span class="cpp-keyword">return</span> maxNeuronOutputIndex + <span class="cpp-number">65</span>;
}

<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// NeuronLayer class functions</span>
<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// Constructor</span>
NeuronLayer::NeuronLayer()
{
}

<span class="cpp-comment">// Adds a neuron to the neuron vector</span>
<span class="cpp-keyword">void</span> NeuronLayer::AddNeuron()
{
    m_neurons.push_back(<span class="cpp-keyword">new</span> Neuron());
}

<span class="cpp-comment">// Returns a pointer to a given neuron for this layer</span>
Neuron *NeuronLayer::GetNeuron(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron)
{
    <span class="cpp-keyword">return</span> m_neurons[neuron];
}

<span class="cpp-keyword">int</span> NeuronLayer::GetNeuronCount()
{
    <span class="cpp-keyword">return</span> m_neurons.size();
}

<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// Neuron class functions</span>
<span class="cpp-comment">/*****************************************************************************/</span>
<span class="cpp-comment">// Constructor</span>
Neuron::Neuron()
{
    <span class="cpp-comment">// Give the neuron an initial value</span>
    m_value = <span class="cpp-number">0</span>;

    <span class="cpp-comment">// set the delta value (used in backpropagation) initially to 0</span>
    m_deltaValue = <span class="cpp-number">0</span>;
}

<span class="cpp-comment">// Returns the output value for the neuron</span>
<span class="cpp-keyword">double</span> Neuron::GetValue()
{
    <span class="cpp-keyword">return</span> m_value;
}

<span class="cpp-comment">// Sets the output value for the neuron</span>
<span class="cpp-keyword">void</span> Neuron::SetValue(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> value)
{
    m_value = value;
}

<span class="cpp-comment">// Returns the delta value for the neuron</span>
<span class="cpp-keyword">double</span> Neuron::GetDeltaValue()
{
    <span class="cpp-keyword">return</span> m_deltaValue;
}

<span class="cpp-comment">// Sets the delta value for the neuron</span>
<span class="cpp-keyword">void</span> Neuron::SetDeltaValue(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> value)
{
    m_deltaValue = value;
}

<span class="cpp-comment">// Gets the target value for the neuron. Should only be used if the neuron is</span>
<span class="cpp-comment">// an output neuron</span>
<span class="cpp-keyword">double</span> Neuron::GetTargetValue()
{
    <span class="cpp-keyword">return</span> m_targetValue;
}

<span class="cpp-comment">// Sets the target value for the neuron. Should only be used if the neuron is</span>
<span class="cpp-comment">// an output neuron</span>
<span class="cpp-keyword">void</span> Neuron::SetTargetValue(<span class="cpp-keyword">double</span> targetValue)
{
    m_targetValue = targetValue;
}

<span class="cpp-comment">// Adds a new connection to the connection vector</span>
<span class="cpp-keyword">void</span> Neuron::AddConnection(<span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> weight)
{
    m_connections.push_back(weight);
}

<span class="cpp-comment">// Returns the connection weight to another neuron</span>
<span class="cpp-keyword">double</span> Neuron::GetConnectionWeight(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron)
{
    <span class="cpp-keyword">return</span> m_connections[neuron];
}

<span class="cpp-comment">// Sets the connection weight to another neuron</span>
<span class="cpp-keyword">void</span> Neuron::SetConnectionWeight(<span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> neuron, <span class="cpp-keyword">const</span> <span class="cpp-keyword">double</span> weight)
{
    m_connections[neuron] = weight;
}

<span class="cpp-directive">#endif</span>



</pre></div><!–ENDSCRIPT–> 

<!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - chadjohnson on September 14, 2005 4:03:12 AM]<!–EDIT–></span><!–/EDIT–>

This topic is closed to new replies.

Advertisement