Click here to Skip to main content
15,885,875 members
Articles / Multimedia / GDI+

Reading Barcodes from an Image - II

Rate me:
Please Sign up or sign in to vote.
4.74/5 (35 votes)
21 Aug 2010CPOL2 min read 336.7K   24.8K   205   51
An example of how to process an image for barcode strings
Sample Image

Introduction

I recently ran across Benjamin Liedblad's article on reading barcode strings from images. The code was good, but not very useful in the real world. I thought my additions had a place here.

Berend Engelbrecht has vastly improved this project. His new version can be found at BarcodeImaging3.aspx.

Background

Liedblad's barcode reader has two significant flaws:

  • It only reads right-side up barcodes (as he mentioned in his "todo").
  • It assumes that there is nothing other than the barcode in the image.

Frequently, we need to read a barcode from a page full of other text. This is what I set about to do.

Using the Code

First of all, you should check out the original article to see how the barcode reading works. Much of the code is left unchanged.

Changes:

  • Since the barcode we are looking for may not be at the beginning of the text line that we scan, we can't just scan by blocks of 9 'characters'. Instead, we walk along the scanned pattern one 'bar' at a time, testing it and the 8 bars after it to see if they form a character. If we find a real character, then we skip over the character pattern and begin again.
  • Since there are text and other distractions on many pages, we need to cut the page up into sections and look for barcodes in each section. I've found that 50 is a good number of sections. While this seems like a lot, it's enough to ensure that we get the barcode we're looking for. Your mileage may vary. To this end, I added a startheight and endheight to ReadCode39(). Then we just need to calculate where each section begins and ends. This is accomplished easily in a for loop:
    C#
    for (int i=0; i < numscans; i++)
    {
        read = ReadCode39(bmp,i * (bmp.Height / numscans), 
               (i * (bmp.Height / numscans))+ (bmp.Height / numscans));
        [...]
    }
  • We need to check all four page orientations, which is handled easily with .NET's Bitmap control:
    C#
    for (int i=0; i < 4; i++)
    {
        bmp.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
        VScanPageCode39(ref CodesRead, bmp,numscans);
    }

    You can, of course not use this if you know that all of your pages are the right way up.

  • Finally, since we scan so many times and receive so many barcodes (including the backwards version of what we are looking for), we need to store all of the barcodes that we found. For this, I decided to use an ArrayList. The code currently returns all of the barcodes, but since most people supply some sort of pattern to their code (usually beginning and ending with astericks "*"), it's easy enough to pick out the right one.

Running the Demo

When you run the demo and load "SamplePage.jpg", first perform "Scan Barcode". This is essentially identical to Liedblad's original code. You will get "*JR7". Not very helpful. Then perform "Scan Page". Now you have a list of barcodes, one of which is the one you want (*surprise*)... and one is its mirror image (P4 9V*VK P). As you can see, it's pretty easy to pick out what you need.

History

  • 5-15-05: Original
  • 8-20-10: Article updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) InGage Networks
United States United States
James is currently a Software developer after a detour from that profession into IT because he 'didn't want to sit in a cubicle and wanted to deal with people.' He has since learned that people are stupid, and enjoys his cubicle greatly.

Comments and Discussions

 
QuestionOMR Sheet inside that how to read marks Pin
Member 1017743627-Mar-14 3:11
Member 1017743627-Mar-14 3:11 
Questionit is even not working for code39 Pin
heemanshubhalla9-Feb-14 0:28
heemanshubhalla9-Feb-14 0:28 
Generalproblem Pin
ankur78916-Jun-13 22:22
professionalankur78916-Jun-13 22:22 
GeneralRe: problem Pin
qlipoth17-Jun-13 2:31
qlipoth17-Jun-13 2:31 
GeneralRe: problem Pin
ankur78917-Jun-13 17:01
professionalankur78917-Jun-13 17:01 
Generalproblem Pin
ankur78916-Jun-13 22:20
professionalankur78916-Jun-13 22:20 
GeneralMy vote of 5 Pin
csharpbd28-Nov-12 23:05
professionalcsharpbd28-Nov-12 23:05 
QuestionExcelent Pin
Sergey Lapp28-Sep-12 8:04
Sergey Lapp28-Sep-12 8:04 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey26-Feb-12 19:59
professionalManoj Kumar Choubey26-Feb-12 19:59 
GeneralMy vote of 5 Pin
sw_tech12322-Jun-11 23:26
sw_tech12322-Jun-11 23:26 
GeneralBarcode reader for PDF Pin
MarkNaff17-Aug-10 13:55
MarkNaff17-Aug-10 13:55 
AnswerRe: Barcode reader for PDF Pin
qlipoth20-Aug-10 3:56
qlipoth20-Aug-10 3:56 
GeneralRe: Barcode reader for PDF Pin
MarkNaff20-Aug-10 4:06
MarkNaff20-Aug-10 4:06 
GeneralRe: Barcode reader for PDF Pin
qlipoth20-Aug-10 4:12
qlipoth20-Aug-10 4:12 
GeneralRe: Barcode reader for PDF Pin
MarkNaff20-Aug-10 4:15
MarkNaff20-Aug-10 4:15 
GeneralRe: Barcode reader for PDF Pin
2374112-Mar-12 5:03
2374112-Mar-12 5:03 
GeneralHelp for Barcode 39 Extension Pin
naorem24-Jan-10 19:45
naorem24-Jan-10 19:45 
NewsPublished new CodeProject version: Reading Barcodes from an Image - III Pin
Berend Engelbrecht5-Oct-09 10:56
Berend Engelbrecht5-Oct-09 10:56 
NewsModifications to prevent "false positives" for Code39, improved speed, EAN and Code128 support Pin
Berend Engelbrecht2-Oct-09 5:19
Berend Engelbrecht2-Oct-09 5:19 
Hello,

