Click here to Skip to main content
15,894,285 members
Articles / Programming Languages / C#

Image Recognition with Neural Networks

Rate me:
Please Sign up or sign in to vote.
4.82/5 (89 votes)
30 Oct 2007CPOL4 min read 1M   46.2K   286  
This article contains a brief description of BackPropagation Artificial Neural Network and its implementation for Image Recognition
��/*##########################################################################

 * 

 * FormANN.cs

 * -------------------------------------------------------------------------

 * By

 * Murat FIRAT, June 2007

 * muratti24@gmail.com

 * 

 * -------------------------------------------------------------------------

 * Last Update:

 * July,18th 2007

 * 

 * -------------------------------------------------------------------------

 * Description:

 * FormANN.cs implements the interface that uses backpropagation classes.

 * 

 * -------------------------------------------------------------------------

 * Notes:

 * To train the B.P.N. Network there must be a folder [in the same directory

 * of the .exe ] named "PATTERNS" which contains one image for each pattern.

 * (For example, [for english alfhabet] in "PATTERNS" directory 

 * there must be images, namely 0.bmp, 1.bmp, 2.bmp ... Z.bmp 

 * 

 * -------------------------------------------------------------------------

 ###########################################################################*/





using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO;

using System.Collections;

using System.Threading;

using ANN;



//BPNN: BackPropagation Neural Network

namespace BPNN

{

    public partial class FormANN : Form

    {

        private BP1Layer Recognizer1Layer;

        private BP2Layer Recognizer2Layer;

        private BP3Layer Recognizer3Layer;



        private double[] InputFromUser;

        private List<Point> PointsOnPanel;



        private int AvImageHeigh;

        private int AvImageWidth;

        //private int PreInputNumber = AvImageHeigh * AvImageWidth;//not needed

        private int InputNumber = 250;

        private int HiddenNumber = 100;

        private int OutputNumber;

        private double MaxError = 1.1;

        private int LayerNum=1;

        private string PatternsDirectory = "PATTERNS";

        

        //to save each taining image as array of double(network inputs)

        ArrayList TrainingSet;

        //to hold [each] name of [each] image(network outputs) 

        ArrayList TrainingValues;        



        //to draw characters on panel

        private bool MouseMoving = false;

        private int PanelImgeHeight;

        private int PanelImgeWidth;



        //for training process

        private Thread ThreadTrain;



        //to state training process       

        private delegate void UpdateControl(string s);

        private DateTime DTStart;

       

        public FormANN()

        {

            InitializeComponent();

            InitializeDataMembers();

            InitializeSettings();

        }



        //clean (any) threads

        private void FormANN_FormClosing(object sender, FormClosingEventArgs e)

        {

            System.Environment.Exit(System.Environment.ExitCode);

        }



        //Create Instances of Data Members

        private void InitializeDataMembers()

