Serial ReadLine in C# for Arduino doesn't work properly - c#

I want to send a serial data from Arduino to an app using C# IDE Visual Studio. I will send 40 character with 9600 baudrate. The connection between Arduino in C# is good, the problem is when I send the data to C# using ReadLine command. I don't get the whole data, and always some first data loss, for an example if I send 123456789, in C#, it reads just 456789 or 89 or 3456789.
#define TC1 A0
#define TC2 A1
#define TC3 A2
#define TC4 A3
#define TC5 A4
#define TC6 A5
#define TC7 A6
#define TC8 A7
//#define TC9 A8
//#define TC10 A9
float K1 = 1;
float K2 = 1;
float K3 = 1;
float K4 = 1;
float K5 = 1;
float K6 = 1;
float K7 = 1;
float K8 = 1;
float K9 = 1;
float K10 = 1;
int n = 10;
int temp[10];
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
int x = 100;
temp[0]=analogRead(TC1)*K1*x*5/1023;
temp[1]=analogRead(TC2)*K2*x*5/1023;
temp[2]=analogRead(TC3)*K3*x*5/1023;
temp[3]=analogRead(TC4)*K4*x*5/1023;
temp[4]=analogRead(TC5)*K5*x*5/1023;
temp[5]=analogRead(TC6)*K6*x*5/1023;
temp[6]=analogRead(TC7)*K7*x*5/1023;
temp[7]=analogRead(TC8)*K8*x*5/1023;
temp[8]=analogRead(TC8)/5*200*K9;
temp[9]=analogRead(TC8)/5*200*K10;
// temp[0] = 1101;
// temp[1] = 2327;
// temp[2] = 114;
// temp[3] = 6753;
// temp[4] = 50;
// temp[5] = 1;
// temp[6] = 24;
// temp[7] = 123;
// temp[8] = 1269;
// temp[9] = 3;
for (int i = 0; i <= n - 1; i++) {
char buff[] = {'0', '0', '0', '0'};
int length_temp = String(temp[i]).length();
for (int j = length_temp - 1; j >= 0; j--) {
buff[j] = String(temp[i])[length_temp - j - 1];
}
for (int j = 0; j <= 3; j++) {
Serial.write(buff[3 - j]);
}
}
Serial.write('\n');
}
That is my Arduino code, and here the entire my C# code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO.Ports;
using System.Windows.Forms;
namespace Display_data
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void start_Click(object sender, EventArgs e)
{
}
private void stop_Click(object sender, EventArgs e)
{
//myport.Close();
//textbox.Text = "Koneksi diputus!";
}
private void makefile_Click(object sender, EventArgs e)
{
//String simpan = #"C:\"; //Alamat penyimpanan
//string nama_file = "Data.txt";
//System.IO.File.WriteAllText(simpan + nama_file, (ch1.Text+','+ ch2.Text + ',' + ch3.Text + ',' + ch4.Text + ',' + ch5.Text + ',' + ch6.Text + ',' + ch7.Text + ',' + ch8.Text + ',' + ch9.Text + ',' + ch10.Text ));
//MessageBox.Show("Data telah tersimpan di " + simpan + nama_file);
//string nama_gambar = "Data.png";
//this.grafik.SaveImage(simpan + nama_gambar, System.Windows.Forms.DataVisualization.Charting.ChartImageFormat.Png);
//MessageBox.Show("Gambar telah tersimpan di " + simpan + nama_gambar);
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
private void Port_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void connect_Click(object sender, EventArgs e)
{
myport = new SerialPort();
myport.BaudRate = 9600;
myport.PortName = Port.Text;
myport.DataReceived += receive;
try
{
myport.Open();
textbox.Text = "Connected";
}
catch (Exception)
{
textbox.Text = "Connection Failed!";
}
}
int j;
void receive(object sender, SerialDataReceivedEventArgs e)
{
string data = myport.ReadLine();
int CHa;
int CHb;
int CHc;
int CHd;
int CHe;
int CHf;
int CHg;
int CHh;
int CHi;
int CHj;
j++;
int delay = 500;
CHa = Int32.Parse(data.Substring(0, 4));
CHb = Int32.Parse(data.Substring(4, 4));
CHc = Int32.Parse(data.Substring(8, 4));
CHd = Int32.Parse(data.Substring(12, 4));
CHe = Int32.Parse(data.Substring(16, 4));
CHf = Int32.Parse(data.Substring(20, 4));
CHg = Int32.Parse(data.Substring(24, 4));
CHh = Int32.Parse(data.Substring(28, 4));
CHi = Int32.Parse(data.Substring(32, 4));
CHj = Int32.Parse(data.Substring(36, 4));
//ch1.Text = data.Substring(0, 4);
//ch2.Text = data.Substring(4, 4);
//ch3.Text = data.Substring(8, 4);
//ch4.Text = data.Substring(12, 4);
//ch5.Text = data.Substring(16, 4);
//ch6.Text = data.Substring(20, 4);
//ch7.Text = data.Substring(24, 4);
//ch8.Text = data.Substring(28, 4);
//ch9.Text = data.Substring(32, 4);
//ch10.Text = data.Substring(36, 4);
ch1.Text = CHa.ToString();
ch2.Text = CHb.ToString();
ch3.Text = CHc.ToString();
ch4.Text = CHd.ToString();
ch5.Text = CHe.ToString();
ch6.Text = CHf.ToString();
ch7.Text = CHg.ToString();
ch8.Text = CHh.ToString();
ch9.Text = CHi.ToString();
ch10.Text = CHj.ToString();
this.grafik.Series["Ch 1"].Points.AddXY(j * delay, CHa);
this.grafik.Series["Ch 2"].Points.AddXY(j * delay, CHb);
this.grafik.Series["Ch 3"].Points.AddXY(j * delay, CHc);
this.grafik.Series["Ch 4"].Points.AddXY(j * delay, CHd);
this.grafik.Series["Ch 5"].Points.AddXY(j * delay, CHe);
this.grafik.Series["Ch 6"].Points.AddXY(j * delay, CHf);
this.grafik.Series["Ch 7"].Points.AddXY(j * delay, CHg);
this.grafik.Series["Ch 8"].Points.AddXY(j * delay, CHh);
this.grafik.Series["Ch 9"].Points.AddXY(j * delay, CHi);
this.grafik.Series["Ch 10"].Points.AddXY(j * delay, CHj);
}
private void label1_Click(object sender, EventArgs e)
{
}
private void label11_Click(object sender, EventArgs e)
{
}
}
}
So what is the problem? Do I need to latch the open port command?

