Optimized OCR black/white pixel algorithm

前端 未结 7 1901
被撕碎了的回忆
被撕碎了的回忆 2021-02-06 06:30

I am writing a simple OCR solution for a finite set of characters. That is, I know the exact way all 26 letters in the alphabet will look like. I am using C# and am able to easi

相关标签:
7条回答
  • 2021-02-06 07:15

    Alright, I figured out the solution.

    You simply use a depth first search on every single pixel with every other pixel combination, until you find the set of unique characteristics of the letter. While performing the depth first search, make sure you don't start at x=0 and y=0 each time since you only want to process each combination only once, so what you end up doing is incrementing the x and y values in each iteration.

    I created a helper object which contains these properties:

    public Point LastPoint { get; set; }
    public List<OcrChar> CharsWithSimilarProperties { get; set; }
    public List<Point> BlackPixels { get; set; }
    public List<Point> WhitePixels { get; set; }
    

    For every iteration, if I couldn't find a unique characteristic (e.g. all other letters have this pixel as black but this letter has it as white... or the inverse) I add all subsequent pixels to a queue which is being processed, by creating an instance of this above object with the properties properly set.

    Some psuedo code:

    rootNode.LastPoint = new Point(-1, -1)
    rootNode.CharsWithSimilarProperties = all letters in alphabet except for this one
    queue.Add(rootNode)
    
    while queue.HasNodes()
      for each pixel after node.LastPoint
        if node.IsBlackPixel(pixel) && node.CharsWithSimilarProperties.IsAlwaysWhite(pixel)
          node.BlackPixels.Add(pixel)
          return node.BlackPixels and node.WhitePixels
    
        if node.IsWhitePixel(pixel) && node.CharsWithSimilarProperties.IsAlwaysBlack(pixel)
          node.WhitePixels.Add(pixel)
          return node.BlackPixels and node.WhitePixels
    
        newNode = new Node();
        newNode.BlackPixels = node.BlackPixels.Copy();
        newNode.WhitePixels = node.WhitePixels.Copy();
        newNode.LastPoint = pixel
        if node.IsBlackPixel(pixel)
          newNode.BlackPixels.Add(pixel)
          newNode.CharsWithSimilarProperties = list of chars from node.CharsWithSimilarProperties that also had this pixel as black
        else
          newNode.WhitePixels.Add(pixel)
          newNode.CharsWithSimilarProperties = list of chars from node.CharsWithSimilarProperties that also had this pixel as white
        queue.Add(newNode)
    

    To determine if "node.CharsWithSimilarProperites.IsAlwaysWhite()" or "IsAlwaysBlack()", you can generate a compositeMap in each iteration of the queue:

      for each pixel after node.LastPoint
        for each char in node.CharsWithSimilarProperties
          if char.IsBlackPixel(pixel)
            compositeMap[pixel].Add(char)
    

    Before doing all this, I also processed the entire alphabet to find pixels that are always white or always black, since these can never be used. I added them to a List<Point> ignoredPixels, and every time I iterate over pixels, I always use if (ignoredPixels[x, y]) continue;.

    This works perfectly and is really fast. Although keep in mind that this part of my solution doesn't need to be fast at all since it is a one-time optimization which helps me later on. In my test cases of a maximum of 8 chars per "alphabet" set, it usually produces one or two characteristics for each character. I have yet to run it on a full set of 26 characters.

    0 讨论(0)
提交回复
热议问题