Your code was just what I was looking for and it works great in the sense that even on a scan in fax quality it manages to find all Code39 barcodes. My problem was only: it finds a lot more than just the barcodes. Even if I use your relatively clean test image, the test app returns some false positives.

Preventing false positives
To be able to use your code to reliably recognize valid Code39 barcodes, I have added some code to filter for only barcodes starting and ending in "*" (I could not use the checksum solution of vbdotnetcoder2005, because our application needs to read barcodes without checksum).

Even after implementing the start/end character constraint, I still got some false positives with real-world data. Because of this, I have also put in some code for noise recognition. I noticed that in this part of the code noise was ignored:
somedata= parsePattern(new string(pattern));
dataString += somedata;

if (somedata == null)
{
  index++;
...
somedata == null means that the pattern was not recognized, but even if this happens several times in a row, the software would still consider the next valid Code39 bar as a part of the same barcode. In my version, if the index is incremented more than 10 times without finding a valid pattern, a pipe "|" is added to the dataString to indicate noise. With this, a further constraint could be added that a valid Code39 barcode should also not contain any noise. This removed all false positives in my test data, without reduction in recognition rate.

[update October 3, 2009] - optimized code for speed
When profiling the software, I found that it spent 80% of processing time in this single line of code:
bmp.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
To get rid of that, I have rewritten the code to avoid bitmap rotation. The new version implements these optimizations:
1. The code now scans through the same image twice: first scanning top-to-bottom and then left-to-right with x and y coordinates swapped. This removes the need for 90 degrees rotation.
2. On each scan line, the pattern that is found is first parsed front-to-end, then the character array is reversed and the parsing is repeated with the mirrored pattern. This removes the need for 180 degrees rotation or page flip.
3. For black and white images, I followed a suggestion of Pandele Florin: instead of converting the image to 24bpp RGB, I leave the original image format in tact for B&W images. This saves a conversion inside LockBits, making it faster and reduces memory usage.
4. In the verticalHistogram function, use byte and short integer arrays instead of float. Integer arithmetic is slightly faster, and can be used because all pixel data are integer numbers.

In my previous test, the software needed about 7 seconds for 50 scans over a 300dpi A4 image. Improvements 1 and 2 reduce that to about 1 second. 3 reduces that to 0.6 second for a B&W image and 4 shaves off another 5% - 10% for both B&W and color images. The code is now over 10 times faster for B&W images! Big Grin | :-D

[update October 4, 2009] - EAN and Code128 support
For barcode recognition in our Library Catalog software, my company needs EAN barcode support. I've added that, based on information from wikipedia. When testing this, I encountered a problem with narrow bar width calculation, that I also fixed in my latest code.

Since Code128 uses bar width measurements that are fairly similar to EAN, I could add that too. I used following resources for this part of the code: Code128 table, checksum calculation, barcode generator. The Code128 work is only briefly tested, I had only one real-world sample for this barcode type.

[update October 5, 2009] - EAN Supplemental Code support
Some products (mainly books and periodicals) have a 2-digit or 5-digit supplemental code next to the EAN code. I have added support for these codes, will be returned as a separate barcode starting with "S", followed by the detected digits.

The updated code can be downloaded here:
http://www.berend.com/download/BarCodeImaging2Source-20091005.zip

I have uploaded test scans for demonstrating EAN and Code128 barcode detection here:
http://www.berend.com/download/BarCodeImaging2-testscans.zip

modified on Monday, October 5, 2009 5:28 AM

GeneralThanks Pin
mr_squall26-Aug-09 21:54
mr_squall26-Aug-09 21:54 
QuestionAny ideas on how to get this code to work in Windows Mobile? Pin
s1dd29-May-09 8:01
s1dd29-May-09 8:01 
AnswerRe: Any ideas on how to get this code to work in Windows Mobile? Pin
s1dd29-May-09 8:14
s1dd29-May-09 8:14 
GeneralRe: Any ideas on how to get this code to work in Windows Mobile? Pin
Berend Engelbrecht3-Oct-09 5:24
Berend Engelbrecht3-Oct-09 5:24 
QuestionAnyone to give me how to read code 128 barcode from an image ? Pin
Narsimha098-Dec-08 8:12
Narsimha098-Dec-08 8:12 
GeneralCan´t read codebars generated using Word... and other tools Pin
neptas13-Feb-08 6:50
neptas13-Feb-08 6:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.