Signature Comparison

Following the signature capture projects, I decided to make a program that analyzes the signature to see how close two different signatures match.

My first step was create an account on bitbucket.  The reason I chose bitbucket over github was because bitbucket allows for private repros.  Also, I wanted to try out Mercurial.  I installed the most recent version on my machine and then added the VisualHG extension to Visual Studio 2010.  Note that you have to change your source control plug in Visual Studio (Tools –> Source Control)

image

I then was pushing/pulling my repro to bitbucket.  There are still some small things I don’t like (for example, having to enter your credentials each push/pull), but on the whole Mercurial is easier to use in Visual Studio than git and bitbucket is much better than github.

In any event, once I set up my source control, I consolidated all of my projects having to do with this signature series and renamed from things.

image

The once thing I don’t like is that the word ’signature’ is in both the namespace and is a class name – so I get conflicts.  I am not sure what I want to rename the class so I left it ‘as is’ right now.  But as Bob Martin says “with these modern/fancy IDEs, renaming a class should take no time at all.”

I then refactored my object graph:

image

Note that I discarded using System.Drawing.Line and System.Drawing.Point from earlier projects so my analysis program would not have a dependency on System.Drawing.  I spun up the unit tests for line and class in a separate project:

image

and got pretty good code coverage:

image

Note that I didn’t write unit tests for things that the API handles – like the constructor.

With the support classes ready to go, I then tackled the signature analysis.  I first started doing a line analysis – basically starting with a base signature and then layering over a second signature to see how close the lines match.  Because the signatures might be different sizes and on different slopes, I thought I would have to adjust the second signature to match the base’s dimensions.  I would do this by matching the left and top point of both signatures and moving the second one’s lines over to that adjustment factor.

I then realized that I don’t know enough about signature analysis to have “THE” solution to code.  I then adjusted my project to reflect that there might be many different ways to analyze a signature and I should use the power of polymorphism to help me.  I then threw away all of the analysis code that I was working on to get to “THE” solution.

I created an interface called IComparisonFactory like so (note the fully qualified name – I really need to change that)

public interface IComparisonFactory
{
    double CompareSignatures(Tff.Signature.Support.Signature signature1, Tff.Signature.Support.Signature signature2, int levelOfFreedom);
}

I then created an abstract base class that has some functions that do the low level plumbing:

public abstract class BaseComparisonFactory
{

    protected List<Line> GetAllLinesInASignature(Tff.Signature.Support.Signature signature)
    {
        List<Line> lines = new List<Line>();
        List<Glyph> glyphs = signature.Glyphs;
        foreach (Glyph glyph in signature.Glyphs)
        {
            foreach (Line line in glyph.Lines)
            {
                lines.Add(line);
            }
        }

        return lines;
    }
    

    protected List<Point> GetAllPointsInASignature(Tff.Signature.Support.Signature signature)
    {
        List<Point> points = new List<Point>();
        List<Line> lines = GetAllLinesInASignature(signature);
        foreach (Line line in lines)
        {
            points.Add(line.StartPoint);
            points.Add(line.EndPoint);
        }
        return points;
    }
}

I then created my 1st attempt an analyzing two signatures by looking at the dispersal of their points – a scatterplot analysis.

public class ScatterplotComparisonFactory: BaseComparisonFactory, IComparisonFactory
{
    public Double CompareSignatures(Tff.Signature.Support.Signature signature1, Tff.Signature.Support.Signature signature2, Int32 levelOfFreedom)
    {

        Int32 pointTrys = 0;
        Int32 pointHits = 0;

        List<Point> basePoints = GetAllPointsInASignature(signature1);
        List<Point> comparePoints = GetAllPointsInASignature(signature2);

        List<Point> normalizedBasePoints = basePoints.Distinct().ToList<Point>();
        normalizedBasePoints.Sort(ComparePoints); 

        List<Point> normalizedComparePoints = NormalizePoints(comparePoints, levelOfFreedom);
        normalizedComparePoints.Sort(ComparePoints);

        foreach (Point basePoint in normalizedBasePoints)
        {
            foreach (Point comparePoint in normalizedComparePoints)
            {
                if (basePoint == comparePoint)
                {
                    pointHits++;
                    break;
                }
            }
            pointTrys++;
        }

        Double returnValue = ((Double)pointHits / (Double)pointTrys);
        return returnValue;
    }

    private List<Point> NormalizePoints(List<Point> comparePoints, int levelOfFreedom)
    {
        List<Point> normalizedPoints = CreateNormalizedPoints(comparePoints, levelOfFreedom);
        normalizedPoints = RemoveNegativePoints(normalizedPoints);
        return normalizedPoints;
    }