        {

            try

            {

                textBoxState.AppendText("(Re)Initializing The Network..");



                string[] Files = Directory.GetDirectories(PatternsDirectory);

               

                int AvHeight = 0, AvWidth = 0, PNum = 0;



                foreach (string file in Directory.GetFiles(PatternsDirectory))

                {

                    if (Path.GetExtension(file) == ".bmp")

                    {

                        Bitmap BM = new Bitmap(file);

                        AvHeight += BM.Height;

                        AvWidth += BM.Width;

                        PNum++;

                        BM.Dispose();

                    }

                }



                OutputNumber = PNum;

                AvHeight /= PNum;

                AvWidth /= PNum;



                AvImageHeigh = AvHeight;

                AvImageWidth = AvWidth;



                TrainingSet = new ArrayList(PNum);

                TrainingValues = new ArrayList(PNum);





                foreach (string file in Directory.GetFiles(PatternsDirectory))

                {

                    if (Path.GetExtension(file) == ".bmp")

                    {

                        Bitmap BM = new Bitmap(file);

                        TrainingSet.Add(IMGToDoubleArr(BM, AvWidth, AvHeight));                      

                        TrainingValues.Add(Path.GetFileNameWithoutExtension(file));                        

                        BM.Dispose();

                    }



                }



                PanelImgeWidth = TrackBarWidth.Value;

                PanelImgeHeight = 30 - TrackBarHeight.Value;



                pictureBoxInput.Height = AvImageHeigh;

                pictureBoxInput.Width = AvImageWidth;

                

                InputFromUser = new double[AvImageHeigh * AvImageWidth];

                PointsOnPanel = new List<Point>();



                if (LayerNum == 1)

                {

                    Recognizer1Layer = new BP1Layer(AvImageHeigh * AvImageWidth, OutputNumber);

                }

                else if (LayerNum == 2)

                {

                    Recognizer2Layer = new BP2Layer(AvImageHeigh * AvImageWidth, InputNumber, OutputNumber);

                }

                else if (LayerNum == 3)

                {

                    Recognizer3Layer = new BP3Layer(AvImageHeigh * AvImageWidth, InputNumber, HiddenNumber, OutputNumber);

                }



                textBoxState.AppendText("Done!\r\n");

            }

            catch (Exception Ex)

            {                

                MessageBox.Show("Error Initializing Network Defaults: " + Ex.Message);



                textBoxState.AppendText("Error Initializing..\r\n");

            }

        }



        //Fill Settings Panel

        private void InitializeSettings()

        {

            textBoxState.AppendText("Initializing Settings..");



            comboBoxLayers.Items.Clear();

            comboBoxLayers.Items.Add(1);

            comboBoxLayers.Items.Add(2);

            comboBoxLayers.Items.Add(3);

            comboBoxLayers.SelectedIndex = 0;



            textBoxInputUnit.Text = InputNumber.ToString();

            textBoxHiddenUnit.Text = HiddenNumber.ToString();

            textBoxOutputUnit.Text = OutputNumber.ToString();

            textBoxMaxError.Text = MaxError.ToString();



            PatternsDirectory = Path.GetFullPath(PatternsDirectory);

            textBoxTrainingBrowse.Text=PatternsDirectory ;



            textBoxState.AppendText("Done!\r\n");

        }



        //simply convert rgb to double

        private double[] IMGToDoubleArr(Bitmap BM, int Col, int Row)

        {

            double HRate = ((Double)Row / BM.Height);

            double WRate = ((Double)Col / BM.Width);

            double[] Result = new double[Col * Row];

            for (int r = 0; r < Row; r++)

            {

                for (int c = 0; c < Col; c++)

                {

                    Color color = BM.GetPixel((int)(c / WRate), (int)(r / HRate));

                    Result[r * Col + c] =1- (color.R * .3 + color.G * .59 + color.B * .11) / 255;

                }

            }

            return Result;

        }



        //simply convert double to [grey level] rgb  

        private Bitmap DoubleArrToIMG(double[] input,int DHeight,int DWidth,

                                                     int BHeight, int BWidth)

        {

            double HRate = ((double)BHeight / DHeight);

            double WRate = ((double)BWidth / DWidth);

            Bitmap BM = new Bitmap(BWidth, BHeight);



            for (int i = 0; i < BHeight; i++)

            {

                for (int j = 0; j < BWidth; j++)

                {

                    int x =(int)((double) j / WRate);

                    int y =(int)((double) i / HRate);



                    double temp = input[y * DWidth + x];

                    BM.SetPixel(j, i, Color.FromArgb((int)((1 - temp) * 255), (int)((1 - temp) * 255), (int)((1 - temp) * 255)));

                                    

                }

            }

            return BM;

        }



        private void radioButtonDraw_CheckedChanged(object sender, EventArgs e)

