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
- Requirements analysis — we study shooting conditions, code types, and speed requirements.
- Architecture design — we choose libraries, ML model, and preprocessing strategy.
- Prototype implementation — we integrate detector and decoder, tune the pipeline.
- Load testing — we run on your data, measure accuracy and latency.
- Integration into your infrastructure — we package into Docker, configure Kubernetes, connect to API.
- 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.