    private List<Point> CreateNormalizedPoints(List<Point> comparePoints, int levelOfFreedom)
    {
        List<Point> normalizedPoints = new List<Point>();
        foreach (Point basePoint in comparePoints)
        {
            normalizedPoints.Add(basePoint);
            for (int i = 1; i <= levelOfFreedom; i++)
            {
                normalizedPoints.Add(new Point(basePoint.X - i, basePoint.Y - i));
                normalizedPoints.Add(new Point(basePoint.X - i, basePoint.Y));
                normalizedPoints.Add(new Point(basePoint.X - i, basePoint.Y + i));
                normalizedPoints.Add(new Point(basePoint.X, basePoint.Y + i));
                normalizedPoints.Add(new Point(basePoint.X + i, basePoint.Y + i));
                normalizedPoints.Add(new Point(basePoint.X + i, basePoint.Y));
                normalizedPoints.Add(new Point(basePoint.X + i, basePoint.Y - 1));
                normalizedPoints.Add(new Point(basePoint.X, basePoint.Y - 1));
            }
        }

        return normalizedPoints;
    }

    private List<Point> RemoveNegativePoints(List<Point> normalizedPoints)
    {
        List<Point> points = new List<Point>();

        foreach (Point point in normalizedPoints)
        {
            if (point.X >= 0 && point.Y >= 0)
            {
                points.Add(point);
            }
        }

        return points;
    }

    private static int ComparePoints(Point point01, Point point02)
    {
        if (point01 == point02)
        {
            return 0;
        }
        if(point01.X == point02.X)
        {
            if (point01.Y < point02.Y)
            {
                return -1;
            }
            else
            {
                return 1;
            }
        }

        if (point01.X < point02.X)
        {
            return -1;
        }
        else
        {
            return 1;
        }

    }

}

Note that the ComparePoints function allows me to call .Sort().

The levelOfFreedom argument takes the second signature’s points and increases them to all adjacent points.  I also remove duplicate points, sort them (first X than Y), and remove any point that is less than zero.

Instead of creating tests for each of the ComparisonFactories that I will create, I created a test class for ICompairisonFactory and injected in the implementation in the constructor.  I then ran the scatterplot though the tests to see if they pass basic analysis (same signature returns 1, etc…).

public class ScatterplotComparisonFactory: BaseComparisonFactory, IComparisonFactory
{
    public Double CompareSignatures(Tff.Signature.Support.Signature signature1, Tff.Signature.Support.Signature signature2, Int32 levelOfFreedom)
    {

        Int32 pointTrys = 0;
        Int32 pointHits = 0;

        List<Point> basePoints = GetAllPointsInASignature(signature1);
        List<Point> comparePoints = GetAllPointsInASignature(signature2);

        List<Point> normalizedBasePoints = basePoints.Distinct().ToList<Point>();
        normalizedBasePoints.Sort(ComparePoints); 

        List<Point> normalizedComparePoints = NormalizePoints(comparePoints, levelOfFreedom);
        normalizedComparePoints.Sort(ComparePoints);

        foreach (Point basePoint in normalizedBasePoints)
        {
            foreach (Point comparePoint in normalizedComparePoints)
            {
                if (basePoint == comparePoint)
                {
                    pointHits++;
                    break;
                }
            }
            pointTrys++;
        }

        Double returnValue = ((Double)pointHits / (Double)pointTrys);
        return returnValue;
    }

    private List<Point> NormalizePoints(List<Point> comparePoints, int levelOfFreedom)
    {
        List<Point> normalizedPoints = CreateNormalizedPoints(comparePoints, levelOfFreedom);
        normalizedPoints = RemoveNegativePoints(normalizedPoints);
        return normalizedPoints;
    }

    private List<Point> CreateNormalizedPoints(List<Point> comparePoints, int levelOfFreedom)
    {
        List<Point> normalizedPoints = new List<Point>();
        foreach (Point basePoint in comparePoints)
        {
            normalizedPoints.Add(basePoint);
            for (int i = 1; i <= levelOfFreedom; i++)
            {
                normalizedPoints.Add(new Point(basePoint.X - i, basePoint.Y - i));
                normalizedPoints.Add(new Point(basePoint.X - i, basePoint.Y));
                normalizedPoints.Add(new Point(basePoint.X - i, basePoint.Y + i));
                normalizedPoints.Add(new Point(basePoint.X, basePoint.Y + i));
                normalizedPoints.Add(new Point(basePoint.X + i, basePoint.Y + i));
                normalizedPoints.Add(new Point(basePoint.X + i, basePoint.Y));
                normalizedPoints.Add(new Point(basePoint.X + i, basePoint.Y - 1));
                normalizedPoints.Add(new Point(basePoint.X, basePoint.Y - 1));
            }
        }

        return normalizedPoints;
    }

