使用Python3+PyQT5+Pyserial 实现简单的串口工具方法


Posted in Python onFebruary 13, 2019

练手项目,先上图

使用Python3+PyQT5+Pyserial 实现简单的串口工具方法

先实现一个简单的串口工具,为之后的上位机做准备

代码如下:

github 下载地址

pyserial_demo.py

import sys
import serial
import serial.tools.list_ports
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QTimer
from ui_demo_1 import Ui_Form


class Pyqt5_Serial(QtWidgets.QWidget, Ui_Form):
  def __init__(self):
    super(Pyqt5_Serial, self).__init__()
    self.setupUi(self)
    self.init()
    self.setWindowTitle("串口小助手")
    self.ser = serial.Serial()
    self.port_check()

    # 接收数据和发送数据数目置零
    self.data_num_received = 0
    self.lineEdit.setText(str(self.data_num_received))
    self.data_num_sended = 0
    self.lineEdit_2.setText(str(self.data_num_sended))

  def init(self):
    # 串口检测按钮
    self.s1__box_1.clicked.connect(self.port_check)

    # 串口信息显示
    self.s1__box_2.currentTextChanged.connect(self.port_imf)

    # 打开串口按钮
    self.open_button.clicked.connect(self.port_open)

    # 关闭串口按钮
    self.close_button.clicked.connect(self.port_close)

    # 发送数据按钮
    self.s3__send_button.clicked.connect(self.data_send)

    # 定时发送数据
    self.timer_send = QTimer()
    self.timer_send.timeout.connect(self.data_send)
    self.timer_send_cb.stateChanged.connect(self.data_send_timer)

    # 定时器接收数据
    self.timer = QTimer(self)
    self.timer.timeout.connect(self.data_receive)

    # 清除发送窗口
    self.s3__clear_button.clicked.connect(self.send_data_clear)

    # 清除接收窗口
    self.s2__clear_button.clicked.connect(self.receive_data_clear)

  # 串口检测
  def port_check(self):
    # 检测所有存在的串口,将信息存储在字典中
    self.Com_Dict = {}
    port_list = list(serial.tools.list_ports.comports())
    self.s1__box_2.clear()
    for port in port_list:
      self.Com_Dict["%s" % port[0]] = "%s" % port[1]
      self.s1__box_2.addItem(port[0])
    if len(self.Com_Dict) == 0:
      self.state_label.setText(" 无串口")

  # 串口信息
  def port_imf(self):
    # 显示选定的串口的详细信息
    imf_s = self.s1__box_2.currentText()
    if imf_s != "":
      self.state_label.setText(self.Com_Dict[self.s1__box_2.currentText()])

  # 打开串口
  def port_open(self):
    self.ser.port = self.s1__box_2.currentText()
    self.ser.baudrate = int(self.s1__box_3.currentText())
    self.ser.bytesize = int(self.s1__box_4.currentText())
    self.ser.stopbits = int(self.s1__box_6.currentText())
    self.ser.parity = self.s1__box_5.currentText()

    try:
      self.ser.open()
    except:
      QMessageBox.critical(self, "Port Error", "此串口不能被打开!")
      return None

    # 打开串口接收定时器,周期为2ms
    self.timer.start(2)

    if self.ser.isOpen():
      self.open_button.setEnabled(False)
      self.close_button.setEnabled(True)
      self.formGroupBox1.setTitle("串口状态(已开启)")

  # 关闭串口
  def port_close(self):
    self.timer.stop()
    self.timer_send.stop()
    try:
      self.ser.close()
    except:
      pass
    self.open_button.setEnabled(True)
    self.close_button.setEnabled(False)
    self.lineEdit_3.setEnabled(True)
    # 接收数据和发送数据数目置零
    self.data_num_received = 0
    self.lineEdit.setText(str(self.data_num_received))
    self.data_num_sended = 0
    self.lineEdit_2.setText(str(self.data_num_sended))
    self.formGroupBox1.setTitle("串口状态(已关闭)")

  # 发送数据
  def data_send(self):
    if self.ser.isOpen():
      input_s = self.s3__send_text.toPlainText()
      if input_s != "":
        # 非空字符串
        if self.hex_send.isChecked():
          # hex发送
          input_s = input_s.strip()
          send_list = []
          while input_s != '':
            try:
              num = int(input_s[0:2], 16)
            except ValueError:
              QMessageBox.critical(self, 'wrong data', '请输入十六进制数据,以空格分开!')
              return None
            input_s = input_s[2:].strip()
            send_list.append(num)
          input_s = bytes(send_list)
        else:
          # ascii发送
          input_s = (input_s + '\r\n').encode('utf-8')

        num = self.ser.write(input_s)
        self.data_num_sended += num
        self.lineEdit_2.setText(str(self.data_num_sended))
    else:
      pass

  # 接收数据
  def data_receive(self):
    try:
      num = self.ser.inWaiting()
    except:
      self.port_close()
      return None
    if num > 0:
      data = self.ser.read(num)
      num = len(data)
      # hex显示
      if self.hex_receive.checkState():
        out_s = ''
        for i in range(0, len(data)):
          out_s = out_s + '{:02X}'.format(data[i]) + ' '
        self.s2__receive_text.insertPlainText(out_s)
      else:
        # 串口接收到的字符串为b'123',要转化成unicode字符串才能输出到窗口中去
        self.s2__receive_text.insertPlainText(data.decode('iso-8859-1'))

      # 统计接收字符的数量
      self.data_num_received += num
      self.lineEdit.setText(str(self.data_num_received))

      # 获取到text光标
      textCursor = self.s2__receive_text.textCursor()
      # 滚动到底部
      textCursor.movePosition(textCursor.End)
      # 设置光标到text中去
      self.s2__receive_text.setTextCursor(textCursor)
    else:
      pass

  # 定时发送数据
  def data_send_timer(self):
    if self.timer_send_cb.isChecked():
      self.timer_send.start(int(self.lineEdit_3.text()))
      self.lineEdit_3.setEnabled(False)
    else:
      self.timer_send.stop()
      self.lineEdit_3.setEnabled(True)

  # 清除显示
  def send_data_clear(self):
    self.s3__send_text.setText("")

  def receive_data_clear(self):
    self.s2__receive_text.setText("")


