Реализация распознавания штрихкодов и QR-кодов с изображений
Распознавание штрихкодов и QR-кодов — задача, которую в большинстве случаев решают специализированные библиотеки без глубокого обучения. ML-компонент добавляется для детекции кода на изображении при плохом качестве или нестандартных условиях съёмки.
Стандартная интеграция через ZXing и ZBar
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]:
"""Декодирование всех кодов на изображении"""
# pyzbar работает с PIL или numpy array
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]
Поддерживаемые форматы
| Формат | Применение |
|---|---|
| QR Code | URL, vCard, мобильные платежи |
| EAN-13 / EAN-8 | Товары в рознице |
| Code 128 | Логистика, авиабилеты |
| PDF417 | Права, паспорта, посадочные талоны |
| Data Matrix | Медицинские препараты, электроника |
| Aztec | Транспортные билеты |
| Code 39 | Промышленность |
| ITF-14 | Групповая упаковка |
Предобработка для улучшения распознавания
def preprocess_for_barcode(image: np.ndarray) -> list[np.ndarray]:
"""Несколько вариантов предобработки для повышения шансов декодирования"""
variants = []
# Оригинал
variants.append(image)
# Grayscale
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 []
ML-детекция для сложных случаев
Когда стандартные библиотеки не справляются (повреждённые коды, сильное искажение перспективы, низкое разрешение) — добавляем ML-детектор:
from ultralytics import YOLO
# YOLOv8, дообученный на датасете штрихкодов
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
Video stream сканирование
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)
| Задача | Срок |
|---|---|
| Базовое сканирование через pyzbar | 3–5 дней |
| Робастный декодер с предобработкой | 1–2 недели |
| ML-детекция + декодирование поврежденных кодов | 3–5 недель |