Ok I don't quite know but if you write '\n' to the Serial port as line ending and then use ReadLine in c# (I think you use windows?) it caused problems for me. I used my own "Line ending cahr". Just use something like '!' and then always read only one char and compare it to '!'.
pseudocode:
string msg = ""
char read = readchar()
if(read == '!')
//stop reading
else
//add char to string
msg += read

Solved guys, my problem is the first line of the serial data from arduino is not exactly like what i'm trying to send, but for the second line and after that it's normal just like what i print to serial. i still don't know why but my method is just skip my first line incoming data

Related

Thread safe assigning of the returned result of a threaded function to a variable

I have a function that takes a variable as a parameter and returns a calculated result. That function splits up into other functions each doing their own calculation. I need the function to run multi threaded.
My code:
for (int i = 0; i < pic.Width; i++)
{
for (int k = 0; k < pic.Height; k++)
{
var localK = k;
var localI = i;
Image bestPic;
new Thread(() =>
{
bestPic = new Bitmap(getBestPic(argb));//THIS IS WHERE THE WRONG VALUES ARE ASSIGNED BECAUSE OF CROSS THREADING
lock (thisLock)
{
g.DrawImage(bestPic, localI * bestPic.Width, localK * bestPic.Height, bestPic.Width, bestPic.Height);
}
}).Start();
}
}
All I need is the function getBestPic to run multi threaded. But how do I run the function getBestPic multi threaded and make the assigning of the returned result to the bestPic variable atomic?
My entire program if needed: This is a montage program.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Drawing;
namespace test
{
public partial class Form1 : Form
{
private static readonly Object thisLock = new Object();
private Graphics g;
private Bitmap returnImg;
private Bitmap pic;
private int done = 0;
private int pictureWidthAndLength = 200;
private string inputPicName = "test";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime dtStart = DateTime.Now;
pic = new Bitmap(inputPicName + ".jpg");
//MessageBox.Show(pic.GetPixel(1,1).ToArgb().ToString());
//MessageBox.Show(pic.Width.ToString() + " x " + pic.Height.ToString());
returnImg = new Bitmap(pic.Width * pictureWidthAndLength, pic.Height * pictureWidthAndLength);
using (g = Graphics.FromImage(returnImg))
{
Color clr;
int[] argb = new int[4];
for (int i = 0; i < pic.Width; i++)
{
for (int k = 0; k < pic.Height; k++)
{
clr = pic.GetPixel(i, k);
argb[0] = clr.A;
argb[1] = clr.R;
argb[2] = clr.G;
argb[3] = clr.B;
var localK = k;
var localI = i;
Image bestPic;
if (cbxthreading.Checked)
{
new Thread(() =>
{
bestPic = new Bitmap(getBestPic(argb));
lock (thisLock)
{
g.DrawImage(bestPic, localI * bestPic.Width, localK * bestPic.Height, bestPic.Width, bestPic.Height);
done++;
}
}).Start();
}
else
{
//Single threaded
bestPic = new Bitmap(getBestPic(argb));
g.DrawImage(bestPic, localI * pictureWidthAndLength, localK * pictureWidthAndLength, pictureWidthAndLength, pictureWidthAndLength);
}
//MessageBox.Show(getBestPic(argb));
}
}
if (cbxthreading.Checked)
{
int loopNum = pic.Width * pic.Height;
while (done < loopNum) { }
}
}
DateTime dtEnd = DateTime.Now;
MessageBox.Show((dtEnd - dtStart).ToString());
}
//Get picture that is best suited to replace pixel
private string getBestPic(int[] argb)
{
int numOfpics = 5;
int[] currentBest = new int[2];
currentBest[0] = 255;
currentBest[1] = 150;
for (int i = 0; i < numOfpics; i++)
{
int compare = compareARGB(getAverageRGB(new Bitmap((i + 1).ToString()+".jpg")), argb);
if (compare < currentBest[0])
{
currentBest[0] = compare;
currentBest[1] = i + 1;
}
}
return currentBest[1].ToString() + ".jpg";
}
// smaller the value, closer the camparison
private int compareARGB(int[] one, int[] two)
{
int [] tmp = new int[4];
tmp[0] = Convert.ToInt32(Math.Abs(one[0] - two[0]));
tmp[1] = Convert.ToInt32(Math.Abs(one[1] - two[1]));
tmp[2] = Convert.ToInt32(Math.Abs(one[2] - two[2]));
tmp[3] = Convert.ToInt32(Math.Abs(one[3] - two[3]));
return (tmp[0] + tmp[1] + tmp[2] + tmp[3]);
}
//return int arry with size 4 containing the argb values
private int[] getAverageRGB(Bitmap img)
{
Color clr;
int aplha = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < img.Width; i++)
{
for (int k = 0; k < img.Height; k++)
{
clr = img.GetPixel(i, k);
aplha += clr.A;
red += clr.R;
green += clr.G;
blue += clr.B;
}
}
aplha = aplha / (img.Width * img.Height);
red = red / (img.Width * img.Height);
green = green / (img.Width * img.Height);
blue = blue / (img.Width * img.Height);
int[] re = new int[] {aplha,red,green,blue};
return re;
}
private void button2_Click(object sender, EventArgs e)
{
returnImg.Save(inputPicName+".bmp");
MessageBox.Show("Done!");
}
}
}
The single thread functionality works, but takes long. The multi threaded functionality also finishes in a third of the time of the single threaded, but the result is not correct.
getBestPic() method runs multi-thread as I understand. But the problem is the argb parameter. You initialize it ones and then overwrite its values in for loops.argb is reference type, so only the reference is passed to getBestPic(), so it's referenced values get changed while processed in getBestPic().
I would try to pass it by Value or move int[] argb = new int[4];line to the inside of the second for loop, so you every time initialize new variable. More on passing reference type params here.
Just create a copy of the Value of your argb in the getBestPic() method and use it instead of using the original one
private string getBestPic(int[] argb)
{
int[] argbCopy = argb.ToArray();
int numOfpics = 5;
int[] currentBest = new int[2];
currentBest[0] = 255;
currentBest[1] = 150;
for (int i = 0; i < numOfpics; i++)
{
int compare = compareARGB(getAverageRGB(new Bitmap((i + 1).ToString()+".jpg")), argbCopy);
if (compare < currentBest[0])
{
currentBest[0] = compare;
currentBest[1] = i + 1;
}
}
return currentBest[1].ToString() + ".jpg";
}