if __name__ == '__main__':
  app = QtWidgets.QApplication(sys.argv)
  myshow = Pyqt5_Serial()
  myshow.show()
  sys.exit(app.exec_())

ui_demo_1.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'demo_1.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
  def setupUi(self, Form):
    Form.setObjectName("Form")
    Form.resize(707, 458)
    self.formGroupBox = QtWidgets.QGroupBox(Form)
    self.formGroupBox.setGeometry(QtCore.QRect(20, 20, 167, 301))
    self.formGroupBox.setObjectName("formGroupBox")
    self.formLayout = QtWidgets.QFormLayout(self.formGroupBox)
    self.formLayout.setContentsMargins(10, 10, 10, 10)
    self.formLayout.setSpacing(10)
    self.formLayout.setObjectName("formLayout")
    self.s1__lb_1 = QtWidgets.QLabel(self.formGroupBox)
    self.s1__lb_1.setObjectName("s1__lb_1")
    self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.s1__lb_1)
    self.s1__box_1 = QtWidgets.QPushButton(self.formGroupBox)
    self.s1__box_1.setAutoRepeatInterval(100)
    self.s1__box_1.setDefault(True)
    self.s1__box_1.setObjectName("s1__box_1")
    self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.s1__box_1)
    self.s1__lb_2 = QtWidgets.QLabel(self.formGroupBox)
    self.s1__lb_2.setObjectName("s1__lb_2")
    self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.s1__lb_2)
    self.s1__box_2 = QtWidgets.QComboBox(self.formGroupBox)
    self.s1__box_2.setObjectName("s1__box_2")
    self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.s1__box_2)
    self.s1__lb_3 = QtWidgets.QLabel(self.formGroupBox)
    self.s1__lb_3.setObjectName("s1__lb_3")
    self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.s1__lb_3)
    self.s1__box_3 = QtWidgets.QComboBox(self.formGroupBox)
    self.s1__box_3.setObjectName("s1__box_3")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.s1__box_3.addItem("")
    self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.s1__box_3)
    self.s1__lb_4 = QtWidgets.QLabel(self.formGroupBox)
    self.s1__lb_4.setObjectName("s1__lb_4")
    self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.s1__lb_4)
    self.s1__box_4 = QtWidgets.QComboBox(self.formGroupBox)
    self.s1__box_4.setObjectName("s1__box_4")
    self.s1__box_4.addItem("")
    self.s1__box_4.addItem("")
    self.s1__box_4.addItem("")
    self.s1__box_4.addItem("")
    self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.s1__box_4)
    self.s1__lb_5 = QtWidgets.QLabel(self.formGroupBox)
    self.s1__lb_5.setObjectName("s1__lb_5")
    self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.s1__lb_5)
    self.s1__box_5 = QtWidgets.QComboBox(self.formGroupBox)
    self.s1__box_5.setObjectName("s1__box_5")
    self.s1__box_5.addItem("")
    self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.s1__box_5)
    self.open_button = QtWidgets.QPushButton(self.formGroupBox)
    self.open_button.setObjectName("open_button")
    self.formLayout.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.open_button)
    self.close_button = QtWidgets.QPushButton(self.formGroupBox)
    self.close_button.setObjectName("close_button")
    self.formLayout.setWidget(8, QtWidgets.QFormLayout.SpanningRole, self.close_button)
    self.s1__lb_6 = QtWidgets.QLabel(self.formGroupBox)
    self.s1__lb_6.setObjectName("s1__lb_6")
    self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.s1__lb_6)
    self.s1__box_6 = QtWidgets.QComboBox(self.formGroupBox)
    self.s1__box_6.setObjectName("s1__box_6")
    self.s1__box_6.addItem("")
    self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.s1__box_6)
    self.state_label = QtWidgets.QLabel(self.formGroupBox)
    self.state_label.setText("")
    self.state_label.setTextFormat(QtCore.Qt.AutoText)
    self.state_label.setScaledContents(True)
    self.state_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
    self.state_label.setObjectName("state_label")
    self.formLayout.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.state_label)
    self.verticalGroupBox = QtWidgets.QGroupBox(Form)
    self.verticalGroupBox.setGeometry(QtCore.QRect(210, 20, 401, 241))
    self.verticalGroupBox.setObjectName("verticalGroupBox")
    self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalGroupBox)
    self.verticalLayout.setContentsMargins(10, 10, 10, 10)
    self.verticalLayout.setObjectName("verticalLayout")
    self.s2__receive_text = QtWidgets.QTextBrowser(self.verticalGroupBox)
    self.s2__receive_text.setObjectName("s2__receive_text")
    self.verticalLayout.addWidget(self.s2__receive_text)
    self.verticalGroupBox_2 = QtWidgets.QGroupBox(Form)
    self.verticalGroupBox_2.setGeometry(QtCore.QRect(210, 280, 401, 101))
    self.verticalGroupBox_2.setObjectName("verticalGroupBox_2")
    self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.verticalGroupBox_2)
    self.verticalLayout_2.setContentsMargins(10, 10, 10, 10)
    self.verticalLayout_2.setObjectName("verticalLayout_2")
    self.s3__send_text = QtWidgets.QTextEdit(self.verticalGroupBox_2)
    self.s3__send_text.setObjectName("s3__send_text")
    self.verticalLayout_2.addWidget(self.s3__send_text)
    self.s3__send_button = QtWidgets.QPushButton(Form)
    self.s3__send_button.setGeometry(QtCore.QRect(620, 310, 61, 31))
    self.s3__send_button.setObjectName("s3__send_button")
    self.s3__clear_button = QtWidgets.QPushButton(Form)
    self.s3__clear_button.setGeometry(QtCore.QRect(620, 350, 61, 31))
    self.s3__clear_button.setObjectName("s3__clear_button")
    self.formGroupBox1 = QtWidgets.QGroupBox(Form)
    self.formGroupBox1.setGeometry(QtCore.QRect(20, 340, 171, 101))
    self.formGroupBox1.setObjectName("formGroupBox1")
    self.formLayout_2 = QtWidgets.QFormLayout(self.formGroupBox1)
    self.formLayout_2.setContentsMargins(10, 10, 10, 10)
    self.formLayout_2.setSpacing(10)
    self.formLayout_2.setObjectName("formLayout_2")
    self.label = QtWidgets.QLabel(self.formGroupBox1)
    self.label.setObjectName("label")
    self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
    self.label_2 = QtWidgets.QLabel(self.formGroupBox1)
    self.label_2.setObjectName("label_2")
    self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2)
    self.lineEdit = QtWidgets.QLineEdit(self.formGroupBox1)
    self.lineEdit.setObjectName("lineEdit")
    self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit)
    self.lineEdit_2 = QtWidgets.QLineEdit(self.formGroupBox1)
    self.lineEdit_2.setObjectName("lineEdit_2")
    self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_2)
    self.hex_send = QtWidgets.QCheckBox(Form)
    self.hex_send.setGeometry(QtCore.QRect(620, 280, 71, 16))
    self.hex_send.setObjectName("hex_send")
    self.hex_receive = QtWidgets.QCheckBox(Form)
    self.hex_receive.setGeometry(QtCore.QRect(620, 40, 71, 16))
    self.hex_receive.setObjectName("hex_receive")
    self.s2__clear_button = QtWidgets.QPushButton(Form)
    self.s2__clear_button.setGeometry(QtCore.QRect(620, 80, 61, 31))
    self.s2__clear_button.setObjectName("s2__clear_button")
    self.timer_send_cb = QtWidgets.QCheckBox(Form)
    self.timer_send_cb.setGeometry(QtCore.QRect(260, 390, 71, 16))
    self.timer_send_cb.setObjectName("timer_send_cb")
    self.lineEdit_3 = QtWidgets.QLineEdit(Form)
    self.lineEdit_3.setGeometry(QtCore.QRect(350, 390, 61, 20))
    self.lineEdit_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
    self.lineEdit_3.setObjectName("lineEdit_3")
    self.dw = QtWidgets.QLabel(Form)
    self.dw.setGeometry(QtCore.QRect(420, 390, 54, 20))
    self.dw.setObjectName("dw")
    self.verticalGroupBox.raise_()
    self.verticalGroupBox_2.raise_()
    self.formGroupBox.raise_()
    self.s3__send_button.raise_()
    self.s3__clear_button.raise_()
    self.formGroupBox.raise_()
    self.hex_send.raise_()
    self.hex_receive.raise_()
    self.s2__clear_button.raise_()
    self.timer_send_cb.raise_()
    self.lineEdit_3.raise_()
    self.dw.raise_()

    self.retranslateUi(Form)
    QtCore.QMetaObject.connectSlotsByName(Form)

  def retranslateUi(self, Form):
    _translate = QtCore.QCoreApplication.translate
    Form.setWindowTitle(_translate("Form", "Form"))
    self.formGroupBox.setTitle(_translate("Form", "串口设置"))
    self.s1__lb_1.setText(_translate("Form", "串口检测:"))
    self.s1__box_1.setText(_translate("Form", "检测串口"))
    self.s1__lb_2.setText(_translate("Form", "串口选择:"))
    self.s1__lb_3.setText(_translate("Form", "波特率:"))
    self.s1__box_3.setItemText(0, _translate("Form", "115200"))
    self.s1__box_3.setItemText(1, _translate("Form", "2400"))
    self.s1__box_3.setItemText(2, _translate("Form", "4800"))
    self.s1__box_3.setItemText(3, _translate("Form", "9600"))
    self.s1__box_3.setItemText(4, _translate("Form", "14400"))
    self.s1__box_3.setItemText(5, _translate("Form", "19200"))
    self.s1__box_3.setItemText(6, _translate("Form", "38400"))
    self.s1__box_3.setItemText(7, _translate("Form", "57600"))
    self.s1__box_3.setItemText(8, _translate("Form", "76800"))
    self.s1__box_3.setItemText(9, _translate("Form", "12800"))
    self.s1__box_3.setItemText(10, _translate("Form", "230400"))
    self.s1__box_3.setItemText(11, _translate("Form", "460800"))
    self.s1__lb_4.setText(_translate("Form", "数据位:"))
    self.s1__box_4.setItemText(0, _translate("Form", "8"))
    self.s1__box_4.setItemText(1, _translate("Form", "7"))
    self.s1__box_4.setItemText(2, _translate("Form", "6"))
    self.s1__box_4.setItemText(3, _translate("Form", "5"))
    self.s1__lb_5.setText(_translate("Form", "校验位:"))
    self.s1__box_5.setItemText(0, _translate("Form", "N"))
    self.open_button.setText(_translate("Form", "打开串口"))
    self.close_button.setText(_translate("Form", "关闭串口"))
    self.s1__lb_6.setText(_translate("Form", "停止位:"))
    self.s1__box_6.setItemText(0, _translate("Form", "1"))
    self.verticalGroupBox.setTitle(_translate("Form", "接受区"))
    self.verticalGroupBox_2.setTitle(_translate("Form", "发送区"))
    self.s3__send_text.setHtml(_translate("Form", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">123456</p></body></html>"))
    self.s3__send_button.setText(_translate("Form", "发送"))
    self.s3__clear_button.setText(_translate("Form", "清除"))
    self.formGroupBox1.setTitle(_translate("Form", "串口状态"))
    self.label.setText(_translate("Form", "已接收:"))
    self.label_2.setText(_translate("Form", "已发送:"))
    self.hex_send.setText(_translate("Form", "Hex发送"))
    self.hex_receive.setText(_translate("Form", "Hex接收"))
    self.s2__clear_button.setText(_translate("Form", "清除"))
    self.timer_send_cb.setText(_translate("Form", "定时发送"))
    self.lineEdit_3.setText(_translate("Form", "1000"))
    self.dw.setText(_translate("Form", "ms/次"))

