How to handle: Argument out of range? - c#

When I load a picture in the picturebox and don't click on the picturebox first it break.
When I put the return back in the code it goes to an endless loop and when I remove it the code breaks.
Here is the code. It always breaks at point1 and I dont know how to handle it.
private void buttonNoiseAvr_Click(object sender, EventArgs e)
{
Point Zeko = new Point(25, 25);
if (pictureBoxSourcePicture.Image == null)
{
MessageBox.Show("No picture loaded");
return;
}
if (pictureBoxSourcePicture.Height != clickedY || pictureBoxSourcePicture.Width != clickedX)
{
MessageBox.Show("Adeekll");
//return;
}
Color oPoint = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX, clickedY);
Color point1 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX - 1, clickedY - 1);
Color point2 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX, clickedY - 1);
Color point3 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX + 1, clickedY - 1);
Color point4 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX - 1, clickedY + 1);
Color point5 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX, clickedY + 1);
Color point6 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX + 1, clickedY + 1);
Color point7 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX - 1, clickedY);
Color point8 = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX + 1, clickedY);
//int[] XOR = new int[] { oPoint.R };
//int[] XOG = new int[] { oPoint.G };
//int[] XOB = new int[] { oPoint.B };
int[] XR = new int[] { point1.R, point2.R, point3.R, point4.R, point5.R, point6.R, point7.R, point8.R };
int[] XG = new int[] { point1.G, point2.G, point3.G, point4.G, point5.G, point6.G, point7.G, point8.G };
int[] XB = new int[] { point1.B, point2.B, point3.B, point4.B, point5.B, point6.B, point7.B, point8.B };
double SumRed = 0;
double SumGreen = 0;
double SumBlue = 0;
for (int i = 0; i < XR.Length; i++)
{
SumRed += (Math.Abs(oPoint.R - XR[i])) * (Math.Abs(oPoint.R - XR[i]));
SumGreen += (Math.Abs(oPoint.G - XG[i])) * (Math.Abs(oPoint.G - XG[i]));
SumBlue += (Math.Abs(oPoint.B - XB[i])) * (Math.Abs(oPoint.B - XB[i]));
}
MessageBox.Show("The Average Difference of Red is = "
+ Math.Sqrt(SumRed) + "\n"
+ "The Average Difference of Green is = "
+ Math.Sqrt(SumGreen) + "\n"
+ "The Average Difference of Blue is = "
+ Math.Sqrt(SumBlue) + "\n");
}

You can calculate your points as follow:
Color[] points = new Color[8];
int[] xPos = { -1, 0, 1, -1, 0, 1, -1, 1 };
int[] yPos = { -1, -1, -1, 1, 1, 1, 0, 0 };
for (int i = 0; i < 8; i++)
points[i] = ((Bitmap)pictureBoxSourcePicture.Image).GetPixel(clickedX + xPos[i], clickedY + yPos[i]);
And then calculate the sumRed, sumGreen and SumBlue:
for (int i = 0; i < points.Length; i++)
{
SumRed += Math.Pow( (Math.Abs(oPoint.R - points[i].R)),2);
SumGreen += Math.Pow((Math.Abs(oPoint.R - points[i].G)), 2);
SumBlue += Math.Pow((Math.Abs(oPoint.R - points[i].B)), 2);
}
It's more short and easy to understand.
Hope this will be useful

Related

C# mouse events on autoclicker failing randomly

