micjahn / ZXing.Net

.Net port of the original java-based barcode reader and generator library zxing
Apache License 2.0
2.7k stars 668 forks source link

Can't read this barcode... And can't figure out why #95

Open lucapiccinelli opened 6 years ago

lucapiccinelli commented 6 years ago

Dear Michael, first of all thank you for your great work with Zxing.Net. I would like to ask for your help on a particular barcode that i can't make zxing to read, while other libraries can (for example this one https://online-barcode-reader.inliteresearch.com, but this is very slow and waaay uglier compared to zxing :grin:).

I did some debug by myself but now i'm stuck... I wrote a software that reads barcodes on video streams using zxing.net; before feeding zxing with the barcode image i perform some image enhancement and i got impressive results also on shadows and reflections. I only use the decode feature, as i detect barcodes by myself.

Here it follows the incrimined barcode image: frnpla59p60a700p

The decoded value is FRNPLA59P60A700P and the format is CODE 128.

I know that this image is not very good, however as mentioned i perform a number of enhancements on this image, and feed them as well into zxing: the best one for this specific barcode instance is as follows enhanced

If you overlay the enhanced one over the original, as a barcode newbie, it seems to look good to me: overlay

Here it follows another enhancement of another instance of the same barcode that is correctly decoded by zxing: frnpla59p60a700p_2

here i isolated the row on which the decode process succeeded and its pattern is the following (click on the white space below, there is an image link, i swear 😅) ok_pattern

The row is the one missing here: missing_ok

If you remove that row, than also this instance fails to be decoded.

As last info, i use zxing.net with image enhancements to decode with success thousand of barcodes in very extreme reflection, corruption and shadowy situations; i give you an example of what i'm talking about (above is the original image, and below its reconstruction that is succesfully read by zxing)

bad barcode

However i have some instances like the one of this issue, where with an apparently good image reconstruction, zxing can't decode as expected and i'm not competent to figure out why.

Here it follows how i instantiate the BarcodeReader class:

new BarcodeReader
{
    Options =
    {
        TryHarder = true,
        PossibleFormats = new List<BarcodeFormat>()
        {
            BarcodeFormat.CODE_93,
            BarcodeFormat.CODE_128,
            BarcodeFormat.CODE_39,
            BarcodeFormat.EAN_8,
            BarcodeFormat.EAN_13,
            BarcodeFormat.UPC_EAN_EXTENSION,
            BarcodeFormat.ITF,
        },
        PureBarcode = true
    }
};

Also putting PureBarcode = false doesn't help

You did a very great work with this library... if you could also give me some help on this issue, would be very much appreciated.

Best Regards, Luca Piccinelli

micjahn commented 6 years ago

I will try to help you.

PureBarcode = true is only valueable for generated barcode images. It is mostly used for round-tripping tests between generator and decoder. If it is set to true, zxing uses a simple white rectangle detector.

The CODE 128 decoder uses a pattern matching algorithm with variance. If the variance is to high there is not match. One important point is the proportion between different bars and white spaces for a single codeword pattern.

I'm not sure if it will help you but here is little example. I made the white space at one position a little bit wider and zxing finds a barcode. Wrong value I think but it found something.

38032163-3d8365fc-329d-11e8-925b-894d44e252e6-wider

I don't have any idea at the moment what the best is what you can do here.

But another question: Is it possible that you can share code of your enhancements with the community?

lucapiccinelli commented 6 years ago

Dear Michael, thank you for your kind reply and for your advice. I will give it a try and let you know about! I saw about variance thresholds in your code and i tried to play with it but unsuccessfully.

About sharing my image enhancement code... I can't share the code as i am not the owner of it as i developed it at my workplace in a proprietary context; however the raw code would be useless as it is developed using an old version of EmguCv and also I have my image class wrapper.

Anyway, i think that no one could blame me if i share my methods and pseudo code algorithms or a reimplementation of them; i would be really honored to contribute in some way to a great project as Zxing.Net is. Here it follows the big picture of the algorithms:

1) I suppose to have horizontal barcodes images previously deskewed (images that contain only a barcode) 2) I apply in cascade different kind of image enhancent on each image and stop at the first that succeed to decode, as i don't know a priori which kind of enhancement is the best suited for a particular image. The cascade should be ordered from the enhancement that most frequently succeed. 3) the enhancement are different combinations of adaptive thresholding, morphological operators, directional median filter and some contrast normalization.

I implemented a directional median filter that works only in the vertical direction (remember my image hypothesis at point 1), following this article http://www.iaeng.org/publication/WCE2012/WCE2012_pp1240-1245.pdf

Given tight time constraints, what do you think that could be the most efficient way to go deeper in details about these enhancements and to analyze how and if zxing could benefit of them?

micjahn commented 6 years ago

I'm not sure what the best way is. I think it doesn't make sense to build in every enhancement. It should be available as an opt-in for users which need it. It would be great if the algorithms could work on the luminance source objects because that makes it easier to implement it independently from the source image formats. But I'm don't know if every method work with grayscale image data. A good next step would be if you could select one or two enhancements which are the most effective ones. After that it should be added to the decoding pipeline.

brianpopow commented 5 years ago

i know im a little late to this, but i just stumbled on this thread and i wanted to share my findings. As a preprocessing step for barcode detection with ZXing.Net i use the following:

With that ZXing.Net is able to decode: 38031836-767538b4-329c-11e8-8003-adeb0fe2ad33

to FRNPLA59P60A700P.

lucapiccinelli commented 5 years ago

Thank you @brianpopow ! All contributions are always appreciated. @micjahn unfortunately i didn't find time to give my contribute to your ZXing.Net. I hope i will in next future

maiksonstrife commented 4 years ago

@brianpopow do you still have the source code? I'm happy to find your discoveries and will start trying myself, but if you do have the source code would help me a lot, i'm stepping on the same issue, being working on certain barcodes since 8 am, and already is 14:00pm and still got nothing

brianpopow commented 4 years ago

@maiksonstrife here you go:

var barcodeSearcher = new ZXing.ImageSharp.BarcodeReader<Rgba32>()
{
    Options =
    {
        TryHarder = true,
    },
    AutoRotate = true,
    TryInverted = true,
};

using (var image = Image.Load<Rgba32>(fileName))
{
    image.Mutate(img => img.Resize(image.Width * 3, image.Height * 3)
            .GaussianSharpen(sigma: 3.0f)
            .Grayscale());
    image.Save("image.jpg");
    var barcodeScannerResult = barcodeSearcher.DecodeMultiple(image);
}
Visutronik commented 4 years ago

Thanks, with "AutoRotate = true" and "TryInverted = true" it works now.

@micjahn You should write it in your README.md