    private List<Point> RemoveNegativePoints(List<Point> normalizedPoints)
    {
        List<Point> points = new List<Point>();

        foreach (Point point in normalizedPoints)
        {
            if (point.X >= 0 && point.Y >= 0)
            {
                points.Add(point);
            }
        }

        return points;
    }

    private static int ComparePoints(Point point01, Point point02)
    {
        if (point01 == point02)
        {
            return 0;
        }
        if(point01.X == point02.X)
        {
            if (point01.Y < point02.Y)
            {
                return -1;
            }
            else
            {
                return 1;
            }
        }

        if (point01.X < point02.X)
        {
            return -1;
        }
        else
        {
            return 1;
        }

    }

}

Here is the full suite:

image

Finally, I had everything in place to do an integration test.  I loaded some signatures into XML files and ran them through the integration tests.  Interestingly, the scatterplot seemed to work.

Case #1: Same Signature Compared To Itself (Same Person, Same Signature)

imageimage

returns

0 = 1.0

1= 1.0

2= 1.0

3= 1.0

4= 1.0

5= 1.0

6= 1.0

7= 1.0

8= 1.0

9= 1.0

 

Case #2: Two Signatures That Are Close To Each Other (Same Person, Different Times)

imageimage

0 = 0.0131578947368421

1 = 0.177631578947368

2 = 0.266447368421053

3 = 0.391447368421053

4 = 0.463815789473684

5 = 0.542763157894737

6 = 0.628289473684211

7 = 0.661184210526316

8 = 0.700657894736842

9 = 0.753289473684211

 

Case #3: Two Signatures That Are Not Close (Different People)

clip_image001clip_image001[4]

 

0 = 0

1 = 0.111842105263158

2 = 0.154605263157895

3 = 0.180921052631579

4 = 0.213815789473684

5 = 0.220394736842105

6 = 0.299342105263158

7 = 0.305921052631579

8 = 0.319078947368421

9 = 0.345394736842105

Note that using a 9 point degree of freedom, the same person signature is at 75% matching, but the different person ones are at 35%….

Pretty cool.  Next steps will be the adjust for slope and location on the canvas.  Also, Rob Seder suggested that the Line should include a DateTime stamp, because the meter/pace of someone’s signature is also important.  I’ll add that analysis in too – as well as a line comparison….

Advertisements

Signature Capture–WPF

I kept working on the SignaturePanel this last week.  I decided to make the same thing in WPF.   I fired up a new WPF Application and hooked up a reference to my existing SignatureCapture.Support class.  I then added a Rectangle (changed it later to a Canvas) to the MainWindow and three buttons.

image

 

  I then started copy/pasting the code from my WinForms application to the window’s code-behind.

image

 

Yikes!  It looks like the Point and Pen class has been changed from the Windows Implementation to the WPF implementation.  My first thought was to throw away the WPF version by using the trusty Remove and Sort Using context menu:

image

I then fully-qualified my classes:

image

And then I realized that I was completely wrong and if I spent more than 1 second thinking about the problem, the whole remove usings/fully qualifying the classes won’t work.

image

BECAUSE THEY ARE TWO DIFFERENT TYPES.

Given the choice of adding new functions to my Support class or converted, I chose the later.  I added a Convert Line method like so:

private System.Drawing.Point ConvertPoint(System.Windows.Point point)
{
    System.Drawing.Point returnPoint = new System.Drawing.Point();
    returnPoint.X = (Int32)point.X;
    returnPoint.Y = (Int32)point.Y;
    return returnPoint;
}

and then I wired up the UI:

private void signatureCanvas_MouseMove(object sender, MouseEventArgs e)
{
    if (IsCapturing)
    {
        if (startPoint.IsEmpty && endPoint.IsEmpty)
        {
            endPoint = ConvertPoint(e.GetPosition(this.signatureCanvas));
        }
        else
        {
            startPoint = endPoint;
            endPoint = ConvertPoint(e.GetPosition(this.signatureCanvas));
            Line line = new Line(startPoint, endPoint);
            glyph.Lines.Add(line);
            DrawLine(line);
        }
    }
}

Note that the e.GetPosition() method replaces the WinForm’s e.Location property.  The key thing is that the second argument (location) needs to be your capturing panel to make it equivalent to the WinForm implementation…