Where is the position number at

I am trying to create a chess board strategy application in WinForms c#.
Someone from here was gracious enough to help with this code.
When it is run, it does everything I wanted except that the sq.position values are wrong.
The value like A1 should be A7, A6 should be A2
How can I reverse the order of the number value in this code:
private void Test_Load(object sender, EventArgs e)
{
int blockSize = 70;
Panel[,] chessBoardPanels = new Panel[8, 8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j > 8; j++)
{
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), j);
sq.Color = (i + (j % 2)) % 2 == 0 ? Color.Black : Color.White;
Panel p = new Panel()
{
Size = new Size(blockSize, blockSize),
BackColor = sq.Color,
Tag = sq,
Location = new Point(blockSize * i + 15, blockSize * j + 15)
};
p.MouseEnter += new EventHandler(squareMouseEnter);
p.MouseLeave += new EventHandler(squareMouseLeave);
chessBoardPanels[i, j] = p;
groupBox1.Controls.Add(p);
}
}
}
private void squareMouseLeave(object sender, EventArgs e)
{
Panel p = (Panel)sender;
ChessSquare sq = (ChessSquare)p.Tag;
p.BackColor = sq.Color;
}
private void squareMouseEnter(object sender, EventArgs e)
{
Panel p = (Panel)sender;
ChessSquare sq = (ChessSquare)p.Tag;
p.BackColor = Color.Aqua;
label1.Text = string.Format("Current position: {0}", sq.Position);
}
public class ChessSquare
{
public string Letter { get; set; }
public int Number { get; set; }
public Color Color { get; set; }
public string Position
{
get { return string.Format("{0}{1}", Letter, Number + 1); }
}
public ChessSquare()
{ }
public ChessSquare(string letter, int number)
{
Letter = letter;
Number = number;
}
}
I am still very new to this type of programming....
Change this:
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), j);
to that:
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), 7 - j);
Update: Corrected! Thanks user2772713!

