# Wednesday, August 11, 2010

Earlier this week Nick Randolph asked me if I knew of any .NET barcode recognition software.  Not an SDK for an existing laser scanner, but something that might take a picture of a barcode and decode it. 

Early on in my development career I dealt with barcode scanners and I've always found the technology to be fairly interesting.  I remembered some work Casey Chesnut had done quite some time ago on barcode recognition that I had always wanted to spend a little time playing building off of.  Of course Casey didn't provide any code, but that's fine - I'd rather attack this as a pure mental exercise for myself. 

I actually decided to attack the problem a little differently than Casey.  I knew that doing a decode of a "pure" clean barcode would be easy and not a realistic scenario anyway, so I didn't even bother working on code to do it.  I knew I was going to be able to do the decoding algorithm part - that's simply turning bits into text and anyone can do that given the algorithm.  The challenge, and fun, is in extracting the binary data bits from an "analog" picture.  I'm saying "digital" and "analog" here in that an ideal barcode bit is either black or white, on or off, a picture (even a digital picture) is not going to be so clear.

So step one was to take a picture of a barcode.  I grabbed a book off the shelf and used my phone to snap a picture (bonus points if you know what book it is):

You can see, it's not an "optimal" image - it's dark and there are a lot of variations in color.  This seemed way more realistic.

Next I needed to get rid of the "color" and I decided the best path would be to simply "draw" a logical line horizontally through the center of the image assuming that it would cross the barcode. 

I extracted every pixel across this line and determined the luminance of each, essentially turning the line of pixels into greyscale.

Next I needed to turn this analog grey data into binary, which introduced a variable I'll call the "threshold." Luminance values above the threshold (brighter) would be a zero, below the threshold would be a one.  This means that you can alter what the software "sees" for bars by simply adjusting that threshold.

I put together a library and a sample application that showed all of this process at once - the barcode, a chart of the luminance and a chart of the "binary" representation of that luminance based on a given threshold.

The next step was to try to turn this "binary" data into actual bits that I could decode.  My first attempt followed this reasoning: 
1. an EAN13 barcode (which is what I'm working with) starts with three "guard" or delimiter bits: 1-0-1. 
2. I start at the left edge of the image and traverse until I hit the first "on" pixel and record that as the start position.
3. I traverse until the next "off" pixel.  The distance between the on and off is the width of a bit.
4. I "back up" 1/2 of a bit width (to give me the best odds of hitting the actual bit value) and then step forward by bit widths, checking the pixel value.

It took a little tweaking of the logic, in which I'd move the current and subsequent sample points away from any nearby "edge" to help get me in the middle of a data point.  With only this minor logic improvement I was able to decode the picture I started with.  I had a sample app that showed each of these steps:
- The loaded barcode image
- The luminance across the barcode at the mid point as a graph
- A graph of the binary representation of that luminance based on a threshold
- decoding of that binary set

All that in just about 1 day of work.

Of course the second barcode picture I took and tried failed.  It worked through all of the steps until the decode, where it always fell apart, being unable to correctly identify any digit but the first.  The failure, I think, is due to the fact the book cover is glossy, so I have a lot more "noise" in the luminance graph.  That simply means I need to improve my image recognition algorithm, which will be the focus of the next blog entry on this library.

Now you might be asking "well where's the code for this?"  Patience.  It's in Codeplex right now, it's just not yet published.  I want to get it to a state that's a little less ugly before I turn it loose.  When can you expect it?  Well I can't say for certain, but Codeplex required publication within 30 days, so that gives you a "latest possible release" date - though I hope to publish earlier.

Wednesday, August 11, 2010 2:11:36 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, August 02, 2010

Today I decided to finally get around to testing out the IoC core library on Windows Phone 7.  Of course I couldn't be lucky enough for it to just compile out of the box and work. The usage of the Control class for marshaling events made it a little bit challenging, but it really didn't require a whole lot of code changes to get the code base to continue to work for the Desktop, the Compact Framework and Windows Phone.  The latest release now has a solution and a Silverlight project for WinPhone.

Why would you want to use this IoC container?  Well I use it becasue it's lightweight and because I can use the same framework everywhere.  I don't have to learn a new framework when I'm using the desktop, the CF and now the phone.  It keeps my life simpler and allows better code reuse for me.

Monday, August 02, 2010 4:35:50 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, July 28, 2010

Since I use the OpenNETCF.IoC framework in just about every project I do any more, you can imagine I've created a pretty good collection of Modules and Services for common business problems I run into.  I've decided that I'm going to start putting some of these out in the public domain along with the framework and my first release is the OpenNETCF.Location module.  It's basically a module that prvides a GPS location service (GpsService to be exact). 

The default implementation is wrapper around the GPS intermediate driver, but it's not using the CF classes that Microsoft ships with the WinMo SDKs.  I looked at Microsoft's implementation and it felt really ugly to me, so I rewrote it the way it should have been done in the first place.  I don't yet have a simple sample application extracted for it (I have apps that use it, but they're too complex for a sample), but I'll add one as time permits.

