PyQt5学习:从界面搭建到与机器学习实战

以前运行 Python 程序时,我们通常需要在控制台中输入数据,再查看输出结果。这样的程序虽然能实现功能,但是操作不够直观,也不方便展示给其他人。

PyQt5 可以帮助我们给 Python 程序添加窗口、按钮、输入框和图片显示区域。这样,用户不需要了解代码,只需要填写数据并点击按钮,就能使用程序。

这次学习主要包括以下内容:

  1. 安装和配置 PyQt5;
  2. 使用 Qt Designer 设计界面;
  3. 理解常用控件和信号槽;
  4. 将机器学习模型接入 PyQt5;
  5. 在 PyQt5 窗口中显示 OpenCV 摄像头画面;
  6. 使用 dlib 实现人脸框和68个人脸关键点检测。

整体流程可以概括为:

Qt Designer设计界面,将.ui文件转换成.py文件,编写业务逻辑,绑定按钮和槽函数,接入机器学习或OpenCV,形成可以操作的桌面应用

一、PyQt5的介绍

PyQt5 是 Python 的图形用户界面开发库。通过它,我们可以创建窗口、按钮、标签、输入框、菜单栏以及消息提示框等控件。

一个最基本的 PyQt5 程序如下:

python 复制代码
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("我的第一个PyQt5窗口")
        self.resize(600, 400)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

其中,QApplication 负责管理整个应用程序,QMainWindow 表示主窗口,show() 用来显示窗口,app.exec_() 则让程序进入事件循环。

所谓事件循环,就是程序一直等待用户操作。例如,用户点击按钮、输入文字或者关闭窗口时,程序会根据不同事件执行相应功能。

二、使用 Qt Designer 设计界面

如果完全使用 Python 代码设置控件的位置,代码会比较长。因此,我们可以使用 Qt Designer 通过拖拽的方式设计界面。

常用控件包括:

QLabel:显示文字或图片;

QPushButton:按钮;

QLineEdit:单行输入框;

QTextEdit:多行文本框;

QComboBox:下拉选择框;

QCheckBox:复选框;

QMessageBox:提示框;

QFileDialog:文件选择框。

Qt Designer 保存的文件后缀是 .ui。例如:

复制代码
untitled.ui
win1.ui
win3.ui

它们还不能直接作为普通 Python 模块使用,一般需要转换成 .py 文件:

复制代码
pyuic5 untitled.ui -o untitled.py
pyuic5 win1.ui -o win1.py
pyuic5 win3.ui -o win3.py

转换后会生成 Ui_MainWindow 类:

复制代码
from untitled import Ui_MainWindow

需要注意,生成的 Python 文件中通常会写着:

复制代码
不要手动修改该文件,否则重新执行pyuic5时修改会丢失

因此,比较合理的结构是:

复制代码
untitled.ui       负责保存界面设计
untitled.py       由pyuic5自动生成
my窗口.py         编写按钮事件和业务逻辑

三、继承界面并启动程序

项目中的主窗口类同时继承了 QMainWindow 和 Ui_MainWindow:

复制代码
class PyQtMainEntry(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

QMainWindow 提供窗口功能,Ui_MainWindow 提供在 Qt Designer 中设计的控件。

self.setupUi(self) 会把输入框、按钮和标签等控件安装到当前窗口中。如果忘记调用它,窗口可能会显示出来,但设计好的控件不会出现。

程序入口如下:

复制代码
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = PyQtMainEntry()
    window.show()
    sys.exit(app.exec_())

这一部分可以理解为:

复制代码
创建应用程序
→ 创建主窗口
→ 显示主窗口
→ 等待用户操作

四、将机器学习模型接入 PyQt5

项目中的机器学习部分使用玉米价格和豆粕价格预测目标价格。实现过程分为模型训练和界面预测两步。

1. 训练决策树模型

首先读取 Excel 数据:

复制代码
import pandas as pd

data = pd.read_excel("均价数据.xlsx")

然后划分特征和预测目标:

复制代码
x = data.iloc[:, 1:-1]
y = data.iloc[:, -1]

这里的 x 是模型的输入特征,例如玉米和豆粕价格;y 是模型需要预测的目标值。

再划分训练集和测试集:

复制代码
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(
    x,
    y,
    test_size=0.2,
    random_state=1
)

创建并训练决策树回归模型:

复制代码
from sklearn.tree import DecisionTreeRegressor

tree = DecisionTreeRegressor()
tree.fit(x_train, y_train)

最后保存模型:

复制代码
import joblib

joblib.dump(tree, "tree_model.pkl")

这样,界面程序不需要每次启动都重新训练模型,只需要加载保存好的文件。

2. 在界面中加载模型

窗口初始化时加载模型:

复制代码
self.model = joblib.load("tree_model.pkl")

当用户点击"预测"按钮时,读取两个输入框中的内容:

复制代码
def predict_price(self):
    try:
        corn_price = int(self.lineEdit.text())
        soybean_price = int(self.lineEdit_2.text())

        predicted_price = self.model.predict(
            np.array([[corn_price, soybean_price]])
        )

        self.lineEdit_3.setText(
            str(predicted_price[0])
        )

    except ValueError:
        QMessageBox.warning(
            self,
            "错误",
            "请输入有效的价格"
        )

这段代码的执行过程为:

读取玉米价格,读取豆粕价格,组成模型需要的二维数组,调用predict进行预测,把结果显示到第三个输入框

这里要注意:

复制代码
np.array([[corn_price, soybean_price]])

使用了两层方括号,因为机器学习模型接收的通常是二维数据:

复制代码
[样本数量, 特征数量]

即使只预测一条数据,也需要保持二维格式。

3. 输入错误提示

如果用户输入"abc"等非数字内容:

复制代码
int(self.lineEdit.text())

就会产生 ValueError。程序通过 try...except 捕获错误,再使用消息框提示用户,而不是让整个程序崩溃。

复制代码
QMessageBox.warning(
    self,
    "错误",
    "请输入有效的价格"
)

这体现了图形化程序与普通脚本的区别:除了实现功能,还需要考虑用户可能进行的错误操作。

五、在窗口中显示图片

项目中还有一个"打开对照表"按钮。点击后,把图片显示到 QLabel 中:

复制代码
def showbiao(self):
    pixmap = QPixmap("Figure_1.png")
    self.label_4.setPixmap(pixmap)

QPixmap 是 PyQt5 中常用的图片对象,setPixmap() 可以把图片放入标签控件。

为了防止图片尺寸和标签不匹配,也可以进行缩放:

复制代码
pixmap = pixmap.scaled(
    self.label_4.size(),
    Qt.KeepAspectRatio,
    Qt.SmoothTransformation
)
self.label_4.setPixmap(pixmap)

其中,KeepAspectRatio 表示保持原图宽高比例,避免图片变形。

六、PyQt5 与 OpenCV 结合

机器学习模块处理的是数值,而 OpenCV 模块处理的是图像和视频。项目中使用 OpenCV 打开摄像头:

复制代码
self.camera1 = cv2.VideoCapture(0)

参数 0 表示默认摄像头。如果电脑连接了多个摄像头,也可能使用 1 或 2。

但是,不能在主线程中直接使用死循环持续读取摄像头,否则 PyQt5 窗口可能会卡死。项目中使用 QTimer 定时读取画面:

复制代码
self._timer = QtCore.QTimer(self)
self._timer.timeout.connect(self._queryFrame)
self._timer.setInterval(30)

这表示定时器每隔30毫秒触发一次 _queryFrame(),大约每秒刷新33次。

打开和关闭摄像头的槽函数如下:

复制代码
def slot1(self):
    self.is_camera_opened = not self.is_camera_opened

    if self.is_camera_opened:
        self.pushButton.setText("关闭")
        self._timer.start()
    else:
        self.pushButton.setText("打开")
        self._timer.stop()

每次点击按钮,摄像头状态都会取反。按钮文字也会同步改变,让用户知道下一次点击会执行什么操作。

七、把 OpenCV 图像转换成 PyQt5 图像

OpenCV 读取的画面是 NumPy 数组,并且颜色顺序是 BGR;PyQt5 显示图片时通常使用 RGB。

因此需要先转换颜色:

复制代码
rgb_img = cv2.cvtColor(
    frame,
    cv2.COLOR_BGR2RGB
)

然后转换成 QImage:

复制代码
h, w, ch = rgb_img.shape
bytes_per_line = ch * w

q_img = QImage(
    rgb_img.data,
    w,
    h,
    bytes_per_line,
    QImage.Format_RGB888
)

再转换成 QPixmap:

复制代码
pixmap = QPixmap.fromImage(q_img)

最后显示到 QLabel:

复制代码
self.label.setPixmap(pixmap)

完整过程是:

OpenCV读取BGR图像,转换成RGB,NumPy数组转换成QImage,QImage转换成QPixmap,显示到QLabel

八、加入人脸检测和68个关键点

在摄像头画面正常显示后,项目又加入了 dlib 人脸检测:

复制代码
detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor(
    "shape_predictor_68_face_landmarks.dat"
)

detector 用于检测人脸位置,predictor 用于定位人脸上的68个关键点。

窗口中使用两个布尔变量控制功能:

复制代码
self.draw_face_box = False
self.draw_landmarks = False

点击按钮后切换状态:

复制代码
def toggle_face_box(self):
    self.draw_face_box = not self.draw_face_box

def toggle_landmarks(self):
    self.draw_landmarks = not self.draw_landmarks

这样,用户可以独立控制:

是否显示人脸矩形框;

是否显示68个人脸关键点;

也可以同时打开两项功能。

1. 绘制人脸框

python 复制代码
faces = detector(draw_img, 0)

for face in faces:
    x1, y1 = face.left(), face.top()
    x2, y2 = face.right(), face.bottom()

    cv2.rectangle( draw_img,(x1, y1),(x2, y2),(0, 255, 0),2 )

检测器返回人脸区域,rectangle() 根据左上角和右下角坐标画出绿色矩形框。

2. 绘制68个关键点

python 复制代码
shape = predictor(draw_img, face)

landmarks = np.array([[p.x, p.y] for p in shape.parts()])

然后依次画出关键点:

python 复制代码
for idx, point in enumerate(landmarks):
    pos = (point[0], point[1])

    cv2.circle(
        draw_img,
        pos,
        2,
        (0, 255, 0),
        -1
    )

    cv2.putText(
        draw_img,
        str(idx),
        pos,
        cv2.FONT_HERSHEY_SIMPLEX,
        0.4,
        (255, 255, 255),
        1
    )

68个关键点主要分布在:

复制代码
0~16:脸部轮廓
17~26:眉毛
27~35:鼻子
36~47:眼睛
48~67:嘴巴

这些关键点以后还可以用于眨眼检测、张嘴检测、换脸和表情分析。

九、关闭窗口时释放摄像头

如果直接关闭窗口而不释放摄像头,摄像头可能仍然被占用,导致下次运行程序时无法打开。

因此,需要重写窗口关闭事件:

复制代码
def closeEvent(self, event):
    if self.timer.isActive():
        self.timer.stop()

    if self.cap.isOpened():
        self.cap.release()

    event.accept()

这段代码会:

停止定时器

释放摄像头

正常关闭窗口

资源释放是摄像头程序中非常重要的一步。

十、程序运行时常见的问题

1. 找不到 UI 模块

如果出现:

复制代码
ModuleNotFoundError: No module named 'win3'

需要确认 win3.py 与主程序在同一目录,或者重新执行:

复制代码
pyuic5 win3.ui -o win3.py

2. 找不到模型文件

如果出现:

复制代码
FileNotFoundError: tree_model.pkl

需要确认模型文件与程序工作目录一致,也可以使用绝对路径。

3. 摄像头无法打开

可以先检查:

复制代码
cap = cv2.VideoCapture(0)
print(cap.isOpened())

如果输出 False,可能是摄像头编号不正确,或者摄像头正被其他软件占用。

十一、学习总结

这次实践把 PyQt5、机器学习和 OpenCV 连接到了一起。

1.机器学习部分的流程是:

读取Excel数据,训练决策树回归模型,保存模型,PyQt5加载模型,用户输入数据,点击按钮完成预测,在界面中显示结果

2.OpenCV 部分的流程是:

打开摄像头,QTimer定时读取画面,OpenCV处理图像,转换成QImage和QPixmap,在QLabel中显示,根据按钮状态绘制人脸框和关键点

这次学习最重要的地方,是理解了界面和算法之间的关系:

PyQt5 负责与用户交互,机器学习负责处理数值预测,OpenCV 和 dlib 负责处理图像,信号槽机制负责把按钮操作与具体功能连接起来。

以前的程序只能在控制台运行,而加入 PyQt5 后,算法就变成了用户可以直接操作的小应用。这也是从"代码能够运行"走向"程序能够使用"的重要一步。

相关推荐
欣欣之王来了6 小时前
Vue3项目脚手架:Vite vs Vue CLI怎么选?
前端·学习·架构·项目·vue3教程
kaixin_啊啊6 小时前
【零基础学AI】第 7 章——让 AI 辅助学习和办公
人工智能·学习
信奥卷王6 小时前
[GESP202506 六级] 学习小组(含视频)
学习
宛 禾7 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
无敌贵点大王7 小时前
嵌入式软件面试经(自用)
c语言·stm32·单片机·学习·mongodb·面试·职场和发展
Xudde.8 小时前
PwnLab: init 靶机渗透测试(Vulnhub Writeup)
笔记·学习·安全·web安全
我命由我123458 小时前
Function Calling 模型
人工智能·python·学习·ai·学习方法·ai编程·ai写作
别动我齐刘海8 小时前
实时控制学习2
linux·c++·人工智能·学习·算法
海海不掉头发9 小时前
软件开发方法第七周笔记_CSDN博客
人工智能·笔记·学习·软件工程