matching characters in strings in visual C#

I'm working on visual C#
to calculate the word error rate
I have one textbox for the refrence which is the correct sentance
and one for the hypothesis which is wrong one.
in order to calculate WER I need to calculate :
substitution : the word that has been changed which was my first question
Insert : the words that had been inserted in the sentence
Deleted: the words that had been deleted from the original sentence
For EX:
refrence: This is a NPL program.
hypothesis: it is an NPL cool.
it: substitution
is: correct
an :substitution
NPL:correct
program: deleted
cool: inserted
I tried the algorithm that dasblinkenlight proposed ( thank you so much by the way )
I worked but there is a runtime error I couldn't figure it out, in line
int x= Compute(buffer[j], buffer_ref[i]);
Index was outside the bounds of the array.
and here is my code :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
string [] hyp = new string[20];
string [] refrence = new string[20];
string [] Anser= new string[20];
string[] buffer = new string[20];
string[] buffer_ref = new string[20];
int count = 0; // number of words
string ref2=" " ;
string hyp2 = " ";
string Anser2 = " ";
string buffer2 = " ";
int corecct_c=0;
int corecct_d = 0;
int corecct_i = 0;
//====================================================================
public Form1()
{
InitializeComponent();
for (int i = 0; i <= 19; ++i)
{
hyp[i] = null;
buffer[i] = null;
}
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
refrence = this.textBox2.Text.Split(' ');
buffer_ref = this.textBox2.Text.Split(' ');
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
hyp = this.textBox1.Text.Split(' ');
buffer = this.textBox1.Text.Split(' ');
//hyp = this.textBox1.Text;
// fname1.Add(this.textBox1.Text);
}
public void correct(string[] R)
{
for (int i = 0; (i <= 19) && (R[i] != "."); ++i)
{
if (buffer[i] == refrence[i])
{ buffer[i] = "0";
buffer_ref[i] = "0";
corecct_c = corecct_c + 1;
Anser[i] = "C";
}
}
}
// function that compute 2 strings
public static int Compute(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
public void sub(){
for (int j = 0;j<=19;j++)
{
if (buffer[j].IndexOf("0") != -1)
{
for (int i = 0; i <= 19; i++)
{
if (buffer_ref[j].IndexOf("0") != -1)
{
int x= Compute(buffer[j], buffer_ref[i]);
if (x > 3)
{
buffer[j] = "0";
Anser[j] = "S";
}
}//end if
}
}//end if
}//end for
}// end fun
private void button1_Click(object sender, EventArgs e)
{
correct(refrence);
sub();
for (int i = 0; (i <= 19) && (refrence[i] != "."); ++i)
{
//loop intialize
ref2 = ref2 + " " + refrence[i];
hyp2 = hyp2 + " " + hyp[i];
Anser2 = Anser2 + " " + Anser[i];
buffer2 = buffer2 + " " + buffer[i];
count++;
}
listBox1.Items.Add(" Refrence :" + ref2);
listBox1.Items.Add(" HYp :" + hyp2);
listBox1.Items.Add(" Anser:" + Anser2);
listBox1.Items.Add(" buffer:" + buffer2);
listBox1.Items.Add(count);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
}
private void label2_Click(object sender, EventArgs e)
{
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
can you help me please ?
There is a built-in way to test if two lines are identical, but there is no built-in way to tell if two lines are similar. You need to implement an algorithm that measures string similarity, such as the Levenshtein Distance - a very common Edit Distance algorithm. Lines with small edit distance can be declared similar depending on some threshold specific to your requirements.
You'll need to use an algorithm that compares the "distance" between two strings:
The closeness of a match is measured in terms of the number of
primitive operations necessary to convert the string into an exact
match. This number is called the edit distance between the string and
the pattern. The usual primitive operations are:
insertion: cot → coat
deletion: coat → cot
substitution: coat → cost

how to make a dictionary that can hold more than 1 data?

i've been trying to modify the program so that it could accept more than one data for a single alphabet character for example letter "A". there were some sort of ContainsKey function that allow only one key from keyboard to hold only one data. how to make it possible to hold more than one data?
I'm gonna make it very clear, this is an online OCR program using unsupervised neural network. when a user draw a character in the drawing space, they will have the option to add the character into the learning data to be train later. when they add a character, they have to define what character they just entered using the key on the keyboard. for example, they draw letter 'A' and a popup window will show up asking the user to enter the key from the keyboard for that letter.
the problem here, when there is already a letter 'A' in the learning data, i cannot add another letter 'A' bcause the key A is already hold the previous 'A'. i wanted to make the key A is able to hold more than one letter 'A'.
im gonna post the whole code for the program here and i hope u guys bear with me. this isnt my program, it is from Heaton Research and i just intend to modify it. thank in advance.
public partial class Form1 : Form
{
/**
* The downsample width for the application.
*/
const int DOWNSAMPLE_WIDTH = 10;
/**
* The down sample height for the application.
*/
const int DOWNSAMPLE_HEIGHT = 12;
private Bitmap entryImage;
private Graphics entryGraphics;
private int entryLastX;
private int entryLastY;
private Pen blackPen;
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
private double[][] trainingSet;
private SelfOrganizingMap network;
public Form1()
{
InitializeComponent();
blackPen = new Pen(Color.Black);
entryImage = new Bitmap(entry.Width, entry.Height);
entryGraphics = Graphics.FromImage(entryImage);
downsampled = new bool[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
ClearEntry();
}
private void entry_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(entryImage, 0, 0);
Pen blackPen = new Pen(Color.Black);
g.DrawRectangle(blackPen, 0, 0, entry.Width - 1, entry.Height - 1);
}
private void btnDelete_Click(object sender, EventArgs e)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.letterData.Remove(ch);
this.letters.Items.Remove(str);
ClearEntry();
}
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
TextReader f = new StreamReader(openFileDialog1.FileName);
String line;
this.letterData.Clear();
this.letters.Items.Clear();
while ((line = f.ReadLine()) != null)
{
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
char ch = char.ToUpper(line[0]);
bool[] sample = new bool[sampleSize];
int idx = 2;
for (int i = 0; i < sampleSize; i++)
{
if (line[idx++] == '1')
sample[i] = true;
else
sample[i] = false;
}
this.letterData.Add(ch, sample);
this.letters.Items.Add("" + ch);
}
f.Close();
}
MessageBox.Show(this, "File Loaded");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
TextWriter f = new StreamWriter(saveFileDialog1.FileName);
int size = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
for (int i = 0; i < this.letters.Items.Count; i++)
{
char ch = ((string)this.letters.Items[i])[0];
bool[] data = this.letterData[ch];
f.Write(ch + ":");
for (int j = 0; j < size; j++)
{
f.Write(data[j] ? "1" : "0");
}
f.WriteLine("");
}
f.Close();
MessageBox.Show("File Saved");
}
}
catch (Exception e2)
{
MessageBox.Show("Error: " + e2.Message, "Training");
}
}
private void btnBeginTraining_Click(object sender, EventArgs e)
{
int inputCount = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
int letterCount = this.letters.Items.Count;
this.trainingSet = new double[letterCount][];
int index = 0;
foreach (char ch in this.letterData.Keys)
{
this.trainingSet[index] = new double[inputCount];
bool[] data = this.letterData[ch];
for (int i = 0; i < inputCount; i++)
{
this.trainingSet[index][i] = data[i] ? 0.5 : -0.5;
}
index++;
}
network = new SelfOrganizingMap(inputCount, letterCount, NormalizationType.Z_AXIS);
this.ThreadProc();
}
private void btnAdd_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
String Prompt = "Enter the letter you just draw (from the keyboard)";
String Title = "Letter definition Required";
String Default = " ";
Int32 XPos = ((SystemInformation.WorkingArea.Width / 2) - 200);
Int32 YPos = ((SystemInformation.WorkingArea.Height / 2) - 100);
bool valid = false;
for (int i = 0; i < this.downsampled.Length; i++)
{
if (this.downsampled[i])
{
valid = true;
}
}
if (!valid)
{
MessageBox.Show("Please draw a letter before adding it.");
return;
}
String Result = Microsoft.VisualBasic.Interaction.InputBox(Prompt, Title, Default, XPos, YPos);
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
//else if (this.letterData.ContainsKey(Result[0]))
//{
// MessageBox.Show("That letter is already defined, please delete first.");
//}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() {this.downsampled});
}
this.letters.Items.Add(Result);
//this.letterData.Add(Result[0], this.downsampled);
this.ClearEntry();
}
}
}
private void btnRecognize_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
if (this.network == null)
{
MessageBox.Show("The program needs to be trained first");
return;
}
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
double[] input = new double[sampleSize];
for (int i = 0; i < sampleSize; i++)
{
input[i] = this.downsampled[i] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
char[] map = mapNeurons();
this.result.Text = " " + map[best];
MessageBox.Show(" " + map[best] + " (Neuron #"
+ best + " fired)", "That Letter You Enter Is");
//ClearEntry();
}
private void btnClear_Click(object sender, EventArgs e)
{
ClearEntry();
}
private void btnSample_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
public void ClearEntry()
{
Brush whiteBrush = new SolidBrush(Color.White);
entryGraphics.FillRectangle(whiteBrush, 0, 0, entry.Width, entry.Height);
entry.Invalidate();
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
private void entry_MouseDown(object sender, MouseEventArgs e)
{
entry.Capture = true;
entryLastX = e.X;
entryLastY = e.Y;
}
private void entry_MouseUp(object sender, MouseEventArgs e)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entry.Capture = false;
}
private void entry_MouseMove(object sender, MouseEventArgs e)
{
if (entry.Capture == true)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entryLastX = e.X;
entryLastY = e.Y;
}
}
private void sample_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
int x, y;
int vcell = sample.Height / Form1.DOWNSAMPLE_HEIGHT;
int hcell = sample.Width / Form1.DOWNSAMPLE_WIDTH;
Brush whiteBrush = new SolidBrush(Color.White);
Brush blackBrush = new SolidBrush(Color.Black);
Pen blackPen = new Pen(Color.Black);
g.FillRectangle(whiteBrush, 0, 0, sample.Width, sample.Height);
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
g.DrawLine(blackPen, 0, y * vcell, sample.Width, y * vcell);
}
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
g.DrawLine(blackPen, x * hcell, 0, x * hcell, sample.Height);
}
int index = 0;
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
if (this.downsampled[index++])
{
g.FillRectangle(blackBrush, x * hcell, y * vcell, hcell, vcell);
}
}
}
g.DrawRectangle(blackPen, 0, 0, sample.Width - 1, sample.Height - 1);
}
private void letters_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.letters.SelectedIndex >= 0)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.downsampled = this.letterData[ch];
this.sample.Invalidate();
}
}
public void ThreadProc()
{
TrainSelfOrganizingMap train = new TrainSelfOrganizingMap(
this.network, this.trainingSet, TrainSelfOrganizingMap.LearningMethod.SUBTRACTIVE, 0.5);
int tries = 1;
do
{
train.Iteration();
this.txtTries.Text = "" + tries;
this.txtBestError.Text = "" + train.BestError;
this.txtLastError.Text = "" + train.TotalError;
tries++;
Application.DoEvents();
} while (train.TotalError > 0.01 && (tries <= 100));
MessageBox.Show("Training complete.");
}
/**
* Used to map neurons to actual letters.
*
* #return The current mapping between neurons and letters as an array.
*/
public char[] mapNeurons()
{
char[] map = new char[this.letters.Items.Count];
for (int i = 0; i < map.Length; i++)
{
map[i] = '?';
}
for (int i = 0; i < this.letters.Items.Count; i++)
{
double[] input = new double[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
char ch = ((string)(this.letters.Items[i]))[0];
bool[] data = this.letterData[ch];
for (int j = 0; j < input.Length; j++)
{
input[j] = data[j] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
map[best] = ch;
}
return map;
}
}
Dictionary<> is created in a such way that you can access Key Value pair in most efficient way. Now in Dictionary<> you can not have two pairs with same key. To do so,
what you can do, you create a dictionary like Dictionary<char, List<bool[]>>, now in this dictionary you can store one key with more than one value.
Update
If you change the dictionary to Dictionary<char, List<bool[]>> then to store one key with more than one value you will have to as follows
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
//
// Your Code
//
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() { this.downsampled });
}
this.letters.Items.Add(Result);
this.ClearEntry();
}
}
If you want to string as key, instead of char, use Dictionary<string, List<bool[]>>.
Hope this answers your question.
Take a look at the Lookup class in .Net. This lets you have the same "key" value multiple times.