The code is part of the latest change set (49823) - it's not yet in the release download - so if you want it, get it off of the Source Code page.

Wednesday, July 28, 2010 11:45:25 AM (Central Daylight Time, UTC-05:00)  #     | 

In my continuing effort to get code that I have lying around out to where it's publicly available and easy to find, I've pushed my old FTP library up to Codeplex.

Wednesday, July 28, 2010 10:45:16 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, July 23, 2010

I've been working on a new control this week that depends a whole lot on transparency and the alpha channel.  The Compact Framework's Bitmap class is actually really, really bad and it's made for all sorts of swearing. 

The design of the control requires me to regularly create a "transparent" background.  We know that you can't create a transparent bitmap directly (which is the fundamental thing that is killing me) so I end up using a TransparentClearBitmap method that first appeared in Project Resistance that does a LockBits and walks the image setting transparency.  This is slow (600ms for my bitmap on the emulator).

I needed to draw on top of this Bitmap to assemble my control layout. The issue is that every time I repainted the control due to a change, I need a new transparent Bitmap and had to pay the 600ms piper.  Needless to say this gave for a really bad user experience.  Well how about just caching the transparent bitmap and returning a copy of it when necessary?  That should be simple, right?

I tried to use the Bitmap constructor to make a copy:

var bmp = new Bitmap(m_transparentBitmap);

Of course it failed. The new Bitmap lost all transparency data.

Well maybe the Clone method would do what I want, after all that's what I needed - an exact clone:

var bmp = m_transparentBitmap.Clone;

Again, all transparency data was lost. Joy.

So it was off to the drawing board to re-implement what should have already been working.  Here's the result - a TransparentBitmap that you can clone and actually keep the transparency info:

public class TransparentBitmap
{
    private Bitmap m_bmp;

    public int Width { get; private set; }
    public int Height { get; private set; }

