55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
"""二维码识别工具。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import cv2
|
|
import numpy as np
|
|
|
|
from .cv import _load_image, _normalize_points, _warp_qr_image
|
|
|
|
|
|
def _decode_with_detector(img: np.ndarray) -> list[str]:
|
|
detector = cv2.QRCodeDetector()
|
|
texts: list[str] = []
|
|
|
|
if hasattr(detector, "detectAndDecodeMulti"):
|
|
ok, decoded_info, points, _ = detector.detectAndDecodeMulti(img)
|
|
if ok and points is not None:
|
|
normalized_points = _normalize_points(points)
|
|
if isinstance(decoded_info, (list, tuple)):
|
|
decoded_iter = [item or "" for item in decoded_info]
|
|
else:
|
|
decoded_iter = [decoded_info or ""]
|
|
|
|
for idx, points_item in enumerate(normalized_points):
|
|
text = decoded_iter[idx] if idx < len(decoded_iter) else ""
|
|
if not text:
|
|
crop = _warp_qr_image(img, np.array(points_item, dtype=np.float32))
|
|
fallback_text, _, _ = detector.detectAndDecode(crop)
|
|
text = fallback_text or ""
|
|
if text:
|
|
texts.append(text)
|
|
if texts:
|
|
return texts
|
|
|
|
text, points, _ = detector.detectAndDecode(img)
|
|
if text:
|
|
return [text]
|
|
|
|
normalized_points = _normalize_points(points)
|
|
if normalized_points:
|
|
crop = _warp_qr_image(img, np.array(normalized_points[0], dtype=np.float32))
|
|
fallback_text, _, _ = detector.detectAndDecode(crop)
|
|
if fallback_text:
|
|
return [fallback_text]
|
|
|
|
return []
|
|
|
|
|
|
def decode_qr(image: bytes | np.ndarray | str | Path) -> list[str]:
|
|
"""识别图片中的二维码内容。"""
|
|
img = _load_image(image)
|
|
return _decode_with_detector(img)
|