        {

            if (radioButtonDraw.Checked)

            {

                textBoxBrowse.Enabled = false;

                buttonBrowse.Enabled = false;



                radioButtonDraw.Checked = true;

                groupBoxDrawing.Enabled = true;

                buttonClear.Enabled = true;



                InputFromUser = new double[AvImageHeigh * AvImageWidth];                

            }

        }



        private void radioButtonBrowse_CheckedChanged(object sender, EventArgs e)

        {

            if (radioButtonBrowse.Checked)

            {

                textBoxBrowse.Enabled = true;

                buttonBrowse.Enabled = true;



                radioButtonDraw.Checked = false;

                groupBoxDrawing.Enabled = false;

                buttonClear.Enabled = false;



                InputFromUser = new double[AvImageHeigh * AvImageWidth];

                PointsOnPanel.Clear();

                PanelDrawing.Invalidate();

            }

        }



       

        private void TrackBarWidth_Scroll(object sender, EventArgs e)

        {

            PanelImgeWidth = TrackBarWidth.Value;

            if (PanelImgeWidth < 10)

            {

                TrackBarWidth.Value = 10;

                PanelImgeWidth = 10;

            }

            InputFromUser = new double[AvImageHeigh * AvImageWidth];

            PointsOnPanel.Clear();



            PanelDrawing.Invalidate();

        }



        private void TrackBarHeight_Scroll(object sender, EventArgs e)

        {

            PanelImgeHeight = TrackBarHeight.Maximum - TrackBarHeight.Value;

            if (PanelImgeHeight < 15)

            {

                TrackBarHeight.Value = TrackBarHeight.Maximum - 15;

                PanelImgeHeight = 15;

            }

            InputFromUser = new double[AvImageHeigh * AvImageWidth];

            PointsOnPanel.Clear();          



            PanelDrawing.Invalidate();

        }



        private void DrawingPanel_Paint(object sender, PaintEventArgs e)

        {

            Graphics graphicsObject = e.Graphics;



            Brush BR1 = new SolidBrush(Color.Black);

            Brush BR2 = new SolidBrush(Color.White);



            int width=PanelImgeWidth * (PanelDrawing.Width / TrackBarWidth.Maximum);

            int height = PanelImgeHeight * (PanelDrawing.Height / TrackBarHeight.Maximum);

            graphicsObject.FillRectangle(BR2, 0, 0, width, height); ;



            int pointWidth = 2 * (PanelDrawing.Width / TrackBarWidth.Maximum);                

            int pointHeight = 2 * (PanelDrawing.Height / TrackBarHeight.Maximum);



            foreach (Point p in PointsOnPanel)

            {                

                //if statement: to prevent drawing over permitted area

                if ((p.X + pointWidth / 2 < width) && (p.Y + pointHeight / 2 < height))

                {

                    graphicsObject.FillEllipse(BR1, p.X, p.Y, pointWidth, pointHeight);

                }

            }

            graphicsObject.Dispose();

        }



        private void DrawingPanel_MouseMove(object sender, MouseEventArgs e)

        {

            if (MouseMoving)

            {

                //map to actual input(20x30)

                int X = (int)(e.X * ((double)TrackBarWidth.Maximum / PanelDrawing.Width));

                int Y = (int)(e.Y * ((double)TrackBarHeight.Maximum / PanelDrawing.Height));



                //select as to trackbar(PanelImgeHeightxPanelImgeWidth)

                if (X < 0 || PanelImgeHeight <= Y || Y < 0 || PanelImgeWidth<= X)

                {

                    return;

                }



                //map to average dimensions(AvImageHeighxAvImageWidth)

                int y = (int)(Y * ((double)AvImageHeigh / PanelImgeHeight));

                int x = (int)(X * ((double)AvImageWidth / PanelImgeWidth));



                InputFromUser[y * AvImageWidth + x] = 1;

                if (y * AvImageWidth + x + 1 < InputFromUser.Length)

                {

                    InputFromUser[y * AvImageWidth + x + 1] = 1;

                }

                if ((y + 1) * AvImageWidth + x < InputFromUser.Length)

                {

                    InputFromUser[(y + 1) * AvImageWidth + x] = 1;

                }

                if ((y + 1) * AvImageWidth + x + 1 < InputFromUser.Length)

                {

                    InputFromUser[(y + 1) * AvImageWidth + x + 1] = 1;

                }



                //add the point as to previous dimensions(PanelDrawing.WidthxPanelDrawing.Height)

                PointsOnPanel.Add(new Point(X * (PanelDrawing.Width / TrackBarWidth.Maximum),

                                     Y * (PanelDrawing.Height / TrackBarHeight.Maximum)));

                PanelDrawing.Invalidate();

            }

        }