I'm writing a small program to automate clicks on a browser game. Using the code bellow the mouse always moves to the right location, however the click on the button only works about 50% of the times. Why does it not work every time and how do i fix it?
EDIT: Here is the updated code (2 methods about image recognition left in blank due to code block size restrictions):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CICautoplayer
{
public partial class CICplayer : Form
{
public CICplayer()
{
InitializeComponent();
}
[DllImport("user32.dll", EntryPoint = "SetCursorPos")]
private static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")]
public static extern void mouse_event(int dwflags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
Random rnd = new Random();
bool run = false;
int[] corner = new int[] { 0, 0 };
int[] pos = new int[] { 0, 0 };
int level = 0;
string[] logbook = new string[9] { " ", " ", " ", " ", " ", " ", " ", " ", " " };
private void runner()
{
while (run)
{
// =================================================================== identify level
bool n1found = false;
bool n2found = false;
int n1 = 9;
int n2 = 9;
while (!n1found)
{
string name = "n" + n1.ToString();
pos = new int[] { 0, 0 };
pos = position_of_level(name, corner[0] + 0, corner[0] + 15, corner[1] + 10, corner[1] + 40);
if (pos[0] > 0 && pos[1] > 0) { n1found = true; }
else if (n1 > 0) { n1--; }
else { n1found = true;}
}
while (!n2found)
{
string name = "n" + n2.ToString();
pos = new int[] { 0, 0 };
pos = position_of_level(name, corner[0] + 15, corner[0] + 40, corner[1] + 10, corner[1] + 40);
if (pos[0] > 0 && pos[1] > 0){ n2found = true; }
else if (n2 > 0) { n2--; }
else { n2found = true; n2 = 1000; }
}
level = n1 * 10 + n2;
addentry("LVL " + level.ToString() + " => ");
// ================================================================ target rewards
if (level > 5)
{
click_on(new int[] { corner[0] + 20, corner[1] + 20 });
Thread.Sleep(1100 + rnd.Next(1, 100));
//string[] targetlist = new string[] { "saltpeter", "jewels", "tools", "magnificent", "steel", "bolts", "diamond", "lore"};
string[] targetlist = new string[] { "saltpeter", "jewels", "magnificent", "bolts", "diamond", "lore" };
int[] temp_pos = new int[] { 0, 0 };
temp_pos = position_of("corner_slider", corner[0] + 200, corner[0] + 250, corner[1] + 250, corner[1] + 550);
bool chosen = false;
int n = 0;
while (n < targetlist.Count() && !chosen)
{
pos = new int[] { 0, 0 };
pos = position_of(targetlist[n], temp_pos[0] + 200, temp_pos[0] + 550, temp_pos[1], temp_pos[1] + 50);
if (pos[0] != 0 && pos[1] != 0)
{
click_on(new int[] { pos[0] + 10, pos[1] + 10 });
chosen = true;
}
n++;
}
if (chosen)
{
addentry("Rwrd: " + targetlist[n - 1] + " => ");
}
else
{
addentry("Rwrd: NONE! => ");
}
// fecher o menu das rewards
Thread.Sleep(1000 + rnd.Next(1, 100));
click_on(new int[] { corner[0] + 50, corner[1] + 400 });
}
// =============================================================== wait time
int wtime = 0;
if (level < 30) { wtime = 4000 + level * 200;
} else if (level < 60)
{
wtime = 10000 + level * 250;
} else
{
wtime = 25000;
}
addentry("Wait: " + (wtime/1000).ToString() + " sec => ");
Thread.Sleep(wtime);
// ================================================================ reset
if (run) // condition in case the stop button is pressed meanwhile
{
addentry("reseting... \r\n");
click_on(new int[] { corner[0] + 20, corner[1] + 20 });
Thread.Sleep(2000 + rnd.Next(1, 500));
// select restart
int[] p_but = new int[] { 0, 0 };
p_but = position_of("button_restart", corner[0] + 450, corner[0] + 550, corner[1] + 200, corner[1] + 400);
p_but[0] += 10; p_but[1] += 10;
click_on(p_but);
Thread.Sleep(4000 + rnd.Next(1, 500));
click_on(new int[] { corner[0] + 700, corner[1] + (level < 6 ? 335 : 385)});
Thread.Sleep(5000);
}
}
}
public void click_on(int[] coor)
{
SetCursorPos(coor[0], coor[1]);
Application.DoEvents();
mouse_event(MOUSEEVENTF_LEFTDOWN, coor[0], coor[1], 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, coor[0], coor[1], 0, 0);
}
private void addentry(string text)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(addentry), new object[] { text });
return;
}
for (int i = 0; i < 8; i++) { logbook[i] = logbook[i + 1]; }
logbook[8] = text;
logtext.Text = "";
for (int i = 0; i < 9; i++)
{
logtext.Text += logbook[i];
}
}
private int[] position_of(string what, int xmin, int xmax, int ymin, int ymax)
{
// code to identify a picture in a specified area of the screen
// returns int[2] with the coordinates
}
private int[] position_of_level(string what, int xmin, int xmax, int ymin, int ymax)
{
// code to identify a number in a specified area of the screen
// returns int[2] with the coordinates
}
private void but_play_Click(object sender, EventArgs e)
{
Thread.Sleep(3000);
corner = position_of("corner", 0, 500, 0, 600);
addentry("Corner found at " + corner[0].ToString() + " , " + corner[1].ToString() + "\r\n");
run = true;
var thread = new Thread(new ThreadStart(runner));
thread.Start();
}
private void but_stop_Click(object sender, EventArgs e)
{
run = false;
}
}
}

