一、 OpenCV 的 wechat_qrcode_WeChatQRCode
请确保四个文件完整(detect.prototxt, detect.caffemodel, sr.prototxt, sr.caffemodel)
这四个开源文件在gitee上可以搜到下载就行
gitee地址gitee模型地址_wechat-qrcode
或直接下载有时候下载不了
代码
import cv2
import os
import time
import numpy as np
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
# ========== 配置模型路径(纯英文,确保 OpenCV 可读取) ==========
MODEL_DIR = r"C:\yolov8-2\detect_3-video\wechat-qrcode-master\data"
DETECT_PROTOTXT = os.path.join(MODEL_DIR, "detect.prototxt")
DETECT_CAFFEMODEL = os.path.join(MODEL_DIR, "detect.caffemodel")
SR_PROTOTXT = os.path.join(MODEL_DIR, "sr.prototxt")
SR_CAFFEMODEL = os.path.join(MODEL_DIR, "sr.caffemodel")
# 全局初始化检测器(只初始化一次,提高性能)
try:
qr_detector = cv2.wechat_qrcode_WeChatQRCode(
DETECT_PROTOTXT, DETECT_CAFFEMODEL,
SR_PROTOTXT, SR_CAFFEMODEL
)
print("微信二维码检测器初始化成功")
except Exception as e:
print(f"检测器初始化失败: {e}")
exit(1)
# ========== 全局变量 ==========
current_frame = None
save_dir_base = "images_videos"
save_counter = 0
display_text = ""
display_until = 0.0
# ---------- 中文字体 ----------
def get_chinese_font(font_size=36):
font_paths = [
"C:/Windows/Fonts/simhei.ttf",
"C:/Windows/Fonts/simsun.ttc",
"C:/Windows/Fonts/simfang.ttf",
]
for path in font_paths:
if os.path.exists(path):
return ImageFont.truetype(path, font_size)
return ImageFont.load_default()
try:
chinese_font = get_chinese_font(36)
except:
print("警告:未找到中文字体,中文可能显示为方框。")
chinese_font = ImageFont.load_default()
def draw_chinese_text_opencv(img_bgr, text, position, font, color_bgr=(0,255,0)):
"""在 OpenCV 图像上绘制中文(使用 PIL)"""
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
pil_img = Image.fromarray(img_rgb)
draw = ImageDraw.Draw(pil_img)
color_rgb = (color_bgr[2], color_bgr[1], color_bgr[0])
draw.text(position, text, font=font, fill=color_rgb)
return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
# ---------- 鼠标回调:左键保存原始图像 ----------
def mouse_callback(event, x, y, flags, param):
global current_frame, save_counter, display_text, display_until
if event == cv2.EVENT_LBUTTONDOWN and current_frame is not None:
save_counter += 1
now = datetime.now()
subdir_name = now.strftime("%Y-%m-%d_%H-%M-%S")
save_path = os.path.join(save_dir_base, subdir_name)
os.makedirs(save_path, exist_ok=True)
filename = now.strftime("%Y-%m-%d_%H-%M-%S-%f") + ".png"
full_path = os.path.join(save_path, filename)
cv2.imwrite(full_path, current_frame.copy())
print(f"已保存图像: {full_path}")
display_text = f"保存第 {save_counter} 张"
display_until = time.time() + 1.5
# ---------- 摄像头曝光/对焦调节 ----------
def adjust_camera(cap):
try:
# 自动曝光 -> 手动
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.0)
print("已关闭自动曝光(手动模式)")
except:
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.25)
print("尝试设置 AUTO_EXPOSURE = 0.25")
# 曝光值(常用 -6 ~ -2)
if not cap.set(cv2.CAP_PROP_EXPOSURE, -3.0):
cap.set(cv2.CAP_PROP_EXPOSURE, 0.5)
cap.set(cv2.CAP_PROP_BRIGHTNESS, 0.5)
cap.set(cv2.CAP_PROP_GAIN, 0.5)
# 手动对焦
cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
cap.set(cv2.CAP_PROP_FOCUS, 100)
print("摄像头参数已设置(手动曝光、手动对焦)")
# ---------- 二维码检测(使用微信检测器)----------
def decode_qrcodes_wechat(frame, display_frame, font):
"""
使用 cv2.wechat_qrcode_WeChatQRCode 检测二维码,
在 display_frame 上绘制绿色边框和解码文本。
"""
res, points = qr_detector.detectAndDecode(frame)
if res:
for i, info in enumerate(res):
if info:
pts = points[i].astype(int)
# 绘制多边形边框
cv2.polylines(display_frame, [pts], True, (0, 255, 0), 2)
# 获取矩形区域(用于文本定位)
x_min = int(pts[:, 0].min())
y_min = int(pts[:, 1].min())
# 文本显示在二维码上方,避免超出画面
text_y = y_min - 10 if y_min - 10 > 20 else y_min + 30
# 绘制文本(支持中文)
display_frame = draw_chinese_text_opencv(
display_frame, f"QR: {info}",
(x_min, text_y), font, (0, 255, 0)
)
print(f"[二维码] {info}")
return display_frame
# ---------- 主函数 ----------
def main():
global current_frame
# 打开摄像头(索引1,可根据需要修改)
cap = cv2.VideoCapture(1, cv2.CAP_DSHOW)
if not cap.isOpened():
print("错误:无法打开摄像头1,尝试索引0...")
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
if not cap.isOpened():
print("无法打开任何摄像头")
return
adjust_camera(cap)
# 设置期望分辨率(可修改)
desired_width, desired_height = 1280, 720 # 推荐 720p 保证流畅度和识别率
cap.set(cv2.CAP_PROP_FRAME_WIDTH, desired_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, desired_height)
actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"实际分辨率: {actual_w}x{actual_h}")
# 可选:如果实际分辨率不理想,可以尝试备选分辨率
if (actual_w, actual_h) != (desired_width, desired_height):
fallback = [(1920,1080), (1280,720), (640,480)]
for w,h in fallback:
cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
tw, th = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
if (tw,th) == (w,h):
print(f"成功设置分辨率为 {w}x{h}")
break
print(f"最终帧宽度: {cap.get(cv2.CAP_PROP_FRAME_WIDTH)}")
print(f"最终帧高度: {cap.get(cv2.CAP_PROP_FRAME_HEIGHT)}")
print("操作说明:")
print(" - 鼠标左键单击 -> 保存当前画面(不包含框和文字)")
print(" - 二维码会被绿色框标出,并显示内容")
print(" - 按 'q' 键退出")
window_name = "WeChat QR Scanner (Left click save, q exit)"
cv2.namedWindow(window_name)
cv2.setMouseCallback(window_name, mouse_callback)
os.makedirs(save_dir_base, exist_ok=True)
while True:
ret, frame = cap.read()
if not ret:
print("错误:无法读取摄像头帧")
break
# 保存原始帧(供鼠标保存使用)
current_frame = frame.copy()
# 显示用副本(会绘制二维码框和文字)
display_frame = frame.copy()
# 二维码检测
display_frame = decode_qrcodes_wechat(frame, display_frame, chinese_font)
# 显示"保存第X张"提示(绿色文字,持续1.5秒)
if display_text and time.time() < display_until:
display_frame = draw_chinese_text_opencv(
display_frame, display_text,
(20, 50), chinese_font, (0, 255, 0)
)
cv2.imshow(window_name, display_frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
二、二维码和条形码生成,参考下面文章