| 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 |