Write 3 arrays to 1

I have 3 arrays: x, y and z. How can I write all three to one in one-after-one mode?
For example: I have X=1,2 Y=3,4 Z=5,6
I need an array W = X[1],Y[1],Z[1],X[2],Y[2],Z[2] ... X[n],Y[n],Z[n]
float[] posX = new float[rmv2.lod[0].VerticesCount[0]];
float[] posY = new float[rmv2.lod[0].VerticesCount[0]];
float[] posZ = new float[rmv2.lod[0].VerticesCount[0]];
for (int i = 0; i < 1; i += 3)
{
posX[i] = rmv2.lod[0].Mesh[0].Vertex[i].X;
posY[i + 1] = rmv2.lod[0].Mesh[0].Vertex[i].Y;
posZ[i + 2] = rmv2.lod[0].Mesh[0].Vertex[i].Z;
}
I don't see the w array you're trying to write the output to. Are you looking for something like this?
int n = rmv2.lod[0].VerticesCount[0];
float[] posX = new float[n];
float[] posY = new float[n];
float[] posZ = new float[n];
float[] w = new float[n * 3];
for (int i = 0; i < n; i++)
{
posX[i] = rmv2.lod[0].Mesh[0].Vertex[i].X;
posY[i] = rmv2.lod[0].Mesh[0].Vertex[i].Y;
posZ[i] = rmv2.lod[0].Mesh[0].Vertex[i].Z;
w[i * 3 + 0] = rmv2.lod[0].Mesh[0].Vertex[i].X;
w[i * 3 + 1] = rmv2.lod[0].Mesh[0].Vertex[i].Y;
w[i * 3 + 2] = rmv2.lod[0].Mesh[0].Vertex[i].Z;
}
Perhaps you should look at jagged arrays...
https://msdn.microsoft.com/en-us/library/2s05feca.aspx
Try this:
float[] x = new float[] { 1, 2, 9 };
float[] y = new float[] { 3, 4 };
float[] z = new float[] { 5, 6 };
int max = Math.Max(x.Length, Math.Max(y.Length, z.Length));
List<float> combined = new List<float>();
for (int i = 0; i < max; i++)
{
if (x.Length > i) combined.Add(x[i]);
if (y.Length > i) combined.Add(y[i]);
if (z.Length > i) combined.Add(z[i]);
}
Produces a list with the combined arrays, regardless of their original lengths.
1, 3, 5, 2, 4, 6, 9
If I right understand you, try this solution. With this method arrays can have different length
static T[] ConcatOneAfterOne<T>(params T[][] arrays)
{
int outputArrayLength = 0;
for (int i = 0; i < arrays.Length; i++)
{
outputArrayLength += arrays[i].Length;
}
T[] output = new T[outputArrayLength];
int outputIndex = 0;
int sourceIndex = 0;
while (outputIndex != outputArrayLength)
{
for (int arrayIndex = 0; arrayIndex < arrays.Length; arrayIndex++)
{
if (sourceIndex < arrays[arrayIndex].Length)
{
output[outputIndex++] = arrays[arrayIndex][sourceIndex];
}
}
sourceIndex++;
}
return output;
}
[Test]
static void ConcatOneAfterOneTest()
{
int[] result = ConcatOneAfterOne(new[] { 1, 2 }, new[] { 3, 4 }, new[] { 5, 6 });
CollectionAssert.AreEqual(new int[] { 1, 3, 5, 2, 4, 6 }, result);
}

How to add up the numbers in a row and display them in C#?

