|
| 1 | +# Python Barcode Reader Benchmark |
| 2 | + |
| 3 | +This project measures barcode decoding accuracy and speed for the ZXing Python package and Dynamsoft Barcode Reader Python on the public [BarBeR dataset](https://ditto.ing.unimore.it/barber/). Both readers are evaluated with the same image set, ground truth manifest, matching rules, and raw JSONL result protocol. |
| 4 | + |
| 5 | +## Dependencies |
| 6 | + |
| 7 | +- Python 3.9 or later |
| 8 | +- OpenCV Python |
| 9 | +- `zxing-cpp` Python package |
| 10 | +- `dynamsoft-capture-vision-bundle` |
| 11 | +- A valid [Dynamsoft Barcode Reader license](https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv&package=cross-platform) |
| 12 | + |
| 13 | +Install dependencies: |
| 14 | + |
| 15 | +```powershell |
| 16 | +python -m venv .venv |
| 17 | +.\.venv\Scripts\Activate.ps1 |
| 18 | +pip install -r requirements.txt |
| 19 | +``` |
| 20 | + |
| 21 | +## Prepare the BarBeR Dataset |
| 22 | + |
| 23 | +The expected dataset layout is: |
| 24 | + |
| 25 | +```text |
| 26 | +BarBeR - Dataset/ |
| 27 | + Annotations/VIA/ |
| 28 | + dataset/images/ |
| 29 | +``` |
| 30 | + |
| 31 | +Generate the benchmark manifest from the same image collection: |
| 32 | + |
| 33 | +```powershell |
| 34 | +python benchmark.py audit ` |
| 35 | + --images "D:/images/public-barcode-dataset/BarBeR - Dataset/dataset/images" ` |
| 36 | + --annotations "D:/images/public-barcode-dataset/BarBeR - Dataset/Annotations/VIA" ` |
| 37 | + --output manifests |
| 38 | +``` |
| 39 | + |
| 40 | +The audit validates image availability, payload structure, overlapping annotations, and exact duplicate image bytes. It writes `manifests/benchmark_manifest.jsonl`, `manifests/smoke_manifest.jsonl`, and `manifests/barber_source_files.json`. |
| 41 | + |
| 42 | +## Run a Smoke Test |
| 43 | + |
| 44 | +Store the Dynamsoft license in a local text file or set `DYNAMSOFT_LICENSE_KEY`. |
| 45 | + |
| 46 | +```powershell |
| 47 | +python benchmark.py smoke ` |
| 48 | + --images "D:/images/public-barcode-dataset/BarBeR - Dataset/dataset/images" ` |
| 49 | + --manifest manifests/smoke_manifest.jsonl ` |
| 50 | + --output results/smoke ` |
| 51 | + --license-key-file "license-key.txt" ` |
| 52 | + --repetitions 1 |
| 53 | +``` |
| 54 | + |
| 55 | +## Run the Full Benchmark |
| 56 | + |
| 57 | +```powershell |
| 58 | +python benchmark.py run ` |
| 59 | + --images "D:/images/public-barcode-dataset/BarBeR - Dataset/dataset/images" ` |
| 60 | + --manifest manifests/benchmark_manifest.jsonl ` |
| 61 | + --output results/full ` |
| 62 | + --license-key-file "license-key.txt" ` |
| 63 | + --dbr-template ReadBarcodes_Default ` |
| 64 | + --repetitions 1 |
| 65 | +``` |
| 66 | + |
| 67 | +The command is resumable. It skips existing `(sample_id, decoder, repetition)` records in `results.jsonl`, then writes `summary.json` and `results.json`. |
| 68 | + |
| 69 | +## Validate Results |
| 70 | + |
| 71 | +```powershell |
| 72 | +python tools/validate_results.py ` |
| 73 | + --results results/full/results.jsonl ` |
| 74 | + --summary results/full/summary.json ` |
| 75 | + --expected-images 7894 ` |
| 76 | + --expected-ground-truth 8615 ` |
| 77 | + --expected-repetitions 1 |
| 78 | +``` |
| 79 | + |
| 80 | +## Benchmark Results |
| 81 | + |
| 82 | +The current full run uses one repetition on 7,894 unique BarBeR images with zxing-cpp 3.1.1 and the Dynamsoft Capture Vision 3.6.1000 bundle. Recall is calculated as correct ground truth matches divided by 8,615 eligible ground truth instances. Precision is calculated as correct predictions divided by evaluated predictions, where evaluated predictions are `correct + wrong_text + wrong_format + extra_result`. |
| 83 | + |
| 84 | +| Decoder | Correct | Recall | Precision | Image all-read rate | Mean decode time | Median decode time | P95 decode time | |
| 85 | +|---|---:|---:|---:|---:|---:|---:|---:| |
| 86 | +| Dynamsoft Barcode Reader 3.6.1000 | **7,476 / 8,615** | **86.78%** | 91.49% | **86.91%** | **63.84 ms** | 44.87 ms | **173.80 ms** | |
| 87 | +| ZXing-C++ 3.1.1 | 5,809 / 8,615 | 67.43% | 92.35% | 67.24% | 70.22 ms | 42.49 ms | 233.48 ms | |
| 88 | + |
| 89 | +DBR read 1,667 more ground truth barcodes in this run and improved recall by 19.35 percentage points. ZXing-C++ had 0.86 percentage points higher precision. DBR's mean decoder call was 63.84 ms versus 70.22 ms for ZXing-C++, about 9.1% lower in this run. |
| 90 | + |
| 91 | +### Python vs C++ on the Same BarBeR Images |
| 92 | + |
| 93 | +The [C++ benchmark](https://www.dynamsoft.com/codepool/benchmark-barcode-reading-cpp-zxing-dynamsoft-barcode-reader.html) ran the identical 7,894-image manifest with ZXing-C++ 3.1.0 and Dynamsoft Barcode Reader 11.4.20.7177. This Python run uses ZXing-C++ 3.1.1 and the Dynamsoft Capture Vision 3.6.1000 bundle, whose bundled engine is Dynamsoft Barcode Reader 11.6.10.8373. |
| 94 | + |
| 95 | +| Decoder | Run | Correct | Recall | Mean decode time | |
| 96 | +|---|---|---:|---:|---:| |
| 97 | +| Dynamsoft Barcode Reader | C++ 11.4.20.7177 | 7,444 / 8,615 | 86.41% | 70.08 ms | |
| 98 | +| Dynamsoft Barcode Reader | Python 11.6.10.8373 | 7,476 / 8,615 | 86.78% | 63.84 ms | |
| 99 | +| ZXing-C++ | C++ 3.1.0 | 5,855 / 8,615 | 67.96% | 74.09 ms | |
| 100 | +| ZXing-C++ | Python 3.1.1 | 5,809 / 8,615 | 67.43% | 70.22 ms | |
| 101 | + |
| 102 | +On the same BarBeR images, the newer DBR engine in the Python bundle improved recall by 0.37 percentage points and cut mean decode time by about 8.9% compared with the C++ release used in the earlier article. ZXing-C++ 3.1.1 in Python read fewer barcodes than ZXing-C++ 3.1.0 in C++ on this dataset, while the Python binding and newer revision delivered a faster mean decode time in this run. |
| 103 | + |
| 104 | +## Generate the HTML Report |
| 105 | + |
| 106 | +Record the Python runtime environment: |
| 107 | + |
| 108 | +```powershell |
| 109 | +python benchmark.py write-environment ` |
| 110 | + --output configs/benchmark_environment.json ` |
| 111 | + --repetitions 1 ` |
| 112 | + --dbr-template ReadBarcodes_Default |
| 113 | +``` |
| 114 | + |
| 115 | +Generate the report: |
| 116 | + |
| 117 | +```powershell |
| 118 | +python tools/generate_html_report.py ` |
| 119 | + --inventory manifests/barber_source_files.json ` |
| 120 | + --environment configs/benchmark_environment.json ` |
| 121 | + --results results/full/results.jsonl ` |
| 122 | + --results-json results/full/results.json ` |
| 123 | + --summary results/full/summary.json ` |
| 124 | + --output report/index.html |
| 125 | +``` |
| 126 | + |
| 127 | +## Matching Rules |
| 128 | + |
| 129 | +- Ground truth and predictions are matched one to one as multisets. |
| 130 | +- The key is canonical barcode format plus exact normalized payload. |
| 131 | +- UPC-A and the equivalent zero-prefixed EAN-13 value are treated as equal. |
| 132 | +- DBR `CODE39EXTENDED` output is treated as `CODE_39` when the payload matches. |
| 133 | +- Barcode location is not part of the score. |
| 134 | +- Unsupported formats remain visible in coverage-adjusted metrics. |
| 135 | +- Decoder and input pipeline errors are explicit outcomes, not no-read results. |
| 136 | + |
| 137 | + |
0 commit comments