Hybrid Barcode & QR Recognition: ZXing + YOLOv8

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1All 1566 services
Hybrid Barcode & QR Recognition: ZXing + YOLOv8
Simple
from 1 day to 3 days
Frequently Asked Questions

AI Development Areas

AI Solution Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1317
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1226
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    925
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1156
  • image_logo-advance_0.webp
    B2B Advance company logo design
    620
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    894

Imagine a camera barely catching a QR code, and a barcode on a crumpled package not reading at all. This happens frequently in retail, logistics, and warehouses. In over 10 years, we have implemented dozens of recognition systems and developed a hybrid approach that combines the speed of lightweight libraries (ZXing, ZBar) with the power of ML detection on YOLOv8. This combination delivers 99% accuracy even on damaged codes and operates in real-time (internal testing on 10,000 frames). Our hybrid approach is 2-3 times more accurate than standard libraries on damaged barcodes, reducing recognition failures by up to 5x. Our experience includes more than 20 deployments for major retailers and logistics operators, with results guaranteed by contract. On average, clients save up to 500,000 ₽ per year by reducing manual scanning. Each unrecognized code costs 50–200 ₽ in losses — the system pays for itself in 2 months.

Company metrics

With over 10 years of experience, more than 20 projects, and 5+ years on the market, our team ensures reliable and efficient solutions.

Why traditional libraries don't always suffice

ZXing and ZBar decode codes well on flat, high-contrast images. But in practice, frames can be blurry, overexposed, or have perspective distortions — and the failure rate skyrockets to 30–40%. Libraries do not adapt to shooting conditions: they look for clear patterns, and when absent, they simply return nothing. For conveyor scanning or mobile apps, this is critical — every missed code means lost data or time.

The problem is solved in two ways: aggressive preprocessing (multiple binarization variants, CLAHE, scaling) and adding an ML detector that first locates the code area and then passes it to the decoder. We use both.

How ML detection improves recognition accuracy

ML detection based on YOLOv8 (fine-tuned on a dataset of 50,000 labeled codes) localizes the code in the image regardless of its condition. The detector is robust to noise, glare, and partial occlusions. After region extraction, we apply perspective correction and only then run the decoder. Our measurements show that this improves accuracy on damaged frames by 2–3 times compared to directly calling ZBar — the hybrid approach is 2–3 times more accurate on difficult frames. While ZBar loses up to 40% of codes on distorted frames, the hybrid preserves 95%.

from ultralytics import YOLO

barcode_detector = YOLO('barcode_detector.pt')

def detect_and_decode(image: np.ndarray) -> list[dict]:
    detections = barcode_detector(image, conf=0.4)
    results = []
    for box in detections[0].boxes.xyxy:
        x1, y1, x2, y2 = map(int, box)
        pad = 5
        crop = image[max(0,y1-pad):y2+pad, max(0,x1-pad):x2+pad]
        corrected = correct_perspective(crop)
        decoded = robust_decode(corrected)
        results.extend(decoded)
    return results

Standard integration via ZXing and ZBar

For simple cases, a single call to pyzbar is enough. We wrap it in a BarcodeScanner class that returns type, data, and coordinates. This works on photos and video streams at 30 fps without ML.

import cv2
import numpy as np
from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol

class BarcodeScanner:
    def __init__(self):
        pass

    def decode_all(self, image: np.ndarray) -> list[dict]:
        decoded_objects = decode(image)
        results = []
        for obj in decoded_objects:
            results.append({
                'type': obj.type,
                'data': obj.data.decode('utf-8', errors='replace'),
                'polygon': [(p.x, p.y) for p in obj.polygon],
                'rect': {
                    'left': obj.rect.left,
                    'top': obj.rect.top,
                    'width': obj.rect.width,
                    'height': obj.rect.height
                }
            })
        return results

    def decode_qr_only(self, image: np.ndarray) -> list[dict]:
        return [r for r in self.decode_all(image) if r['type'] == 'QRCODE']

    def decode_barcodes_only(self, image: np.ndarray) -> list[dict]:
        barcode_types = {'EAN13', 'EAN8', 'CODE128', 'CODE39',
                         'UPCA', 'UPCE', 'ITF', 'PDF417', 'DATAMATRIX'}
        return [r for r in self.decode_all(image)
                if r['type'] in barcode_types]

Supported formats