I'm using C# and Microsoft Visual Studio. I'm able to display my array through this code:
private void btnDisplay_Click(object sender, EventArgs e)
{
double[,] initialArray = new double[3, 4] { { 5, 1, 9, 3 }, { 7, 8, 6, 4 }, { 2, 4, 9, 5 } };
string rowOfInts = "";
string columnsAndRow = "";
for (int r = 0; r < initialArray.GetLength(0); r++)
{
string tempString = "";
for (int c = 0; c < initialArray.GetLength(1); c++)
{
rowOfInts = tempString + " " + initialArray[r, c];
tempString = rowOfInts;
}
columnsAndRow = columnsAndRow + rowOfInts + "\n";
lblDisplay.Text = Convert.ToString(columnsAndRow);
}
// displays Display = new displays(initialArray, rowOfInts, columnsAndRow);
if (chkRowTotals.Checked == true)
{
for (int r = 0; r < initialArray.GetLength(0); r++)
{
int intTotal = 0;
string tempString = "";
for (int c = 0; c <initialArray.GetLength(1); c++)
{
rowOfInts = tempString + " " + initialArray[r, c];
tempString = rowOfInts;
}
columnsAndRow = columnsAndRow + rowOfInts;
intTotal += Convert.ToInt32(columnsAndRow);
lblDisplay.Text = Convert.ToString(intTotal);
}
}
}
but I don't know how to add the numbers by rows. Is there any way that I can total the numbers in my array by row and then display them in my label (lblDisplay)?
edit: I don't want the entire array added up- just the rows. So, the output would be 18, 25, and 20.
There are many things wrong in your code, to be completely honest. I will just put what I think is the solution you are looking for:
private void Button_Click(object sender, RoutedEventArgs e)
{
double[,] initialArray = new double[3, 4] { { 5, 1, 9, 3 }, { 7, 8, 6, 4 }, { 2, 4, 9, 5 } };
string rowOfInts = "";
string columnsAndRow = "";
for (int r = 0; r < initialArray.GetLength(0); r++)
{
string tempString = "";
double inttotal = 0;
for (int c = 0; c < initialArray.GetLength(1); c++)
{
rowOfInts = tempString + " " + initialArray[r, c];
tempString = rowOfInts;
inttotal += initialArray[r, c];
}
columnsAndRow = columnsAndRow + rowOfInts + " row total of = " + inttotal.ToString() + "\n";
}
txtbx.Text = Convert.ToString(columnsAndRow);
}
Something to the effect of:
const int numRows = 3;
const int numColumns = 4;
double[,] initialArray = new double[numRows, numColumns] { { 5, 1, 9, 3 }, { 7, 8, 6, 4 }, { 2, 4, 9, 5 } };
double[] rowTotal = new double[numRows];
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < numColumns; j++)
{
rowTotal[i] += initialArray[i, j];
}
Console.WriteLine("Current row total: {0}", rowTotal[i]);
}
Try this:
var initialArray = new double[3, 4] { { 5, 1, 9, 3 }, { 7, 8, 6, 4 }, { 2, 4, 9, 5 } };
// List that will hold the sum of each row
List<double> rowSums = new List<double>();
for (int i = 0; i < initialArray.GetLength(0); i++)
{
// accumulator
double rowSum = 0;
for (int j = 0; j < initialArray.GetLength(1); j++)
{
rowSum += initialArray[i, j];
}
// add the row sum to our list
rowSums.Add(rowSum);
}
// will put "18, 25, 20" in your label's Text
lblDisplay.Text = string.Join(", ", rowSums);
You should consider using a flattening your array as it has better performance.
You can use the following Linq:
var numberOfRows = initialArray.GetLength(0);
var numberOfColumns = initialArray.GetLength(1);
var sumOfRows = Enumerable
.Range(0, numberOfRows)
.Select(r => Enumerable.Range(0, numberOfColumns).
Aggregate(0d, (a, i) => a += initialArray[r, i]));
lblDisplay.Text = string.Join(", ", sumOfRows);
However, it might be a lot easier to use a Jagged array instead. The Linq expression would be a lot easier.

How to draw a rectangle in console application?

