| """ |
| Barcode detection + decoding provider. |
| |
| Uses OpenCV's cv2.barcode.BarcodeDetector (available since OpenCV 4.5.2). |
| Detects and decodes common 1D/2D barcodes (EAN, UPC, Code39, Code128, etc.). |
| |
| Pure OpenCV — no external deps. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import cv2 |
| import numpy as np |
|
|
| from config.settings import Settings, settings as _default_settings |
| from pipeline.feature_extraction import PipelineOutput |
| from providers.base import BaseProvider, ProviderCapability |
|
|
|
|
| class BarcodeProvider(BaseProvider): |
| name = "barcode" |
| capability = ProviderCapability.OBJECT_DETECTION |
|
|
| def __init__(self, settings: Settings | None = None) -> None: |
| super().__init__(settings=settings or _default_settings) |
| self._detector = None |
| try: |
| self._detector = cv2.barcode.BarcodeDetector() |
| except AttributeError: |
| |
| pass |
|
|
| def is_available(self) -> bool: |
| return self._detector is not None |
|
|
| def _run(self, pipeline_output: PipelineOutput) -> tuple[dict, dict]: |
| if self._detector is None: |
| raise RuntimeError("BarcodeDetector not available (requires OpenCV >= 4.5.2)") |
|
|
| img: np.ndarray = pipeline_output.image |
|
|
| try: |
| ok, decoded_info, decoded_types, points = self._detector.detectAndDecode(img) |
| except Exception as e: |
| return {"error": str(e)}, {"objects": [], "model": "opencv_barcode"} |
|
|
| objects: list[dict] = [] |
| if ok and points is not None and len(points) > 0: |
| for i, (info, btype) in enumerate(zip(decoded_info, decoded_types)): |
| if i < len(points): |
| pts = points[i].reshape(-1, 2) |
| x1, y1 = int(pts[:, 0].min()), int(pts[:, 1].min()) |
| x2, y2 = int(pts[:, 0].max()), int(pts[:, 1].max()) |
| objects.append({ |
| "label": "barcode", |
| "confidence": 1.0, |
| "box": {"x": x1, "y": y1, "w": x2 - x1, "h": y2 - y1}, |
| "decoded_text": info if info else "", |
| "barcode_type": btype if btype else "", |
| "is_barcode": True, |
| }) |
|
|
| raw = { |
| "num_objects": len(objects), |
| "model": "opencv_barcode", |
| "decoded_count": sum(1 for o in objects if o["decoded_text"]), |
| } |
| normalized = { |
| "objects": objects, |
| "model": "opencv_barcode", |
| } |
| return raw, normalized |
|
|