看网页的时候出现二维码怎么快速识别?一般人可能会掏出手机。手机识别有两个问题:1,对着屏幕,会有摩尔纹的干扰。2,识别结果不能在电脑上立刻使用。如果做个截屏小工具来识别,会方便很多。
安装Python依赖包
pip install pillow opencv-Python dbr pyside2
- 用Qt搭建UI
- 创建一个自定义的全屏Qt widget
- 监听鼠标事件,获得区域
- 用PIL里的接口根据坐标抓图
- 调用Dynamsoft Barcode Reader的接口识别二维码
打开UI编辑器(路径:Python37\Lib\site-packages\PySide2\designer.exe)创建界面。
- 两个按钮分别用于区域截图和全屏截图
- 中间区域是用于显示图片的QLabel
把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
,