1

I've managed to do recognize characters from image. For this reason:

I save all recognized blobs(images) in List

        Bitmap bpt1 = new Bitmap(@"C:\2\torec1.png", true);
        Bitmap bpt2 = new Bitmap(@"C:\2\torec2.png", true);
        List<Bitmap> toRecognize = new List<Bitmap>();
        toRecognize.Add(bpt1);
        toRecognize.Add(bpt2);

I keep a library of known letters in Dictionary.

            Bitmap le = new Bitmap(@"C:\2\e.png", true);
            Bitmap lg = new Bitmap(@"C:\2\g.png", true);
            Bitmap ln = new Bitmap(@"C:\2\n.png", true);
            Bitmap li = new Bitmap(@"C:\2\i.png", true);
            Bitmap ls = new Bitmap(@"C:\2\s.png", true);
            Bitmap lt = new Bitmap(@"C:\2\t.png", true);
            var dict = new Dictionary<string, Bitmap>();
            dict.Add("e", le);
            dict.Add("g", lg);
            dict.Add("n", ln);
            dict.Add("i", li);
            dict.Add("s", ls);
            dict.Add("t", lt);

Then I create New List with Images - from library:

var target = dict.ToList();

And do the comparison of images: (target[index].Key, target[index].Value)

for (int i = 0; i < x; i++)
{
   for (int j = 0; j < y; j++)
   {
       if (CompareMemCmp(toRecognize[i], target[j].Value) == true)
       {
       textBox3.AppendText("Found!" + Environment.NewLine);
       textBox2.AppendText(target[j].Key); //Letter is found - save it!
       }
       else {textBox3.AppendText("Don't match!" + Environment.NewLine); }
   }
}

1. [removed]

2. Is the method that I used tolerable from the perspective of performance? I'm planning to do the recornition of 10-20 images at the same time (average letter count for each is 8) and the library for letters will consist of English alphabet (26 upper + 26 lower case), special letter(~10) and Numbers (10).

So I have 80+ letters that have to be recognized and pattern library which consists of ~70+ characters. Will the performance be at a good level?

Constructive criticism gladly accepted. ;)

Alex
  • 4,607
  • 9
  • 61
  • 99
  • break; -breaks the loop, so 2nd question left – Alex Feb 19 '12 at 14:02
  • Doing image recognition quickly requires massively parallel computing hardware, the kind you have between your ears. OpenCV is a library that's often used for these kind of tasks, highly optimized SIMD code to get a semblance of that kind of hardware. Emgu is a .NET wrapper for it. http://www.emgu.com/wiki/index.php/Main_Page – Hans Passant Feb 19 '12 at 16:30
  • C# isn't going to be the source of your performance bottleneck. You can do this on a single CPU, but moving it a GPU implementation will make it a *lot* (as in, orders of magnitude) faster. Have a look at the Cloo OpenCL library. – 3Dave Feb 19 '12 at 17:05

2 Answers2

2

Question 1:

[removed]

Question 2:

It depends.
First of all, if performance is not enough, what's your bottleneck ?
I suspect it's CompareMemCmp() function... so can you speed-up it ?

If not, given that each iteration of your loop seems independent from the previous ones, you could try to run it in parallel.
To do this have a look at the Task Parallel Library methods of framework 4.0, in particular to Parallel.For.

EDIT :

If we are talking about perfect matching between images, you can try to use dictionary look-up to speed things up.

First, you can build a wrapper class for Bitmap that can be efficiently used as Dictionary<> key, like this:

class BitmapWrapper
{
    private readonly int hash;
    public Bitmap Image { get; private set; }
    public BitmapWrapper(Bitmap img)
    {
        this.Image = img;
        this.hash = this.ComputeHash();
    }

    private int ComputeHash()
    {
        // you could turn this code into something unsafe to speed-up GetPixel
        // e.g. using lockbits etc...
        unchecked // Overflow is fine, just wrap
        {
            int h = 17;
            for (int x = 0; x < this.Image.Size.Width; x++)
                for (int y = 0; y < this.Image.Size.Height; y++)
                    h = h * 23 + this.Image.GetPixel(x, y).GetHashCode();
            return h;
        }
    }

    public override int GetHashCode()
    {
        return this.hash;
    }
    public override bool Equals(object obj)
    {
        var objBitmap = obj as Bitmap;
        if (obj == null)
            return false;
        // use CompareMemCmp in case of hash collisions 
        return Utils.CompareMemCmp(this.Image, objBitmap); 
    }
}