        private void DrawingPanel_MouseUp(object sender, MouseEventArgs e)

        {

            MouseMoving = false;

        }



        private void DrawingPanel_MouseDown(object sender, MouseEventArgs e)

        {

            MouseMoving = true;

        }

        

        private void buttonClear_Click(object sender, EventArgs e)

        {

            InputFromUser = new double[AvImageHeigh * AvImageWidth];

            PointsOnPanel.Clear();

            PanelDrawing.Invalidate();

        }



        private void buttonTrainingBrowse_Click(object sender, EventArgs e)

        {

            FolderBrowserDialog FD = new FolderBrowserDialog();

            FD.SelectedPath = PatternsDirectory;

            if (FD.ShowDialog() == DialogResult.OK)

            {

                textBoxTrainingBrowse.Text = FD.SelectedPath;

            }

        }        



        private void comboBoxLayers_SelectedIndexChanged(object sender, EventArgs e)

        {

            if (comboBoxLayers.SelectedIndex == 0)

            {

                textBoxInputUnit.Enabled = false;

                textBoxHiddenUnit.Enabled = false;

            }

            else if (comboBoxLayers.SelectedIndex == 1)

            {

                textBoxInputUnit.Enabled = true;

                textBoxHiddenUnit.Enabled = false;

            }

            else if (comboBoxLayers.SelectedIndex == 2)

            {

                textBoxInputUnit.Enabled = true;

                textBoxHiddenUnit.Enabled = true;

            }

        }



        private void buttonSaveSettings_Click(object sender, EventArgs e)

        {

            try

            {

                LayerNum = comboBoxLayers.SelectedIndex + 1;

                MaxError = Double.Parse(textBoxMaxError.Text);

                if (MaxError <= 0)

                {

                    throw new Exception("Maximum Error Must Be Positive");

                }



                InputNumber = Int32.Parse(textBoxInputUnit.Text);

                if (InputNumber <= 0)

                {

                    throw new Exception("Input Unit Number Must Be Positive");

                }



                HiddenNumber = Int32.Parse(textBoxHiddenUnit.Text);

                if (HiddenNumber <= 0)

                {

                    throw new Exception("Hidden Unit Number Must Be Positive");

                }



                OutputNumber = Int32.Parse(textBoxOutputUnit.Text);

                if (OutputNumber <= 0)

                {

                    throw new Exception("Output Unit Number Must Be Positive");

                }



                PatternsDirectory = textBoxTrainingBrowse.Text;

                if (!Directory.Exists(PatternsDirectory))

                {

                    throw new Exception("Directory Does Not Exist: " + PatternsDirectory);

                }

                //re-initialize

                InitializeDataMembers();



                textBoxOutputUnit.Text = OutputNumber.ToString();   



                buttonRecognize.Enabled = false;

                buttonSave.Enabled = false;



                textBoxState.AppendText("Saved Settings. (Re)Train Network To Apply New Settings.\r\n");

            }

            catch (Exception Ex)

            {

                MessageBox.Show("Error Saving Settings: " + Ex.Message);

            }

        }

        

        private void buttonTrain_Click(object sender, EventArgs e)

