This commit is contained in:
2025-09-27 22:57:59 +08:00
parent 8a458ff0a4
commit ed26244cdb
12585 changed files with 1914308 additions and 3474 deletions

View File

@@ -0,0 +1,82 @@
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