Jump to content

C# - Odd bug


Delscid

Recommended Posts

EDIT: Fixed

 

(sorry for the bad post formatting and generally bad code, was just a quick test to see if it worked, will refactor once I actually get it working)

 

I'm working on a little personal project, which is an OCR-driven drop log for Runescape (This never actually interacts with the Runescape client in any way, no input)

 

It's supposed to work by taking a screenshot of the Runescape client, finding any item text (which is done by itterating through each pixel and checking if it matches the item text colour, then converting the result to a pattern) and using OCR to turn this into a string (not the best method for this, but again, to test).

To do this, I'm using patterns of each character in the Runescape font stored with the format:

(Pattern being a boolean representation of each pixel in the image used to generate the pattern, non-white: true, white: false)

ptnformat.png

And itterating over each pixel in the input image and looking for sequences that match the first part of a pattern, then repeating this for the pixels below the matched sequence until there is a part which does not match, or until the pattern is fully matched (yes, I know this is horribly inefficient and I have briefly looked at other OCR libraries, most of the ones which have the features I need have memory leak issues though).

 

Currently, its only a test to make sure I can actually read text.

 

One part of the code which searches for a matching sequence is giving an odd bug which I can't find the source of anywhere...

 

GetCharacters:

private char[] GetCharacters(bool[] value, SearchPattern[] patterns)
{
List<char> characters = new List<char>();

// Itterate over each pixel in the input image sequence.
for (int i = 0; i < value.Length; i++)
{
   	foreach (SearchPattern p in patterns)
   	{
       	// Check if there is a match for the first line of the search pattern.
       	if (p.IsMatch(0, value.Skip(i).Take(p.Lines[0].Length).ToArray())) // <-- Line where it fails.
       	{
           	// Check each line of the pattern for a match.
           	for (int l = 1; l < p.Height; l++)
           	{
               	int offset = 0;
               	bool isMatch = p.IsMatch(l, value.Skip(i + offset + (loadedImage.Width - p.Width)).Take(p.Lines[l].Length).ToArray()); // <-- May fail
               	if (isMatch && l == p.Height - 1)
               	{
                   	characters.Add(p.Character);
                   	break;
               	}
               	else if (isMatch)
               	{
                   	offset += (loadedImage.Width - p.Width);
               	}
               	else
               	{
                   	break;
               	}
           	}
       	}
   	}
}

return characters.ToArray();
}

The call

p.IsMatch(0, value.Skip(i).Take(p.Lines[0].Length).ToArray())

always fails because of the bug in

SearchPattern.IsMatch

 

loadedImage being a Bitmap object representing the input image.

Skip and Take provided by LINQ.

 

SearchPattern.cs

using System.IO;
using System;

namespace RunescapeOcr
{
public class SearchPattern
{
	public SearchPattern(string path)
	{
		using (BinaryReader reader = new BinaryReader(File.OpenRead(path)))
		{
			this.Character = reader.ReadChar();
			this.Width = reader.ReadInt32();
			this.Height = reader.ReadInt32();

			int sequenceLength = (int)reader.BaseStream.Length - (int)reader.BaseStream.Position;
			this.Sequence = new bool[sequenceLength];

			for (int i = 0; i < sequenceLength; i++)
			{
				this.Sequence[i] = reader.ReadBoolean();
			}

			this.Lines = GetLines(Width, Height, Sequence);
		}
	}

	public bool IsMatch(int line, bool[] sequence)
	{
		// BUG: This check always fails no matter what I change.
		// For the test, this.Lines[line].Length is 5 (only characters used are both 5 pixels wide)
		// However, even though this.Lines[line].Length is used to select characters in GetCharacters,
		// it always ends up being with sequence.Length being 4 (for this test).
		// if I add 1 to this to get them to match, sequence.Length becomes 5, so the result ends up being 6 instead.
		// I've tried several other things (different operators (e.g. <, >, <=, >=, ==  etc.))
		// but this condition will always change so that it throws an exception.
		if (this.Lines[line].Length != sequence.Length)
			throw new Exception("Sequence lengths do not match");

		for (int i = 0; i < this.Lines[line].Length; i++)
		{
			if (this.Lines[line][i] != sequence[i])
				return false;
		}
		return true;
	}

	protected bool[][] GetLines(int width, int height, bool[] sequence)
	{
		if ((sequence.Length / width) != height)
			throw new Exception("Corrupted Search Pattern.");

		bool[][] lines = new bool[height][];

		for (int h = 0; h < height; h++)
		{
			lines[h] = new bool[width];
			for (int w = 0; w < width; w++)
			{
				lines[h][w] = sequence[(h * width) + w];
			}
		}

		return lines;
	}

	public char Character { get; private set; }

	public int Width { get; private set; }

	public int Height { get; private set; }

	public bool[] Sequence { get; private set; }

	public bool[][] Lines { get; private set; }
}
}

 

I really can't see what is causing this bug... it always happens and seems to change dynamically to any adjustments I make.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.