private void DrawLine(Line line)
{
    System.Windows.Shapes.Line currentLine = new System.Windows.Shapes.Line();
    currentLine.Stroke = System.Windows.Media.Brushes.Black;
    currentLine.X1 = line.StartPoint.X;
    currentLine.Y1 = line.StartPoint.Y;
    currentLine.X2 = line.EndPoint.X;
    currentLine.Y2 = line.EndPoint.Y;
    currentLine.StrokeThickness = 1;
    signatureCanvas.Children.Add(currentLine);

}
private void signatureCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
    IsCapturing = false;
    signature.Glyphs.Add(glyph);
    startPoint = new System.Drawing.Point();
    endPoint = new System.Drawing.Point();

}
private void signatureCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
    IsCapturing = true;
    glyph = new Glyph();
}

All that was left was to handle the button clicks:

private void clearButton_Click(object sender, RoutedEventArgs e)
{
    signatureCanvas.Children.Clear();
}
private void exportButton_Click(object sender, RoutedEventArgs e)
{
    signatureFactory.SerializeSignatureToDisk(signature, fileName);
}
private void DrawSignature()
{
    foreach (Glyph glyph in signature.Glyphs)
    {
        foreach (Line line in glyph.Lines)
        {
            DrawLine(line);
        }
    }
}
private void importButton_Click(object sender, RoutedEventArgs e)
{
    signature = signatureFactory.DeserializeSignatureFromDisk(fileName);
    signatureCanvas.Children.Clear();
    DrawSignature();
}

And now I have a WPF implementation of the signature capture panel:

image

With the cool thing is that I can import and signature from a WinForm into my WPF app, or export my WPF generated signature into the WinForm app or that Web Form app,

Primary Keys and Entity Framework

 

If you are creating EF classes from an existing database schema and one of your classes has a composite key of all of the fields like this:

image

You didn’t define a primary key in the database.  Once you go back and do that, your EF class will reflect it:

image

A curious property about dependency properties

For my Panzer General game, I have a collection of hexes that make up the main board. Before every turn, I update the main canvas with this collection. I wrote some code like this:

this.MainCanvas.Children.Clear(); foreach (Hex hex in Game.CurrentBoard) { hex.HexInfoTextBlock.Text = string.Empty; this.MainCanvas.Children.Add(hex); }

However, when I run it, I get the following exception:

 

System.InvalidOperationException was unhandled

Message=Element is already the child of another element.

 

My first thought was to create a Clone for each Hex – remove the old Hex and then add the new one to the collection. However, I still got the same error.

After mucking around Bing for a bit (and not getting any closer to the answer), I decided to back into the parent and try and clear the collection that way:

Canvas currentCanvas = Game.CurrentBoard[0].Parent as Canvas; if (currentCanvas != null) { currentCanvas.Children.Clear(); }

Surprise! Surprise! It worked. I am guessing that the dependency property of the children still hold onto their parent even after the clear until the page goes out of scope.

Using LINQ to replace foreach

I sometimes forget how powerful LINQ can be – especially when dealing with older constructs that work fine.  I recently wrote this nugget of crappy code:

Unit unit = null; foreach (Hex hex in Game.CurrentBoard) { if (hex.CurrentUnit != null) { if (hex.CurrentUnit.Country.AlliesIndicator == true) { unit = hex.CurrentUnit; } } }

I looked at it for a second and then re-wrote it using LINQ:

var q = (from h in Game.CurrentBoard where h.CurrentUnit.Country.AlliesIndicator == true select h);

Take about an improvement in readability!

Removing something from a collection

Consider the following snippet:

//Remove all hexes that have a unit in them for (int i = 0; i < returnValue.Count; i++ ) { if (returnValue[i].CurrentUnit != null) { returnValue.RemoveAt(i); } } return returnValue;

This does not work.  For example, here is a screen shot:

image

The reason why is that the indexer is evaluated once,, but the list changes after each iteration.  In graphical terms:

0

1

2

3

4

5

X

X

0

1

2

3

4

X

 

 

Index 1 becomes Index 0, and since the loop is already on 1, it gets skipped for evaluation. What we need it to remove a hex and then keep looping – so the while construct needs to be used:

bool keepLooping = true; while (keepLooping == true) { int totalHexes = returnValue.Count; for (int i = 0; i < returnValue.Count; i++) { if (returnValue[i].CurrentUnit != null) returnValue.RemoveAt(i); if (totalHexes == returnValue.Count) keepLooping = false; } }

 

And the results work as expected:

image

Entity Framework: Identity Errors

If you create a table with a PK that is not identity and then create a EF class from that and then try and load in an empty value, you get a System.Data.Update exception:

image

 

If you go ahead and change the server to identity without updating EF on your client, you still get a System.Data.Update exception, but with a different inner exception:

image

What you need to do is to fix it by changing to identity and then updating the EF on the client:

image

Volia: the change will now persist

However, if you create a PK on an existing table where there used to be a Implied key, you get an error. You need to drop the table and re-create.