Reporting progress of a LINQ query with background worker, how?

I am exprementing an application which prints out all the possible multiplies of integers in an array that equals size of the array:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int progress = 0;
int toCheck = int.Parse(textBox2.Text); //Number to check for
int[] array = new int[toCheck];
//Fill the array
for (int i = 0; i < toCheck; i++)
{
array[i] = i;
bgw.ReportProgress(progress);
progress += 1;
}
var result =
from i1 in array
from i2 in array
where i1 * i2 == toCheck
let square = i1 * i2
select new { i1, i2, square }; //how to report progress here?
foreach (var res in result)
{
textBox1.Text += res.i1 + " * " + res.i2 + " = " + res.square + Environment.NewLine;
bgw.ReportProgress(progress);
progress += 1;
}
}
The linq query itself is very time consuming specially if a big number should be checked for. Is there a way to report the progress of the linq query? Or I should leave linq and do this old-school mode?
Update
This is my whole code. The progressbard does not fill after it got half-full. The first half is when the array is being created, the second part is when code tries to perform the linq query (That is why I think the reporting should be done in the linq query!) pardon my stupidity!!!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace BGWorkerTest
{
public partial class Form1 : Form
{
private PerformanceCounter cpuCounter;
private PerformanceCounter ramCounter;
string[] diagnosticInfo = new string[2] { string.Empty, string.Empty };
int toCheck = 0;
StringBuilder sb;
public Form1()
{
InitializeComponent();
//Diagnostics
cpuCounter = new PerformanceCounter();
cpuCounter.CategoryName = "Processor";
cpuCounter.CounterName = "% Processor Time";
cpuCounter.InstanceName = "_Total";
ramCounter = new PerformanceCounter("Memory", "Available KBytes");
}
private string[] GetDiagnostics()
{
diagnosticInfo[0] = string.Format("{0:0.##}", cpuCounter.NextValue()) + "%";
diagnosticInfo[1] = ramCounter.NextValue() + "MB";
return diagnosticInfo;
}
private void timerStStr_Tick(object sender, EventArgs e)
{
string[] temp = new string[2] { "", ""};
temp = GetDiagnostics();
ststrLabelCpu.Text = temp[0];
ststrLabelMem.Text = temp[1];
}
private void button1_Click(object sender, EventArgs e)
{
ststrProgBar.Minimum = 0;
ststrProgBar.Maximum = 0;
toCheck = int.Parse(textBox2.Text);
ststrProgBar.Minimum = 0;
ststrProgBar.Maximum = toCheck * 2;
ststrProgBar.Step = 1;
//Starts the backgroundworker process asynchronously
bgw.RunWorkerAsync();
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int progress = 0;
int[] array = new int[toCheck + 1];
for (int i = 0; i < toCheck + 1; i++)
{
array[i] = i;
bgw.ReportProgress(progress);
progress += 1;
}
var result =
from i1 in array
from i2 in array
where i1 * i2 == toCheck
let square = i1 * i2
select new { i1, i2, square };
sb = new StringBuilder();
foreach (var res in result)
{
sb.AppendLine(res.i1 + " * " + res.i2 + " = " + res.square);
bgw.ReportProgress(progress);
progress += 1;
Application.DoEvents();
}
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ststrProgBar.PerformStep();
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Operation Cancelled");
}
else
{
MessageBox.Show("Operation Completed");
textBox1.Text = sb.ToString();
}
}
}
}
var result =
from int i1 in array
from int i2 in array
where i1 * i2 == toCheck
let square = getSquare(i1,i2)
select new { i1, i2, square };
And then create the method:
public static int getSquare(int i, int i2)
{
Console.WriteLine("busy {0}", i);
return i * i2;
}
just change Console.WriteLine("busy {0}", i); to whatever you want to report
You could try this:
private static IEnumerable<T> ActAsEnumerated<T>(this IEnumerable<T> source, Action<T> act)
{
foreach(var t in source)
{
act(t);
yield return t;
}
}
Usage could be something like:
var pairs = from i1 in array from i2 in array select new { int1 = i1, int2 = i2 };
var reportPairs = pairs.ActAsEnumerated(p => { bgw.ReportProgress(progress); progress += 1; });
var result =
from pair in reportPairs
where pair.int1 * pair.int2 == toCheck
let square = pair.int1 * pair.int2
select new { pair.int1, pair.int2, square };
which is really not very pretty. Really, I think you'd be better off doing this in a non-Linq fashion.

Categories

Resources