1. 准备干净的环境

否则会将无关的库部打包进去,导致 exe 文件动辄 1GB 以上甚至报错,建议创建一个干净的环境,只装必要的库。

2. 修改代码中的路径处理

打包后的程序在运行时,会解压到一个临时目录(sys._MEIPASS)。如果在代码里写死了 model = YOLO('weights/best.pt') 或者 icon = QIcon('img/logo.png'),打包后会报错“找不到文件”。

必须在你的Qt主代码(比如 main.py)中添加并使用这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import sys
import os

def get_resource_path(relative_path):
"""
获取资源文件的绝对路径
用于解决打包成exe后路径错乱的问题
"""
if hasattr(sys, '_MEIPASS'):
# PyInstaller 打包后的临时目录
base_path = sys._MEIPASS
else:
# 开发环境下的当前目录
base_path = os.path.abspath(".")

return os.path.join(base_path, relative_path)

# --- 使用示例 ---
# 以前你可能这样写:
# model = YOLO('best.pt')
# self.setWindowIcon(QIcon('icon.png'))

# 现在要改成这样:
# model = YOLO(get_resource_path('best.pt'))
# self.setWindowIcon(QIcon(get_resource_path('icon.png')))

3. 生成并修改 .spec 文件

不要直接用 pyinstaller -F main.py 一行命令,因为 YOLO 项目很复杂,直接命令行很难配置全。我们需要生成配置文件。

(1)在终端运行:

1
pyinstaller --name=TrashApp --onedir --windowed main.py
  • --name: exe的名字。
  • --onedir: 生成一个文件夹(推荐)。虽然 --onefile 可以生成单个exe,但对于包含 PyTorch 的项目,单个 exe 启动极慢(因为每次都要解压几百兆文件),且容易报错。建议先用 onedir 跑通,最后再尝试 onefile。
  • --windowed: 运行时不显示黑框控制台(如果还在调试阶段,建议先去掉这个参数,保留黑框看报错信息)。
  • main.py: 你的入口脚本文件。
  1. 修改生成的 TrashDetect.spec 文件:
    运行上面命令后,目录下会多一个 .spec 文件。用记事本或 VSCode 打开它。

    我们需要做两件事:

    • 把模型权重 (best.pt) 和其他资源(图片、UI文件)加进去。
    • 收集 ultralytics 及其依赖的所有数据。

    修改后的 .spec 参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_all

# ============== 修改开始 ==============
# 1. 收集 ultralytics 的所有隐式依赖
# 这步至关重要,YOLOv11 依赖很多动态加载的库
datas = []
binaries = []
hiddenimports = []

tmp_ret = collect_all('ultralytics')
datas += tmp_ret[0]
binaries += tmp_ret[1]
hiddenimports += tmp_ret[2]

# 2. 添加你的模型文件
# 格式:('本地文件名', '打包后放置的位置')
datas += [
('yolov11n_best.pt', '.')
]
# ============== 修改结束 ==============

block_cipher = None

a = Analysis(
['main.py'],
pathex=[],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='TrashApp',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False, # 如果运行闪退,把这里改成 True 查看报错
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='TrashApp',
)

4. 执行打包

在终端运行修改后的 spec 文件:

1
pyinstaller TrashApp.spec

等待进度条跑完。打包完成后,你会看到一个 dist 文件夹,里面有一个 TrashApp 文件夹。

5. 另外可以打包成单exe的格式

只有spec文件不同,创建spec文件,输入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_all

# ========================================================
# 1. 资源收集 (和之前保持一致)
# ========================================================
datas = []
binaries = []
hiddenimports = []

# 收集 ultralytics
tmp_ret = collect_all('ultralytics')
datas += tmp_ret[0]
binaries += tmp_ret[1]
hiddenimports += tmp_ret[2]

# 收集你的模型
datas += [
('yolov11n_best.pt', '.')
]

block_cipher = None

a = Analysis(
['main.py'],
pathex=[],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

# ========================================================
# 2. EXE 配置 (单文件模式的核心修改)
# 注意:这里 exclude_binaries 变成了 False
# 并且把 a.binaries, a.zipfiles, a.datas 全部放进来了
# ========================================================
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='TrashApp_OneFile', # 输出的 exe 名字
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # 压缩文件,减小体积,但会增加打包时间
upx_exclude=[],
runtime_tmpdir=None,
console=False, # False = 关闭黑框 (正式发布版)
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

最后打包即可

1
pyinstaller TrashApp.spec