就随便用Qt Designer弄了下,尽量用简单的布局弄得整齐些。
用到的控件基本上都是 QLabel
,QLineEdit
,QPushButton
,QFormLayout
其中粉色的那个QLabel的样式,是通过QSS实现的,具体:可以在Property属性编辑器
中
具体的值:
QLabel{
background:rgb(255,204,204);color:black;font-size:18px}
主要参考了:
注意,这个例子里采用的是 继承Qt里的QThread,而不是python中自带的Thread库
import cv2
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QImage, QPixmap
# 定义类
class Thread(QThread):
# 定义信号
changPixmap=pyqtSignal(QImage)
def run(self):
cap = cv2.VideoCapture(0)
# 或者"rtsp://admin:admin@IP:Port/11"
print(cap.isOpened(),"读取视频流正常")
while True:
ret, frame = cap.read()
if ret:
rgbImage = frame
# 这个读进来不用进行BGR2RGB的转换。。。
# rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgbImage.shape
bytesPerLine = ch * w
convert2QtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_BGR888)
p = convert2QtFormat.scaled(640, 360, Qt.KeepAspectRatio)
self.changPixmap.emit(p)
else:
continue
# 使用
class WinForm(QMainWindow,Ui_MainWindow):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.setupUi(self)
self.thread = Thread()
# 绑定信号和槽
self.thread.changPixmap.connect(self.setImage)
# 启动子线程
self.thread.start()
# 定义槽函数
@pyqtSlot(QImage)
def setImage(self, image):
self.label.setPixmap(QPixmap.fromImage(image))
# 这里的label就是显示摄像头画面的QLabel的 objectName
在网上搜了很多地方,基本都是同一个代码,让人诧异的是,谷歌上面搜到的英文博客结果竟然是抄袭国人的,也算是一个好消息,哈哈哈。
主要参考:脚本之家——PyQt5 在label显示的图片中绘制矩形的方法:其余基本都是这个的变形。
主要是把继承了一下QLabel,然后重写了QLabel对象的鼠标点击和释放事件,可以获取鼠标点击和释放的起始位置,就可以画矩形了。
如果想画多个,而不是画了一个,之前的那个就消失,可以参考
PyQt5 在 QLabel 使用 QPainter 绘制矩形
# 类定义
class MyLabel(QLabel):
x0 = 0
y0 = 0
x1 = 0
y1 = 0
flag = False
# 鼠标点击事件
def mousePressEvent(self, event):
self.flag = True
self.x0 = event.x()
self.y0 = event.y()
# 鼠标释放事件
def mouseReleaseEvent(self, event):
self.flag = False
# 鼠标移动事件
def mouseMoveEvent(self, event):
if self.flag:
self.x1 = event.x()
self.y1 = event.y()
self.update()
# 绘制事件
def paintEvent(self, event):
super().paintEvent(event)
rect = QRect(self.x0, self.y0, abs(self.x1 - self.x0), abs(self.y1 - self.y0))
painter = QPainter(self)
painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))
painter.drawRect(rect)
# 使用
self.label = MyLabel(self.centralwidget)
# 找到自己.ui文件中 实现显示视频流的那个QLabel 也就是要在其上画框的QLabel,把类名从QWidget.QLabel改成MyLabel 然后其他地方就不用改了,使用label来进行对这个对象的其他调用即可
效果类似:
先在上面这个显示视频的地方画个框
然后点击获取坐标,就可以显示新的坐标
这里是参考了书上的一部分代码《PyQt5快速开发与实战》:PyQt5/Chapter07/CallMainWinSignalSlog02.py
这个例子就是点一个按钮,传递打印
信息;按另一个按钮,传递预览
信息
参考上面的,我给出自己写的一个示例,其实很简单:
# 定义信号
configInfo=pyqtSignal(dict) # 这个信号传递的信息是dict类型的
# 绑定信号和槽
self.productConfigBtn.clicked.connect(self.emitConfigInfor)
# productConfigBtn 这个是一个QPushButton按钮的Obeject Name,按钮点击事件本来也是一种信号
self.configInfo.connect(self.productConfig)
# productConfig这是自己写的一个函数
def emitConfigInfor(self):
configValue={
}
configValue.update({
"camera_ip": self.cameraIPLE.text()})
configValue.update({
"device_name":self.deviceNameLE.text()})
configValue.update({
"device_type": self.deviceTypeLE.text()})
.............
self.configInfo.emit(configValue)
# 函数中一定要有一个emit()函数 之前定义的configInfo信号 使用emit()发射需要传递给槽的信息
# (connect函数决定了信息的发送方向)这里就是 点击了上面的productConfigBtn按钮后,使用这个emitConfigInfor函数来获取信息,并把收集到的configValue信息发送给productConfig
def productConfig(self,valueDict):
# 接受传递的json格式的信息,也就是上面的configValue,然后写入json文件
self.configDict.update(valueDict)
for k,v in self.configDict.items():
print(k,v)
jsonDir=os.path.join(self.savedPath,'configFile')
if not os.path.exists(jsonDir):
os.mkdir(jsonDir)
jsonPath=os.path.join(jsonDir,self.configDict["device_id"]+str(".json"))
print("文件保存路径:",jsonPath)
with open(jsonPath, 'w') as fp:
json.dump(self.configDict, fp,indent=4)
for i in range(5):
if os.path.exists(jsonPath):
self.statusbar.showMessage("配置文件保存成功",2000)
break
所以逻辑就是,界面上的那些需要手动输入的信息,当我按下一个生成配置文件
的按钮时,传递一个消息/信号,生成配置信息的dict,然后发送到生成配置文件的那个函数,其实可以一步完成,哈哈哈。
第一码流和第二码流,
参考监控里的主码流和子码流是什么意思:
我拿到的摄像头的主码流(第一码流)是 1920*1080,子码流(第二码流)是640*352左右。。
这个错误不是很有所谓,偶尔会出现,偶尔不出现。
[h264@0000000046ba40]error while decoding MB 105 15,bytestream -14
参考CSDN博客——h264 @ 000001d641122200 error while decoding MB 36 106, bytestream -7
目前没有什么特别有效的解决方案,就是重新初始化一遍摄像头,哈哈哈。
把保存配置的dict变量导出写入一个json文件中,
参考How to save a dictionary in a json file with python ?:其实很简单,直接采用json的dump方法就可以
import json
dict = {
"member #002":{
"first name": "John", "last name": "Doe", "age": 34},
"member #003":{
"first name": "Elijah", "last name": "Baley", "age": 27},
"member #001":{
"first name": "Jane", "last name": "Doe", "age": 42}}
with open('data.json', 'w') as fp:
json.dump(dict, fp)
如果想让写入的json格式更好看,可以加入缩进参数,例如
with open('data.json', 'w') as fp:
json.dump(dict, fp, indent=4)
如果还想让json对写入的字段进行排序,可以使用排序参数,例如:
with open('data.json', 'w') as fp:
json.dump(dict, fp, sort_keys=True, indent=4)
使用
pyinstaller -F main.py
一般参考链接都是前期调研,看大致情况的,所以实际参考的并不一定是这些链接,还是以正文为主,哈哈哈
百度搜索结果:
谷歌搜索结果:
搜索了一下labelImg的实现,看到代码中使用了canvas,地址链接——Github-canvas
下面的都是单纯绘制矩形,但是这个矩形无法显示在label层上面,其它空白的地方倒是可以看到。
获取坐标
多线程
由于获取的鼠标一直在移动,获取的坐标也一直在改变,所以需要使用一个单独的线程对坐标进行监控和获取
mousemove event statusbar show pyqt