This class computes the hascode in ComputeHash method that is inspired by this answer (but you can just ex-or every pixel). That surely can be improved by involving unsafe code (something like in the CompareMemCmp method).

Once you have this class, you can build a look-up dictionary like this:

Bitmap le = new Bitmap(@"C:\2\e.png", true);
Bitmap lg = new Bitmap(@"C:\2\g.png", true);
...
var lookup = new Dictionary<string, Bitmap>();
lookup.Add(new BitmapWrapper(le), "e");
lookup.Add(new BitmapWrapper(lg), "g");
...

then the search will be simply:

foreach(var imgToRecognize in toRecognize)
{
   string letterFound;
   if(lookup.TryGetValue(new BitmapWrapper(imgToRecognize), out letterFound))
   {
      textBox3.AppendText("Found!" + Environment.NewLine);
      textBox2.AppendText(letterFound); //Letter is found - save it!
   }
   else
      textBox3.AppendText("Don't match!" + Environment.NewLine);
}

The performances of this method definitely depends on the hash computation, but certainly they can save a lot of CompareMemCmp() calls.

Community
  • 1
  • 1
digEmAll
  • 56,430
  • 9
  • 115
  • 140
  • CompareMemCmp() is one of the fastest methods of bitmap comparison I've ever seen (it's also unsafe) Thanks, I'll dig more info on Parallel.For. maybe that's what I'm looking for. "First of all, if performance is not enough, what's your bottleneck ?" - I expect to do the recognition of 15 images within half a second – Alex Feb 19 '12 at 14:31
  • @Alex: sorry I don't know CompareMemCmp, because is not in the base library. I suspect it's the one reported [here](http://stackoverflow.com/questions/9348946/c-sharp-bitmap-comparison-pinvokestackimbalance-exception), isn't it ? If so, yes, I suspect it's hardly improvable. That being said, I don't see a performance problem in your code, and by exploiting parallelism you can probably go n-times faster (with n being the number of processors/cores of your pc) – digEmAll Feb 19 '12 at 14:59
  • 1
    @Alex: just to be sure, are you talking about perfect image matching (i.e. the 2 compared bitmaps are perfectly equal), right ? If so, peraphs you can compute an hashcodes of the images (for example exor-ing the bytes) then exploit a dictionary lookup. I don't know if it will be faster (because hash computation could be long), but It could be worth a try... – digEmAll Feb 19 '12 at 15:08
  • although I'm not sure if I'll see any difference now, but when my dictionary is complete - I'll try to use your method! seems like "exor-ing" is a good idea.. btw is it "ok" to keep all images in dictionary like this? Maybe I should use arrays[] or something? – Alex Feb 19 '12 at 16:00
  • Up to this moment I was trying to compare "Exact Image to Exact Image" (B to A: no match, then B to B: match). Are you saying that I can use hashcode comparison to identify text within an image? i.e. "Whole Image to A, to B, to C - write down the letter when match". That might be even better sollution because I don;t have to do the segmentation. Basically List of Images that has to be recognized become 1 image, is that so? Also, I was trying to use your example for hash comparison but I receive "The name 'Utils' does not exist in the current context" error. – Alex Feb 20 '12 at 11:08
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7951/discussion-between-alex-and-digemall) – Alex Feb 20 '12 at 11:18
2

If C# is the right tool for the job depends on how big your images are. A hash table is a nice approach but you need to compare the whole image before you can check if you have a match. Xoring the images is very fast but you need to xor all images until you find the matching ones which is quite inefficient.

A better approach would be to choose a fingerprint which is designed in a way that you need to read only minimal amount of data. E.g. you can generate a hash code of a vertical line in the middle if your image which would produce a different value for each of your images. If not adapt the approach until you arrive at an algorithm where you do not need to read the image as a whole but only a few bytes until you can assign the image to the right bucket. This does only work if your input data contains only the images in your dictionary. Otherwise it would be only a probabilistic method.

Alois Kraus
  • 13,229
  • 1
  • 38
  • 64
  • Computing the hashcode on one line (or the diagonal) of the image, could be a smart idea. Anyway, exoring all the images in the list to put them into the dictionary, is computationally equal to compare the searched image with all the images in the list, with the difference that in teh first case, once the dictionary is full (and all the hashcodes stored), you will have much more speed for further comparisons. Of course this is worth if you need more than 1 look-up. – digEmAll Feb 19 '12 at 21:06
  • You are right that exoring is quite fast but depending on the image size it might matter. Besides this if you know you do not need the complete image you could spare memory by loading only the relevant parts of the image to do the matching. This could lead to huge savings in IO bandwidth. – Alois Kraus Feb 20 '12 at 09:51