Files
PartsInquiry/backend/txm/app/pyzbar_engine.py
2025-09-27 22:57:59 +08:00

83 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from typing import Dict, List, Tuple
import cv2
import numpy as np
import logging
from pyzbar.pyzbar import decode, ZBarSymbol
def _prepare_images(gray: np.ndarray, try_invert: bool, rotations: List[int]) -> List[Tuple[np.ndarray, int, bool]]:
# 返回 (图像, 旋转角度, 是否反色)
images: List[Tuple[np.ndarray, int, bool]] = []
for ang in rotations:
if ang % 360 == 0:
rot = gray
elif ang % 360 == 90:
rot = cv2.rotate(gray, cv2.ROTATE_90_CLOCKWISE)
elif ang % 360 == 180:
rot = cv2.rotate(gray, cv2.ROTATE_180)
elif ang % 360 == 270:
rot = cv2.rotate(gray, cv2.ROTATE_90_COUNTERCLOCKWISE)
else:
# 任意角度插值旋转
h, w = gray.shape[:2]
M = cv2.getRotationMatrix2D((w / 2, h / 2), ang, 1.0)
rot = cv2.warpAffine(gray, M, (w, h), flags=cv2.INTER_LINEAR)
images.append((rot, ang, False))
if try_invert:
images.append((cv2.bitwise_not(rot), ang, True))
return images
def _collect_supported_symbols() -> List[ZBarSymbol]:
names = [
"EAN13",
"EAN8",
"UPCA",
"UPCE",
"CODE128",
"CODE39",
"QRCODE",
# 兼容不同版本:有的叫 ITF有的叫 I25
"ITF",
"I25",
]
symbols: List[ZBarSymbol] = []
for n in names:
if hasattr(ZBarSymbol, n):
symbols.append(getattr(ZBarSymbol, n))
# 若列表为空,退回由 zbar 自行决定的默认集合
return symbols
def decode_with_pyzbar(image_bgr: np.ndarray, try_invert: bool, rotations: List[int]) -> List[Dict[str, str]]:
logger = logging.getLogger("pyzbar_engine")
# 输入 BGR转灰度
gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
results: List[Dict[str, str]] = []
symbols = _collect_supported_symbols()
logger.debug("调用 pyzbar: symbols=%d, rotations=%s, try_invert=%s", len(symbols) if symbols else 0, rotations, try_invert)
for img, ang, inv in _prepare_images(gray, try_invert=try_invert, rotations=rotations):
# pyzbar 要求 8bit 图像
decoded = decode(img, symbols=symbols or None)
for obj in decoded:
data = obj.data.decode("utf-8", errors="ignore")
typ = obj.type
results.append({"type": typ, "code": data})
if results:
# 若当前设置已识别出内容,继续下一个旋转场景以收集更多,但不必反复
# 这里不提前返回,以便尽量收集多结果
pass
# 去重(按 type+code
uniq = []
seen = set()
for r in results:
key = (r["type"], r["code"]) if isinstance(r, dict) else (None, None)
if key not in seen:
seen.add(key)
uniq.append(r)
logger.debug("pyzbar 返回结果数: %d", len(uniq))
return uniq