以上这篇使用Python3+PyQT5+Pyserial 实现简单的串口工具方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python translator使用实例
Sep 06 Python
Python批量修改文件后缀的方法
Jan 26 Python
python 字符串转列表 list 出现\ufeff的解决方法
Jun 22 Python
Tensorflow环境搭建的方法步骤
Feb 07 Python
Tensorflow使用tfrecord输入数据格式
Jun 19 Python
python实现决策树分类(2)
Aug 30 Python
python_opencv用线段画封闭矩形的实例
Dec 05 Python
浅谈python3.x pool.map()方法的实质
Jan 16 Python
Python字符串和正则表达式中的反斜杠('\')问题详解
Sep 03 Python
python 通过视频url获取视频的宽高方式
Dec 10 Python
tensorflow从ckpt和从.pb文件读取变量的值方式
May 26 Python
python asyncio 协程库的使用
Jan 21 Python
PyQt5内嵌浏览器注入JavaScript脚本实现自动化操作的代码实例
Feb 13 #Python
Python实现Event回调机制的方法
Feb 13 #Python
Python socket实现多对多全双工通信的方法
Feb 13 #Python
对python文件读写的缓冲行为详解
Feb 13 #Python
python单线程文件传输的实例(C/S)
Feb 13 #Python
Python 实现文件打包、上传与校验的方法
Feb 13 #Python
使用python3构建文件传输的方法
Feb 13 #Python
You might like
php实现点击可刷新验证码
2015/11/07 PHP
深入php内核之php in array
2015/11/10 PHP
ThinkPHP发送邮件示例代码
2016/10/08 PHP
[原创]PHP正则删除html代码中a标签并保留标签内容的方法
2017/05/23 PHP
调用jQuery滑出效果时闪烁的解决方法
2014/03/27 Javascript
jQuery实现跟随鼠标运动图层效果的方法
2015/02/02 Javascript
jquery+php实现滚动的数字特效
2015/11/29 Javascript
jQuery Mobile页面返回不需要重新get
2016/04/26 Javascript
深入理解JS DOM事件机制
2016/08/06 Javascript
js基础之DOM中document对象的常用属性方法详解
2016/10/28 Javascript
Bootstrap源码解读模态弹出框(11)
2016/12/28 Javascript
JavaScript实现的选择排序算法实例分析
2017/04/14 Javascript
JS实现禁止用户使用Ctrl+鼠标滚轮缩放网页的方法
2017/04/28 Javascript
详解Angular 4.x Injector
2017/05/04 Javascript
解决Extjs下拉框不显示的问题
2017/06/21 Javascript
Vue.js上下滚动加载组件的实例代码
2017/07/17 Javascript
jquery插件开发之选项卡制作详解
2017/08/30 jQuery
详解react-router 4.0 下服务器如何配合BrowserRouter
2017/12/29 Javascript
微信小程序数据存储与取值详解
2018/01/30 Javascript
详解JavaScript实现动态的轮播图效果
2019/04/29 Javascript
vue实现axios图片上传功能
2019/08/20 Javascript
vue设置一开始进入的页面教程
2019/10/28 Javascript
npm全局环境变量配置详解
2020/12/15 Javascript
通过python顺序修改文件名字的方法
2018/07/11 Python
对python Tkinter Text的用法详解
2018/10/11 Python
python2和python3在处理字符串上的区别详解
2019/05/29 Python
python找出一个列表中相同元素的多个索引实例
2019/06/11 Python
基于Python解密仿射密码
2019/10/21 Python
Python数据可视化:泊松分布详解
2019/12/07 Python
python 串口读取+存储+输出处理实例
2019/12/26 Python
如何使用python实现模拟鼠标点击
2020/01/06 Python
学校周年庆活动方案
2014/08/22 职场文书
检讨书大全
2015/01/27 职场文书
内勤岗位职责
2015/02/10 职场文书
Python捕获、播放和保存摄像头视频并提高视频清晰度和对比度
2022/04/14 Python
Python  序列化反序列化和异常处理的问题小结
2022/12/24 Python