Python 实现「PC端一键框选识别二维码」工具(附完整源码)
Python 实现「一键框选识别二维码」工具(附完整源码)🔍 一、前言:为什么要做这个工具?💡 二、使用方法🧰 三、技术栈与依赖✅ 安装依赖
📦 四、完整源码实现🎉 五、结语
Python 实现「一键框选识别二维码」工具(附完整源码)
发布日期:2025年8月25日
标签:Python, PyQt5, 二维码识别, pyzbar, pyautogui, 实用工具
🔍 一、前言:为什么要做这个工具?
在日常工作中,我们经常需要扫描网页、PDF 或截图中的二维码,但大多数情况只能借助手机扫码,非常不方便。
有没有一种方式,能直接用鼠标框选屏幕上的二维码,自动识别并复制内容?
答案是:有!而且用 Python 就能轻松实现!
今天,我将带你一步步实现一个 「二维码框选识别工具」,支持:
✅ 全局快捷键启动(
)
Ctrl+Alt+Q
✅ 鼠标拖拽框选任意区域
✅ 自动识别二维码内容
✅ 复制结果到剪贴板
✅ 弹窗提示识别结果
✅ 无需打开任何软件,秒级操作!
💡 二、使用方法
按下
鼠标拖拽选择二维码区域松开鼠标,自动识别内容复制到剪贴板,弹出提示
Ctrl + Alt + Q
👉 效果:像截图一样简单,但输出的是二维码的文本内容!
🧰 三、技术栈与依赖
本工具基于以下 Python 库构建:
库 | 用途 |
---|---|
|
创建全屏透明窗口,实现框选界面 |
|
截图、模拟操作 |
|
图像处理 |
|
二维码识别引擎 |
|
监听全局快捷键 |
|
图像数据转换 |
|
提升管理员权限(避免截图失败) |
✅ 安装依赖
创建
文件,内容如下:
requirements.txt
keyboard==0.13.5
numpy==1.24.4
opencv-python==4.11.0.86
pyautogui==0.9.54
PyQt5==5.15.11
pyzbar==0.1.9
安装命令:
pip install -r requirements.txt
📦 四、完整源码实现
import sys
import keyboard
import pyautogui
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
from PyQt5.QtCore import Qt, QObject, QEvent, QCoreApplication, QRect
from PyQt5.QtGui import QPainter, QPen, QBrush, QColor, QPainterPath
import threading
import cv2
from pyzbar import pyzbar
import numpy as np
import ctypes
import os
# ==================== 检查管理员权限 ====================
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
def run_as_admin():
if is_admin():
return True
script = os.path.abspath(sys.argv[0])
params = ' '.join([script] + sys.argv[1:])
try:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, params, None, 1)
except Exception as e:
QMessageBox.critical(None, "错误", f"无法获取管理员权限,请右键选择“以管理员身份运行”。
{e}")
return False
# ==================== 自定义事件 ====================
class CaptureEvent(QEvent):
EVENT_TYPE = QEvent.Type(QEvent.registerEventType())
# ==================== 框选截图窗口 ====================
class CaptureWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowState(Qt.WindowFullScreen)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setCursor(Qt.CrossCursor)
self.setFocusPolicy(Qt.StrongFocus)
# 📸 截图作为背景
screen = QApplication.primaryScreen()
self.screenshot_pixmap = screen.grabWindow(0)
self.start_pos = None
self.end_pos = None
self.is_drawing = False
def paintEvent(self, event):
painter = QPainter(self)
# 🖼️ 绘制截图
if self.screenshot_pixmap:
painter.drawPixmap(self.rect(), self.screenshot_pixmap)
# 🌑 变暗
painter.setCompositionMode(QPainter.CompositionMode_DestinationIn)
painter.fillRect(self.rect(), QColor(0, 0, 0, 120))
painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
# 🟩 绿色框
if self.is_drawing and self.start_pos and self.end_pos:
rect = QRect(self.start_pos, self.end_pos).normalized()
pen = QPen(QColor(0, 255, 0), 2, Qt.SolidLine)
brush = QBrush(QColor(0, 255, 0, 30))
painter.setPen(pen)
painter.setBrush(brush)
painter.drawRect(rect)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.start_pos = event.pos()
self.end_pos = event.pos()
self.is_drawing = True
self.update()
def mouseMoveEvent(self, event):
if self.is_drawing:
self.end_pos = event.pos()
self.update()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton and self.is_drawing:
self.end_pos = event.pos()
self.is_drawing = False
self.close() # ✅ 先关闭窗口
print("a")
self.capture_selected_area() # 再识别(此时窗口已关闭)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
self.close()
def capture_selected_area(self):
x1 = min(self.start_pos.x(), self.end_pos.x())
y1 = min(self.start_pos.y(), self.end_pos.y())
x2 = max(self.start_pos.x(), self.end_pos.x())
y2 = max(self.start_pos.y(), self.end_pos.y())
width = x2 - x1
height = y2 - y1
if width < 10 or height < 10:
print("❌ 区域太小,取消识别")
return
screen = QApplication.primaryScreen()
screen_x = screen.geometry().x()
screen_y = screen.geometry().y()
real_x = x1 + screen_x
real_y = y1 + screen_y
print(f"📸 截图区域: x={real_x}, y={real_y}, w={width}, h={height}")
screenshot = pyautogui.screenshot(region=(real_x, real_y, width, height))
self.recognize_qr_from_image(screenshot)
def recognize_qr_from_image(self, image):
"""识别PIL.Image中的二维码"""
try:
# 将PIL图像转为OpenCV格式 (RGB -> BGR)
cv_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
# 使用pyzbar识别二维码
decoded_objects = pyzbar.decode(cv_image)
if not decoded_objects:
print("❌ 未识别到二维码")
QMessageBox.information(None, "识别结果", "未识别到二维码,请重试。")
return
# 取第一个二维码
obj = decoded_objects[0]
data = obj.data.decode('utf-8')
print(f"✅ 识别成功: {data}")
QApplication.clipboard().setText(data)
QMessageBox.information(None, "识别成功", f"已识别并复制到剪贴板:
{data}")
'''
# 弹出消息框显示结果
msg_box = QMessageBox()
msg_box.setWindowTitle("识别结果")
msg_box.setText(f"识别内容:
{data}")
msg_box.setTextInteractionFlags(Qt.TextSelectableByMouse) # 可复制
msg_box.exec_()
'''
except Exception as e:
print(f"❌ 识别失败: {e}")
QMessageBox.critical(None, "识别失败", f"解码出错:
{e}")
# ==================== 事件接收器 ====================
class EventReceiver(QObject):
def __init__(self):
super().__init__()
self.current_window = None # ✅ 持有窗口引用
def customEvent(self, event):
print("🎯 customEvent 被触发!")
if isinstance(event, CaptureEvent):
print("🎯 检测到 CaptureEvent")
self.show_capture_window()
def show_capture_window(self):
global is_active
print("🖼️ show_capture_window 被调用")
if not is_active:
print("⚠️ 当前处于非活跃状态,忽略")
return
is_active = False
# 创建窗口
self.current_window = CaptureWindow()
# 窗口关闭后重置状态
def on_window_closed():
global is_active
is_active = True
self.current_window = None
print("✅ 窗口已关闭,状态重置")
# 使用 destroyed 信号
self.current_window.destroyed.connect(lambda: on_window_closed())
# 显示窗口
self.current_window.show()
print("✅ 全屏窗口已显示")
# ==================== 快捷键监听 ====================
def start_listener():
print("👂 监听快捷键: Ctrl+Alt+Q")
def on_hotkey():
print("✅ 检测到快捷键: Ctrl+Alt+Q")
try:
if event_receiver is None:
print("❌ event_receiver 未初始化")
return
# 注意:QCoreApplication.postEvent 返回 None 是正常的!
QCoreApplication.postEvent(event_receiver, CaptureEvent(CaptureEvent.EVENT_TYPE))
print("📤 事件已发送")
except Exception as e:
print(f"❌ 事件发送失败: {e}")
keyboard.add_hotkey('ctrl+alt+q', on_hotkey, suppress=False)
print("✅ 热键监听启动,程序将持续运行...")
try:
while True:
keyboard.wait() # 等待任意键盘事件,避免忙等待
except KeyboardInterrupt:
print("⏹️ 监听线程退出")
# ==================== 主程序 ====================
if __name__ == '__main__':
global is_active, event_receiver
if not run_as_admin():
sys.exit()
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(True)
dummy = QWidget()
dummy.hide()
is_active = True
event_receiver = EventReceiver() # ✅ 现在支持 self.current_window
event_receiver.setParent(dummy)
listener_thread = threading.Thread(target=start_listener, daemon=True)
listener_thread.start()
print("=" * 50)
print("🚀 二维码框选识别工具已启动")
print("📌 按下 Ctrl+Alt+q 开始框选")
print("✅ 支持全屏置顶、手动框选、自动识别")
print("❌ 关闭窗口退出程序")
print("=" * 50)
sys.exit(app.exec_())
🎉 五、结语
放于桌面随取随用。
版权声明:本文为 CSDN 博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文作者、出处链接及本声明。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END
暂无评论内容