QC_Rules / src /utils /barcode.py
Jakecole1's picture
Upload 18 files
863cb78 verified
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:
# Empty strings are always invalid
if not data:
return False
# For unknown symbology, try all known formats first
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
# If no known format matches, validate basic structure
return False
# For known formats, validate normally
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):
# 1) normalize to OpenCV BGR numpy array
if isinstance(image, np.ndarray):
cv_img = image.copy()
else:
# assume PIL
cv_img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
# 2) for zxing we need a PIL, so make one from cv_img
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)
# Create barcode result with position data
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