| | import cv2 |
| | import numpy as np |
| | from PIL import Image |
| | import zxingcpp |
| | import barcodenumber |
| |
|
| | class Barcode: |
| | def __init__(self): |
| | self._SYM_ALIAS = { |
| | 'EAN13': 'ean13', |
| | 'EAN8': 'ean8', |
| | 'UPCA': 'upc', |
| | 'UPC-A': 'upc', |
| | } |
| |
|
| | def validate_barcode(self, data: str, sym: str) -> bool: |
| | |
| | if not data: |
| | return False |
| | |
| | |
| | if sym.upper() not in self._SYM_ALIAS: |
| | if data.isdigit(): |
| | for known_format in ['ean13', 'ean8', 'upc']: |
| | try: |
| | if barcodenumber.check_code(known_format, data): |
| | return True |
| | except (ValueError, KeyError): |
| | continue |
| | |
| | return False |
| | |
| | |
| | code = self._SYM_ALIAS.get(sym, sym.lower()) |
| | try: |
| | return barcodenumber.check_code(code, data) |
| | except (ValueError, KeyError): |
| | return False |
| |
|
| | def scan_and_validate(self, image, show_image: bool = False): |
| | |
| | if isinstance(image, np.ndarray): |
| | cv_img = image.copy() |
| | else: |
| | |
| | cv_img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) |
| |
|
| | |
| | pil_for_scan = Image.fromarray(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)) |
| | barcodes = zxingcpp.read_barcodes(pil_for_scan) |
| |
|
| | results = [] |
| | for i, barcode in enumerate(barcodes): |
| | pos = barcode.position |
| | if pos: |
| | pts = [pos.top_left, pos.top_right, pos.bottom_right, pos.bottom_left] |
| | xs = [p.x for p in pts] |
| | ys = [p.y for p in pts] |
| | x, y = int(min(xs)), int(min(ys)) |
| | w, h = int(max(xs) - x), int(max(ys) - y) |
| | else: |
| | x, y, w, h = 0, 0, 100, 50 |
| |
|
| | raw = barcode.text |
| | sym = str(barcode.format) |
| | ok = self.validate_barcode(raw, sym) |
| |
|
| | |
| | barcode_result = { |
| | 'id': f'BARCODE_{i+1:03d}', |
| | 'type': sym, |
| | 'data': raw, |
| | 'valid': ok, |
| | 'position': { |
| | 'x': x, |
| | 'y': y, |
| | 'width': w, |
| | 'height': h, |
| | 'top_left': {'x': x, 'y': y}, |
| | 'top_right': {'x': x + w, 'y': y}, |
| | 'bottom_right': {'x': x + w, 'y': y + h}, |
| | 'bottom_left': {'x': x, 'y': y + h} |
| | } |
| | } |
| | |
| | results.append(barcode_result) |
| |
|
| | return results |
| |
|
| | def draw_box(self, img, x, y, w, h, sym, raw, ok): |
| | color = (0,255,0) if ok else (0,0,255) |
| | cv2.rectangle(img, (x,y), (x+w, y+h), color, 2) |
| | cv2.putText(img, f"{sym}:{raw}", (x, y-10), |
| | cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) |
| | return img |