I need to draw a rectangle, with a number inside, in a C# console app and using extended ASCII. How do I go about it?
This is for a demo.
public class ConsoleRectangle
{
private int hWidth;
private int hHeight;
private Point hLocation;
private ConsoleColor hBorderColor;
public ConsoleRectangle(int width, int height, Point location, ConsoleColor borderColor)
{
hWidth = width;
hHeight = height;
hLocation = location;
hBorderColor = borderColor;
}
public Point Location
{
get { return hLocation; }
set { hLocation = value; }
}
public int Width
{
get { return hWidth; }
set { hWidth = value; }
}
public int Height
{
get { return hHeight; }
set { hHeight = value; }
}
public ConsoleColor BorderColor
{
get { return hBorderColor; }
set { hBorderColor = value; }
}
public void Draw()
{
string s = "╔";
string space = "";
string temp = "";
for (int i = 0; i < Width; i++)
{
space += " ";
s += "═";
}
for (int j = 0; j < Location.X ; j++)
temp += " ";
s += "╗" + "\n";
for (int i = 0; i < Height; i++)
s += temp + "║" + space + "║" + "\n";
s += temp + "╚";
for (int i = 0; i < Width; i++)
s += "═";
s += "╝" + "\n";
Console.ForegroundColor = BorderColor;
Console.CursorTop = hLocation.Y;
Console.CursorLeft = hLocation.X;
Console.Write(s);
Console.ResetColor();
}
}
This is an extension method to String, which will draw a console box around a given string. Multi-line support included.
i.e.
string tmp = "some value"; Console.Write(tmp.DrawInConsoleBox());
public static string DrawInConsoleBox(this string s)
{
string ulCorner = "╔";
string llCorner = "╚";
string urCorner = "╗";
string lrCorner = "╝";
string vertical = "║";
string horizontal = "═";
string[] lines = s.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int longest = 0;
foreach(string line in lines)
{
if (line.Length > longest)
longest = line.Length;
}
int width = longest + 2; // 1 space on each side
string h = string.Empty;
for (int i = 0; i < width; i++)
h += horizontal;
// box top
StringBuilder sb = new StringBuilder();
sb.AppendLine(ulCorner + h + urCorner);
// box contents
foreach (string line in lines)
{
double dblSpaces = (((double)width - (double)line.Length) / (double)2);
int iSpaces = Convert.ToInt32(dblSpaces);
if (dblSpaces > iSpaces) // not an even amount of chars
{
iSpaces += 1; // round up to next whole number
}
string beginSpacing = "";
string endSpacing = "";
for (int i = 0; i < iSpaces; i++)
{
beginSpacing += " ";
if (! (iSpaces > dblSpaces && i == iSpaces - 1)) // if there is an extra space somewhere, it should be in the beginning
{
endSpacing += " ";
}
}
// add the text line to the box
sb.AppendLine(vertical + beginSpacing + line + endSpacing + vertical);
}
// box bottom
sb.AppendLine(llCorner + h + lrCorner);
// the finished box
return sb.ToString();
}
Output like this
Like this?
This worked for me:
Console.OutputEncoding = Encoding.GetEncoding(866);
Console.WriteLine("┌─┐");
Console.WriteLine("│1│");
Console.WriteLine("└─┘");
[EDIT]
Answer to the sub-question in the comment:
Console.OutputEncoding = Encoding.GetEncoding(866);
Console.WriteLine(" ┌─┐");
Console.WriteLine(" │1│");
Console.WriteLine("┌─┼─┘");
Console.WriteLine("│1│");
Console.WriteLine("└─┘");
You can use CsConsoleFormat† to draw with ASCII border symbols in console.
Drawing a number within a rectangle with "double" lines:
ConsoleRenderer.RenderDocument(
new Document()
.AddChildren(
new Border {
Stroke = LineThickness.Wide,
Align = HorizontalAlignment.Left
}
.AddChildren(1337)
)
);
You can change Stroke = LineThickness.Wide line to change the style of lines. LineThickness.Single would produce thin single lines, new LineThickness(LineWidth.Single, LineWidth.Wide) would produce single vertical and double horizontal lines.
Here's what it looks like:
You can also use ConsoleBuffer class to draw lines explicitly (argument names added for clarity):
using static System.ConsoleColor;
var buffer = new ConsoleBuffer(width: 6);
buffer.DrawHorizontalLine(x: 0, y: 0, width: 6, color: White);
buffer.DrawHorizontalLine(x: 0, y: 2, width: 6, color: White);
buffer.DrawVerticalLine(x: 0, y: 0, height: 3, color: White);
buffer.DrawVerticalLine(x: 5, y: 0, height: 3, color: White);
buffer.DrawString(x: 1, y: 1, color: White, text: "1337");
new ConsoleRenderTarget().Render(buffer);
† CsConsoleFormat was developed by me.
Problem with above code is extra spaces, if you draw multiple rectangles, it causes mess.
here is a code which draw rectangles recursively without extra spaces.
public class AsciDrawing
{
public static void TestMain() {
var w = Console.WindowWidth;
var h = Console.WindowHeight;
RecursiveDraw(16, 8, new Point(w/2-8, h/2-4), ConsoleColor.Black);
Console.CursorTop = h;
Console.CursorLeft = 0;
}
public static void RecursiveDraw(int Width, int Height, Point Location, ConsoleColor BorderColor) {
if(Width < 4 || Height < 2) return;
Draw(Width, Height, Location, BorderColor); //Commnet this draw and and Uncomment Draw bellow to see the difference.
Thread.Sleep(500);
//Comment or Uncomment to see how many recursive calls you want to make
//The best is to comment all execpt 1 and then uncomment 1 by 1
RecursiveDraw(Width/2, Height/2, new Point(Location.X-Width/4, Location.Y-Height/4), ConsoleColor.Green); //Left Top
RecursiveDraw(Width / 2, Height / 2, new Point(Location.X + 3* Width / 4, Location.Y + 3* Height / 4), ConsoleColor.Red); //Right Bottom
RecursiveDraw(Width / 2, Height / 2, new Point(Location.X + 3* Width / 4, Location.Y - Height / 4), ConsoleColor.Blue); //Right Top
RecursiveDraw(Width / 2, Height / 2, new Point(Location.X - Width / 4, Location.Y + 3* Height / 4), ConsoleColor.DarkMagenta); // Left Bottom
//Draw(Width, Height, Location, BorderColor);
}
public static void Draw(int Width, int Height, Point Location, ConsoleColor BorderColor)
{
Console.ForegroundColor = BorderColor;
string s = "╔";
string temp = "";
for (int i = 0; i < Width; i++)
s += "═";
s += "╗" + "\n";
Console.CursorTop = Location.Y;
Console.CursorLeft = Location.X;
Console.Write(s);
for (int i = 0; i < Height; i++) {
Console.CursorTop = Location.Y + 1 + i;
Console.CursorLeft = Location.X;
Console.WriteLine("║");
Console.CursorTop = Location.Y + 1 + i;
Console.CursorLeft = Location.X + Width+1;
Console.WriteLine("║");
}
s = temp + "╚";
for (int i = 0; i < Width; i++)
s += "═";
s += "╝" + "\n";
Console.CursorTop = Location.Y+Height;
Console.CursorLeft = Location.X;
Console.Write(s);
Console.ResetColor();
}
}
public record Point(int X, int Y);