        {            

            textBoxState.AppendText("Training The Network.." + "\r\n");



            buttonStop.Enabled= true;

            buttonTrain.Enabled = false;

            buttonLoad.Enabled = false;           



            ThreadTrain = new Thread(new ThreadStart(TrainNetwork));            

            ThreadTrain.Start();

            DTStart = DateTime.Now;            

            timer1.Start();

        }





        private void TrainNetwork()

        {

            if (LayerNum == 1)

            {

                Recognizer1Layer.Train(TrainingSet, TrainingValues, MaxError);

            }

            else if (LayerNum == 2)

            {

                Recognizer2Layer.Train(TrainingSet, TrainingValues, MaxError);

            }

            else if (LayerNum == 3)

            {

                Recognizer3Layer.Train(TrainingSet, TrainingValues, MaxError);

            }



            buttonRecognize.Enabled = true;

            buttonSave.Enabled = true;



            textBoxState.Invoke(new UpdateControl(UpdateState), new object[] 

            { "Ended Training Process..\r\n "});

            

            buttonStop.Enabled = false;

            buttonTrain.Enabled = true;

            buttonLoad.Enabled = true;



            //show the last error and elapsed time           

            timer_Tick("object", new EventArgs());

            timer1.Stop();

        }



        void timer_Tick(object sender, EventArgs e)

        {

            TimeSpan TSElapsed;

            if (LayerNum == 1)

            {

                labelError.Text = "Current Error: " + Recognizer1Layer.CurrentError.ToString("##.###");

                TSElapsed = DateTime.Now - DTStart;

                labelTimer.Text = TSElapsed.Hours.ToString("D2") + ":" + TSElapsed.Minutes.ToString("D2") + ":" + TSElapsed.Seconds.ToString("D2");

            }

            else if (LayerNum == 2)

            {

                labelError.Text = "Current Error: " + Recognizer2Layer.CurrentError.ToString("##.###");

                TSElapsed = DateTime.Now - DTStart;

                labelTimer.Text = TSElapsed.Hours.ToString("D2") + ":" + TSElapsed.Minutes.ToString("D2") + ":" + TSElapsed.Seconds.ToString("D2");

            }

            else if (LayerNum == 3)

            {

                labelError.Text = "Current Error: " + Recognizer3Layer.CurrentError.ToString("##.###");

                TSElapsed = DateTime.Now - DTStart;

                labelTimer.Text = TSElapsed.Hours.ToString("D2") + ":" + TSElapsed.Minutes.ToString("D2") + ":" + TSElapsed.Seconds.ToString("D2");

            }

        }



        private void UpdateState(string s)

        {

            textBoxState.AppendText(s);

        }

        

        private void buttonRecognize_Click(object sender, EventArgs e)

        {

            string MatchedHight = "?", MatchedLow = "?";

            double OutputValueHight = 0, OutputValueLow = 0;

            if (LayerNum == 1)

            {

                Recognizer1Layer.Recognize(InputFromUser, ref MatchedHight, ref OutputValueHight, ref MatchedLow, ref OutputValueLow);

            }

            else if (LayerNum == 2)

            {

                Recognizer2Layer.Recognize(InputFromUser, ref MatchedHight, ref OutputValueHight, ref MatchedLow, ref OutputValueLow);

            }

            else if (LayerNum == 3)

            {

                Recognizer3Layer.Recognize(InputFromUser, ref MatchedHight, ref OutputValueHight, ref MatchedLow, ref OutputValueLow);

            }



            pictureBoxInput.Image = DoubleArrToIMG(InputFromUser, AvImageHeigh, AvImageWidth,

                                                   pictureBoxInput.Height, pictureBoxInput.Width);

                  

            labelMatchedHigh.Text = MatchedHight + "(%" + (OutputValueHight * 100).ToString("##.#") + ")";

            if (MatchedHight != "?" && File.Exists(PatternsDirectory + "\\" + MatchedHight + ".bmp"))

            {

                pictureBoxMatchedHigh.ImageLocation = PatternsDirectory + "\\" + MatchedHight + ".bmp";

            }



            labelMatchedLow.Text = MatchedLow + "(%" + (OutputValueLow * 100).ToString("##.#") + ")";

            if (MatchedLow != "?" && File.Exists(PatternsDirectory + "\\" + MatchedLow + ".bmp"))

            {

                pictureBoxMatchedLow.ImageLocation = PatternsDirectory + "\\" + MatchedLow + ".bmp";

            }



        }