    public TransparentBitmap(int width, int height)
    {
        Width = width;
        Height = height;
        m_bmp = new Bitmap(width, height, (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        GraphicTools.TransparentClearBitmap(m_bmp);
    }

    private TransparentBitmap(Bitmap image)
    {
        m_bmp = image;
        Width = image.Width;
        Height = image.Height;
    }

    public static implicit operator Bitmap(TransparentBitmap t)
    {
        return t.m_bmp;
    }

    public TransparentBitmap Clone()
    {
        var clone = new Bitmap(Width, Height, (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        var dest = clone.LockBits(
                new Rectangle(0, 0, Width, Height),
                ImageLockMode.WriteOnly,
                (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        try
        {
            var src = m_bmp.LockBits(
                    new Rectangle(0, 0, Width, Height),
                    ImageLockMode.ReadOnly,
                    (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

            try
            {
                int bytes = src.Width * src.Height * 4;
                memcpy(dest.Scan0, src.Scan0, bytes);
            }
            finally
            {
                m_bmp.UnlockBits(src);
            }
        }
        finally
        {
            clone.UnlockBits(dest);
        }

        return new TransparentBitmap(clone);
    }

    [DllImport("coredll.dll", SetLastError = true)]
    private static extern IntPtr memcpy(IntPtr to, IntPtr from, int count);
}

The Clone takes only about 4ms to run instead of 600ms to create new, so it certainly improved things.

Friday, July 23, 2010 4:02:06 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, July 21, 2010

I'm working on a new control and I ran into the need to know if a pixel in an image is transparent or not (essentially I want to ignore clicks on the control if the underlying color is transparent).  My first reaction was that I'd simply call GetPixel on the underlying Bitmap and look at the Color's A (alpha) value.  Unfortunately, the Compact Framework's implementation always appears to return 0xff (fully opaque) for teh A channel.

Next I figured I'd call LockBits and look at the pixel data manually.  Once again the CF tried to thwart me because the supported PixelFormat enumeration values in the Compact Framework don't include anything with Alpha support.

Instead I decided to try to "fool" the framework by creeating my own PixelFormat enumeration that contained all of the actual possible values, not just the three exposed in the CF:

enum PixelFormat
{
    Indexed = 0x00010000, // Indexes into a palette
    GDI = 0x00020000, // Is a GDI-supported format
    Alpha = 0x00040000, // Has an alpha component
    PAlpha = 0x00080000, // Pre-multiplied alpha
    Extended = 0x00100000, // Extended color 16 bits/channel
    Canonical = 0x00200000,

    Undefined = 0,
    DontCare = 0,

    F1bppIndexed = (1 | (1 << 8) | Indexed | GDI),
    F4bppIndexed = (2 | (4 << 8) | Indexed | GDI),
    F8bppIndexed = (3 | (8 << 8) | Indexed | GDI),
    F16bppRGB555 = (5 | (16 << 8) | GDI),
    F16bppRGB565 = (6 | (16 << 8) | GDI),
    F16bppARGB1555 = (7 | (16 << 8) | Alpha | GDI),
    F24bppRGB = (8 | (24 << 8) | GDI),
    F32bppRGB = (9 | (32 << 8) | GDI),
    F32bppARGB = (10 | (32 << 8) | Alpha | GDI | Canonical),
    F32bppPARGB = (11 | (32 << 8) | Alpha | PAlpha | GDI),
    F48bppRGB = (12 | (48 << 8) | Extended),
    F64bppARGB = (13 | (64 << 8) | Alpha | Canonical | Extended),
    F64bppPARGB = (14 | (64 << 8) | Alpha | PAlpha | Extended),
    Max = 15,
}

Since an enum is really just a number, you can directly cast this to a System.Drawing.Imaging.PixelFormat. Nicely (and fortunately), the CF implementation of LockBits doesn't check to ensure that the value you pass in is one of the defined PixelFormat values and it readly accepts this cast value.  Even more interesting is that it returns a set of data with the proper alpha channel data. 

Gettting the Alpha data, then is as easy as this (I don't return a Color because there is no easy way to create a Color class that contains Alpha data in the CF either):

private byte GetPixelAlpha(Bitmap image, Point point)
{
    var d = image.LockBits(new Rectangle(0, 0, this.Width, this.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

    try
    {
        // the CF's GetPixel method will always return 0xff (full opaque) for the alpha channel
        // so we have to resort to unsafe shenanigans
        unsafe
        {
            int offset = (d.Width * point.Y * 4) + (point.X * 4);
            byte* p = (byte*)d.Scan0;
            p += offset;

            return *(p + 3);
        }
    }
    finally
    {
        image.UnlockBits(d);
    }
}

Wednesday, July 21, 2010 3:50:57 PM (Central Daylight Time, UTC-05:00)  #     |