reading a barcode with a webcam

Hey,
I'm trying to read a EAN-13 barcode from my webcam.
I already wrote a class to do that work.
I'm taking a picture from my webcam, trimming it to show ONLY the barcode,
and reading the barcode with the code tables from wikipedia.
For some reason, the barcode gets trimmed, but the output is always "0-1-1-1-1-1-1-1-1-1-1-1-1".
I wonder if i did any stupid mistake or misunderstood something?
I do not want to use ANY third-party programs!
this is my code for now:
public class BarcodeDecoder
{
static string[] ligerade = new string[] { "0100111", "0110011", "0011011", "0100001", "0011101", "0000101", "0010001", "0001001", "0010111" };
static string[] rechtsgerade = new string[ligerade.Length];
static string[] liungerade = new string[ligerade.Length];
static string[] GeradeUG = new string[] { "UUUUUU", "UUGUGG", "UUGGUG", "UUGGGU", "UGUUGG", "UGGUUG", "UGGGUU", "UGUGUG", "UGUGGU", "UGGUGU" };
static int[] links;
static int[] rechts;
static string result;
public static string Decode(Bitmap b)
{
result = "";
Bitmap bb = CutOutOf(b, b.Height / 2);
bb = trimBitmap(bb);
int[] lgs = GetNumberOutOf(bb);
int[][] rr = trimArray(lgs);
links = rr[0];
rechts = rr[1];
FillArrays();
BearbeiteLinks();
BearbeiteRechts();
return result;
}
static void BearbeiteLinks()
{
string GU = "";
string[] zahlen = new string[6];
zahlen[0] = OutOfArray(links, 0, 7);
zahlen[1] = OutOfArray(links, 7, 7);
zahlen[2] = OutOfArray(links, 14, 7);
zahlen[3] = OutOfArray(links, 21, 7);
zahlen[4] = OutOfArray(links, 28, 7);
zahlen[5] = OutOfArray(links, 35, 7);
foreach (string pq in zahlen)
{
bool gerade = ligerade.ToList().IndexOf(pq) > -1;
if (gerade)
{
result += ligerade.ToList().IndexOf(pq).ToString();
GU += "G";
}
else
{
result += liungerade.ToList().IndexOf(pq).ToString();
GU += "U";
}
}
result = GeradeUG.ToList().IndexOf(GU).ToString() + result;
}
static void BearbeiteRechts()
{
string[] zahlen = new string[6];
zahlen[0] = OutOfArray(rechts, 0, 7);
zahlen[1] = OutOfArray(rechts, 7, 7);
zahlen[2] = OutOfArray(rechts, 14, 7);
zahlen[3] = OutOfArray(rechts, 21, 7);
zahlen[4] = OutOfArray(rechts, 28, 7);
zahlen[5] = OutOfArray(rechts, 35, 7);
foreach (string pq in zahlen)
{
result += rechtsgerade.ToList().IndexOf(pq).ToString();
}
}
static string OutOfArray(int[] ar, int startindex, int length)
{
int[] gar = new int[length];
Array.Copy(ar, startindex, gar, 0, length);
StringBuilder bilder = new StringBuilder();
for (int i = 0; i < gar.Length; i++)
{
bilder.Append(gar[i].ToString());
}
return bilder.ToString();
}
static Bitmap trimBitmap(Bitmap b)
{
bool alreadyBlack = false;
int firstblack = 0;
for (int i = 0; i < b.Width; i++)
{
Color gp = b.GetPixel(i, 0);
if ((gp.R + gp.G + gp.B) / 3 < 128)
{
if (!alreadyBlack)
{
alreadyBlack = true;
firstblack = i;
}
}
}
bool alreadyblack = false;
int lastblack = 0;
for (int i = b.Width -1; i > 0; i--)
{
Color gpp = b.GetPixel(i, 0);
if ((gpp.R + gpp.G + gpp.B) / 3 < 128)
{
if (!alreadyblack)
{
alreadyblack = true;
lastblack = i;
}
}
}
Bitmap result = new Bitmap(lastblack - firstblack, 1);
for (int i = firstblack; i < lastblack; i++)
{
Color c = b.GetPixel(i, 0);
result.SetPixel(i - firstblack, 0, c);
}
result.Save("C:\\result.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
return result;
}
static int[][] trimArray(int[] ar)
{
int[][] res = new int[2][];
int[] resl = new int[6 * 7];
int[] resr = new int[6 * 7];
Array.Copy(ar, 2, resl, 0, 6 * 7);
Array.Copy(ar, 2 + 6 * 7 + 5, resr, 0, 6 * 7);
res[0] = resl;
res[1] = resr;
return res;
}
static void FillArrays()
{
for (int i = 0; i < ligerade.Length; i++)
{
rechtsgerade[i] = string.Concat(ligerade[i].Reverse());
}
for (int x = 0; x < liungerade.Length; x++)
{
liungerade[x] = Invert(rechtsgerade[x]);
}
}
static string Invert(string xx)
{
string xs = "";
for (int y = 0; y < xx.Length; y++)
{
int fd = int.Parse(xx[y].ToString());
if (fd == 0)
fd = 1;
else
fd = 0;
xs += fd.ToString();
}
return xs;
}
static Bitmap CutOutOf(Bitmap b, int y)
{
Bitmap res = new Bitmap(b.Width, 1);
for (int i = 0; i < b.Width; i++)
{
Color c = b.GetPixel(i, y);
res.SetPixel(i, 0, c);
}
return res;
}
static int[] GetNumberOutOf(Bitmap bb)
{
List<int> intlst = new List<int>();
float f = (float)bb.Width / 95.0f;
float wd = f / 2.0f;
for (float i = wd; i < bb.Width; i+=f)
{
Color c = bb.GetPixel((int)Math.Round(i,0), 0);
intlst.Add(GetOutOfColor(c));
}
return intlst.ToArray();
}
static int GetOutOfColor(Color c)
{
if (c.A + c.B + c.R > 128 * 3)
{
return 0;
}
return 1;
}
}
Sorry for german names in the code!
I see two problems:
1) You only scan the top most pixel row of your image (see the second parameter of GetPixel). Your barcode is probably in the middle of the image and not at the top.
Color c = bb.GetPixel((int)Math.Round(i,0), 0);
2) Instead of the green component, you take the alpha component to convert the colored pixel into a binary value. Since the alpha component is probably always 255, you always get 0 unless you have a very dark pixel.
if (c.A + c.B + c.R > 128 * 3)

Categories