        private void buttonBrowse_Click(object sender, EventArgs e)

        {

            OpenFileDialog FD = new OpenFileDialog();

            FD.Filter = "Bitmap Image(*.bmp)|*.bmp";

            FD.InitialDirectory = PatternsDirectory;



            if (FD.ShowDialog() == DialogResult.OK)

            {

                string FileName = FD.FileName;

                if (Path.GetExtension(FileName) == ".bmp")

                {

                    Bitmap BM = new Bitmap(FileName);

                    InputFromUser = IMGToDoubleArr(BM, AvImageWidth, AvImageHeigh);

                    BM.Dispose();



                    textBoxBrowse.Text = FileName;

                }

            }

        }



        private void buttonStop_Click(object sender, EventArgs e)

        {

            if (LayerNum == 1)

            {

                Recognizer1Layer.StopTraining = true;

            }

            else if (LayerNum == 2)

            {

                Recognizer2Layer.StopTraining = true;

            }

            else if (LayerNum == 3)

            {

                Recognizer3Layer.StopTraining = true;

            }            

            

            textBoxState.AppendText("Terminating Training Process..\r\n");

        }



        private void buttonSave_Click(object sender, EventArgs e)

        {

            try

            {

                SaveFileDialog FD = new SaveFileDialog();

                FD.Filter = "Network File(*.net)|*.net";

                if (FD.ShowDialog() == DialogResult.OK)

                {

                    if (LayerNum == 1)

                    {

                        Recognizer1Layer.SaveNetwork(FD.FileName, AvImageHeigh, AvImageWidth);

                    }

                    else if (LayerNum == 2)

                    {

                        Recognizer2Layer.SaveNetwork(FD.FileName, AvImageHeigh, AvImageWidth);

                    }

                    else if (LayerNum == 3)

                    {

                        Recognizer3Layer.SaveNetwork(FD.FileName, AvImageHeigh, AvImageWidth);

                    }

                    textBoxState.AppendText("Saved The Network Successfully..\r\n");

                }                

            }

            catch (Exception Ex)

            {

                MessageBox.Show("Unable To Save The File Due To The Reason: " + Ex.Message,"Error");

            }

            

        }



        private void buttonLoad_Click(object sender, EventArgs e)

        {

            try

            {

                OpenFileDialog FD = new OpenFileDialog();

                FD.Filter = "Network File(*.net)|*.net";

                if (FD.ShowDialog() == DialogResult.OK)

                {

                    if (LayerNum == 1)

                    {

                        Recognizer1Layer.LoadNetwork(FD.FileName, ref AvImageHeigh, ref AvImageWidth);

                    }

                    else if (LayerNum == 2)

                    {

                        Recognizer2Layer.LoadNetwork(FD.FileName, ref AvImageHeigh, ref AvImageWidth);

                    }

                    else if (LayerNum == 3)

                    {

                        Recognizer3Layer.LoadNetwork(FD.FileName, ref AvImageHeigh, ref AvImageWidth);

                    }



                    buttonRecognize.Enabled = true;

                    buttonSave.Enabled = true;



                    textBoxState.AppendText("Loaded The Network Successfully..\r\n");

                }                

            }

            catch (Exception Ex)

            {

                MessageBox.Show("Unable To Load The File Due To The Reason: " + Ex.Message,"Error");

            }

        }                

    }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Turkey Turkey
Has BS degree on computer science, working as software engineer in istanbul.

Comments and Discussions