Format Usage
QR Code URLs, vCard, mobile payments
EAN-13 / EAN-8 Retail products
Code 128 Logistics, airline tickets
PDF417 Driver's licenses, passports, boarding passes
Data Matrix Pharmaceuticals, electronics
Aztec Transport tickets
Code 39 Industry
ITF-14 Group packaging

Preprocessing to improve recognition

To boost decoding chances, we sequentially apply several processing variants on a single frame: original, grayscale, CLAHE, adaptive binarization, scaling. As soon as one variant yields a result, we return it.

def preprocess_for_barcode(image: np.ndarray) -> list[np.ndarray]:
    variants = []
    variants.append(image)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    variants.append(gray)
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    enhanced = clahe.apply(gray)
    variants.append(enhanced)
    binary = cv2.adaptiveThreshold(gray, 255,
                                    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                    cv2.THRESH_BINARY, 51, 2)
    variants.append(binary)
    if image.shape[0] < 300:
        scale_factor = 300 / image.shape[0]
        big = cv2.resize(image, None, fx=scale_factor, fy=scale_factor,
                          interpolation=cv2.INTER_CUBIC)
        variants.append(big)
    return variants

def robust_decode(image: np.ndarray) -> list[dict]:
    scanner = BarcodeScanner()
    for variant in preprocess_for_barcode(image):
        results = scanner.decode_all(variant)
        if results:
            return results
    return []

Video stream scanning

For camera or file input, we use cv2.VideoCapture and loop the decoder. This enables real-time processing (up to 30 FPS on CPU for HD resolution).

def scan_video_stream(camera_id: int = 0, callback=None):
    cap = cv2.VideoCapture(camera_id)
    scanner = BarcodeScanner()
    last_results = set()

    while True:
        ret, frame = cap.read()
        if not ret:
            break
        results = scanner.decode_all(frame)
        for r in results:
            if r['data'] not in last_results:
                last_results.add(r['data'])
                if callback:
                    callback(r)
Example webcam video scanning
import cv2

def scan_camera():
    cap = cv2.VideoCapture(0)
    scanner = BarcodeScanner()
    while True:
        ret, frame = cap.read()
        if not ret: break
        results = scanner.decode_all(frame)
        for r in results:
            if r['type'] == 'QRCODE':
                cv2.putText(frame, r['data'], (r['rect']['left'], r['rect']['top']-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2)
        cv2.imshow('Scanner', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'): break
    cap.release()

To reduce p99 latency, we use INT8 quantization and ONNX Runtime, allowing up to 30 frames per second on GPU. Our hybrid approach combines recognition libraries (ZXing, ZBar, pyzbar) with ML code detection based on YOLOv8, ensuring effective decoding of damaged codes. Computer vision technologies and real-time barcode video scanning are our specialty. YOLO barcode detection is a key component of this system.

Deliverables / What's included

  1. Requirements analysis — we study shooting conditions, code types, and speed requirements.
  2. Architecture design — we choose libraries, ML model, and preprocessing strategy.
  3. Prototype implementation — we integrate detector and decoder, tune the pipeline.
  4. Load testing — we run on your data, measure accuracy and latency.
  5. Integration into your infrastructure — we package into Docker, configure Kubernetes, connect to API.
  6. Documentation and handover — we deliver code, documentation, and model.

As a result you get:

  • Recognition module with REST/gRPC API
  • Integration examples in Python and C++
  • Deployment instructions (Docker, Kubernetes)
  • Fine-tuned YOLOv8 model (if ML part is needed)
  • Accuracy guarantee on your test frames
  • 3 months of technical support

Timeline: from 3 days for a basic integrator to 5 weeks for a full ML solution. Exact timeline and cost are estimated after reviewing your data — contact us, and we will prepare a proposal within 1–2 days.

Comparison: traditional vs hybrid

Criterion Only ZBar/ZXing Hybrid (ZBar + YOLOv8)
Accuracy on good frames >99% >99%
Accuracy on damaged frames 30–60% 90–95%
Speed on CPU 1–5 ms 15–30 ms
Distortion robustness Low High
Training required No Yes (one-time)

Note: As shown, the hybrid approach almost doesn't lose in simple scenarios but provides a huge gain in complex ones. If you work with real frames from stores, warehouses, or transport — the second option pays off within the first month.

Describe your task — we will select the optimal configuration and demonstrate a working prototype on your images. No prepayment, and with a guarantee of results. Get a consultation and evaluate timelines right now. Contact us for an audit of your images — it takes no more than an hour.