看网页的时候出现二维码怎么快速识别?一般人可能会掏出手机。手机识别有两个问题:1,对着屏幕,会有摩尔纹的干扰。2,识别结果不能在电脑上立刻使用。如果做个截屏小工具来识别,会方便很多。

安装Python依赖包

pip install pillow opencv-Python dbr pyside2

屏幕截图识别二维码的步骤
  1. 用Qt搭建UI
  2. 创建一个自定义的全屏Qt widget
  3. 监听鼠标事件,获得区域
  4. 用PIL里的接口根据坐标抓图
  5. 调用Dynamsoft Barcode Reader的接口识别二维码
代码实现

打开UI编辑器(路径:Python37\Lib\site-packages\PySide2\designer.exe)创建界面。

我想看屏幕中的二维码:识别屏幕中的二维码(1)

把UI编译成python文件:

pyside2-uic design.ui -o design.py

把UI导入到python工程中:

from design import Ui_MainWindow class MainWindow(QMainWindow): def __init__(self, license): super(MainWindow, self).__init__() self.setWindowState(Qt.WindowMaximized) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setAcceptDrops(True)

新建SnippingTool.py文件。在里面创建一个自定义的Qt Widget:

import numpy as np import cv2 from PIL import ImageGrab from PySide2 import QtWidgets, QtCore, QtGui from PySide2.QtCore import Qt class SnippingWidget(QtWidgets.QWidget): is_snipping = False def __init__(self, parent=None, app=None): super(SnippingWidget, self).__init__() self.parent = parent self.setWindowFlags(Qt.WindowStaysOnTopHint) self.screen = app.primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height()) self.begin = QtCore.QPoint() self.end = QtCore.QPoint() self.onSnippingCompleted = None def fullscreen(self): img = ImageGrab.grab(bbox=(0, 0, self.screen.size().width(), self.screen.size().height())) try: img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: img = None if self.onSnippingCompleted is not None: self.onSnippingCompleted(img) def start(self): SnippingWidget.is_snipping = True self.setWindowOpacity(0.3) QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor)) self.show() def paintEvent(self, event): if SnippingWidget.is_snipping: brush_color = (128, 128, 255, 100) lw = 3 opacity = 0.3 else: self.begin = QtCore.QPoint() self.end = QtCore.QPoint() brush_color = (0, 0, 0, 0) lw = 0 opacity = 0 self.setWindowOpacity(opacity) qp = QtGui.QPainter(self) qp.setPen(QtGui.QPen(QtGui.QColor('black'), lw)) qp.setBrush(QtGui.QColor(*brush_color)) rect = QtCore.QRectF(self.begin, self.end) qp.drawRect(rect) def mousePressEvent(self, event): self.begin = event.pos() self.end = self.begin self.update() def mouseMoveEvent(self, event): self.end = event.pos() self.update() def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QtWidgets.QApplication.restoreOverrideCursor() x1 = min(self.begin.x(), self.end.x()) y1 = min(self.begin.y(), self.end.y()) x2 = max(self.begin.x(), self.end.x()) y2 = max(self.begin.y(), self.end.y()) self.repaint() QtWidgets.QApplication.processEvents() img = ImageGrab.grab(bbox=(x1, y1, x2, y2)) try: img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: img = None if self.onSnippingCompleted is not None: self.onSnippingCompleted(img) self.close()

在初始化的时候我们把widget设置成全屏大小:

self.screen = app.primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height())

在调用start()函数时,把widget显示出来。这个时候paintEvent()会被触发,我们在里面绘制截屏效果。

通过监听鼠标事件,我们可以获得点击和释放时候的坐标:

def mousePressEvent(self, event): self.begin = event.pos() self.end = self.begin self.update() def mouseMoveEvent(self, event): self.end = event.pos() self.update() def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QtWidgets.QApplication.restoreOverrideCursor() x1 = min(self.begin.x(), self.end.x()) y1 = min(self.begin.y(), self.end.y()) x2 = max(self.begin.x(), self.end.x()) y2 = max(self.begin.y(), self.end.y()) self.repaint() QtWidgets.QApplication.processEvents()

最后用ImageGrab.grab(bbox=(x1, y1, x2, y2))来获得屏幕的截图。全屏的坐标为img = ImageGrab.grab(bbox=(0, 0, self.screen.size().width(), self.screen.size().height()))。

获得的图像经过转换交给回调函数传出:

try: img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: img = None if self.onSnippingCompleted is not None: self.onSnippingCompleted(img)

在主函数中,初始化按钮并设置回调函数。当截屏触发的时候,我们把窗口最小化,这样就不会遮挡屏幕。得到图像之后再把程序窗口还原:

self.snippingWidget = SnippingTool.SnippingWidget(app=QApplication.instance()) self.snippingWidget.onSnippingCompleted = self.onSnippingCompleted self.ui.pushButton_area.clicked.connect(self.snipArea) self.ui.pushButton_full.clicked.connect(self.snipFull) def snipArea(self): self.setWindowState(Qt.WindowMinimized) self.snippingWidget.start() def snipFull(self): self.setWindowState(Qt.WindowMinimized) self.snippingWidget.fullscreen()

回调函数触发之后,把图像数据传给SDK解码。最后把结果绘制到QLabel上:

def onSnippingCompleted(self, frame): self.setWindowState(Qt.WindowMaximized) if frame is None: return frame, self._results = self._barcodeManager.decode_frame(frame) self.showResults(frame, self._results)

视频

源码

https://github.com/yushulx/python-gui-barcode-reader

,