ARTICLE · 1218796
零基础学ESP32:PC端界面程序更新——做一个高逼格的摄像头监控软件!
上一节课,我们用Python写了几行代码,在电脑上弹出一个窗口,实时显示了ESP32-CAM拍到的画面。虽然能看,但那个黑乎乎的命令行窗口,总觉得不够酷。
今天,我们要把电脑端的接收程序全面升级——加界面、加按钮、加功能!让它从一个“草稿纸”变成一个真正的桌面级监控软件,不仅能看画面,还能一键录制视频!
第一步:看看成品效果
你会看到本节课的最终效果:一个拥有现代化界面的监控软件。
顶部可以选择电脑IP和端口 有 “启动显示”、“开始录制”、“设置保存路径” 按钮 下方是超大、高清的实时视频画面

第二步:为什么用 PySide 而不是 PyQt?
在Python做界面,很多老手会推荐 PyQt。但这里有个大坑:
| PyQt | ||
| PySide |
由于两者的 API 几乎 100% 通用,切换起来毫无压力。所以本节课的程序,我们全面使用 PySide6(顺便帮你省下了一大笔授权费!)。
第三步:ESP32-CAM端代码(无变化)
ESP32-CAM那边什么都不用改,依然用上节课的代码,不断向电脑发送UDP图像数据就行。
import socketimport networkimport cameraimport time# 连接wifiwlan = network.WLAN(network.STA_IF)wlan.active(True)if not wlan.isconnected(): print('connecting to network...') wlan.connect('dongfeiqiu', 'wangmingdong1225') while not wlan.isconnected(): passprint('网络配置:', wlan.ifconfig())# 摄像头初始化try: camera.init(0, format=camera.JPEG)except Exception as e: camera.deinit() camera.init(0, format=camera.JPEG)# 其他设置:# 上翻下翻camera.flip(1)#左/右camera.mirror(1)# 分辨率camera.framesize(camera.FRAME_HVGA)# 选项如下:# FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240# FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA# FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD# FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA# FRAME_P_FHD FRAME_QSXGA# 有关详细信息,请查看此链接:https://bit.ly/2YOzizz# 特效camera.speffect(camera.EFFECT_NONE)#选项如下:# 效果\无(默认)效果\负效果\ BW效果\红色效果\绿色效果\蓝色效果\复古效果# EFFECT_NONE (default) EFFECT_NEG \EFFECT_BW\ EFFECT_RED\ EFFECT_GREEN\ EFFECT_BLUE\ EFFECT_RETRO# 白平衡# camera.whitebalance(camera.WB_HOME)#选项如下:# WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME# 饱和camera.saturation(0)#-2,2(默认为0). -2灰度# -2,2 (default 0). -2 grayscale # 亮度camera.brightness(0)#-2,2(默认为0). 2亮度# -2,2 (default 0). 2 brightness# 对比度camera.contrast(0)#-2,2(默认为0).2高对比度#-2,2 (default 0). 2 highcontrast# 质量camera.quality(10)#10-63数字越小质量越高# socket UDP 的创建s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)try: while True: buf = camera.capture() # 获取图像数据 s.sendto(buf, ("192.168.31.53", 9090)) # 向服务器发送图像数据 time.sleep(0.1)except: passfinally: camera.deinit()
第四步:PC端界面大更新(完整代码)
准备工作:
电脑安装依赖库:
pip install PySide6 opencv-python pillow
下载界面所需的图片素材(按钮图标等): https://doc.hardwarelab.cn/old/A0002.esp32cam/02.download/04.pc.py/ESP32.CAM.V2022.10.13.001.zip
核心代码结构:
代码分为两个主要类:
CaptureThread: 后台线程,默默在后台接收UDP视频流,处理图像并转成Qt能显示的格式。 VideoWindow: 主界面,负责显示UI、处理按钮点击事件、定时刷新画面。
import osimport socketimport sysimport winregimport timeimport ioimport cv2from PIL import Imageimport numpy as npfrom PySide6.QtCore import QTimer, QThread, QSettingsfrom PySide6.QtGui import QIcon, Qt, QImage, QPixmapfrom PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QGroupBox, QHBoxLayout, QStyle, QVBoxLayout, QStackedLayout, QLineEdit, QComboBox, QMessageBox, QFileDialogCAPTURE_IMAGE_DATA = NoneSAVE_VIDEO_PATH = ""# --------- 1. 后台接收线程 ---------class CaptureThread(QThread): def __init__(self, ip, port): super().__init__() self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) self.udp_socket.bind((ip, port)) self.run_flag = True self.record_flag = False def run(self): global CAPTURE_IMAGE_DATA while self.run_flag: data, ip = self.udp_socket.recvfrom(100000) bytes_stream = io.BytesIO(data) image = Image.open(bytes_stream) img = np.asarray(image) # 如果需要录制视频 if self.record_flag: img_2 = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) self.mp4_file.write(img_2) # 转换为Pixmap用于显示 temp_image = QImage(img.flatten(), 480, 320, QImage.Format_RGB888) temp_pixmap = QPixmap.fromImage(temp_image) CAPTURE_IMAGE_DATA = temp_pixmap self.udp_socket.close() def stop_run(self): self.run_flag = False self.record_flag = False try: self.mp4_file.release() except: pass def stop_record(self): self.mp4_file.release() self.record_flag = False def start_record(self): video_type = cv2.VideoWriter_fourcc(*'XVID') file_name = "{}.avi".format(time.time()) file_path_name = os.path.join(SAVE_VIDEO_PATH, file_name) self.mp4_file = cv2.VideoWriter(file_path_name, video_type, 5, (480, 320)) self.record_flag = True# --------- 2. 主界面 ---------class VideoWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle("远程摄像头监控 v2022.10.13.001") self.resize(777, 555) # (省略部分UI布局代码,详见完整代码...) # 初始化定时器刷新画面 self.timer = QTimer() self.timer.timeout.connect(self.show_video_image) def camera_open_close(self): if self.camera_open_close_btn.text() == "启动显示": ip = self.combox.currentText() port = int(self.port_edit.text()) self.thread = CaptureThread(ip, port) self.thread.daemon = True self.thread.start() self.timer.start(100) self.camera_open_close_btn.setText("关闭显示") else: self.camera_open_close_btn.setText("启动显示") self.timer.stop() self.stacked_layout_capture_view.video_label.clear() self.thread.stop_run() def show_video_image(self): if CAPTURE_IMAGE_DATA: self.stacked_layout_capture_view.video_label.setPixmap(CAPTURE_IMAGE_DATA)if __name__ == "__main__": app = QApplication(sys.argv) video_window = VideoWindow() video_window.show() app.exec()
第五步:核心功能解析
这个软件之所以好用,是因为它在后台巧妙地运用了这些技术:
1. 多线程接收(CaptureThread)
如果直接在UI线程里接收视频数据,界面会卡死。所以我们用 QThread 开了一个后台线程,专门默默无闻地接收数据、转码,UI线程只负责把转好的画面贴上去。
2. 视频录制功能
新增了录制按钮。在后台收到数据时,顺手丢给 cv2.VideoWriter 保存成 .avi 格式。配合“设置保存路径”按钮,录制好的视频会自动保存到你的电脑里。
3. 智能下拉框选 IP
代码用 socket.gethostbyname_ex 自动扫描你电脑的所有IP地址,并生成下拉菜单,你再也不用去cmd里敲 ipconfig 找IP了!
第六步:运行测试
先运行 PC端的这个界面程序。 点击 “启动显示” ,等待画面出现。 再运行 ESP32-CAM端代码。 视频画面瞬间点亮!
如果想录视频: 先点“设置保存路径”选个文件夹,再点“开始录制”,画面上的视频就会被保存下来。
常见问题
Q:报错 ModuleNotFoundError: No module named 'PySide6'?
A:命令行执行 pip install PySide6 安装即可。
Q:界面出来了,但视频加载不出来?
A:第一,确保ESP32-CAM代码里的IP填的是你这台电脑的IP;第二,关掉电脑防火墙;第三,确保两者连的是同一个WiFi。
Q:录制的视频在哪里?
A:点击“设置保存路径”选定的文件夹里。默认不设置是无法录制的,系统会弹窗提醒你。
全程回顾
| 安装库 | ||
| 写界面 | ||
| 运行PC端 | ||
| 运行ESP32 |
更多在线课程,请访问 https://doc.dounao.cn
逗脑编程配套的在线课程涵盖 Python、C语言、C++、ESP32、树莓派、51单片机、AI智能体、HomeAssistant、电子元器件、数据库、Linux操作系统 等多个方向,从编程语言到硬件开发,从基础入门到项目实战,持续更新中。欢迎访问官网,发现更多好玩的内容。















































































