跳转至

02 · 环境与运行

本篇目标:让任何一个新接手者在 30 分钟内把推理跑起来。 阅读前置:无。 下一篇:03 · 系统架构


2.1 系统要求

要求 备注
操作系统 Windows 10/11(推荐) gxl 开发主环境;Linux 可适配,但需修中文字体路径
Python 3.7 ~ 3.11 主要受 efficientnet_pytorch 兼容性约束
内存 ≥ 2GB 可用 加载 4 个 EfficientNet-B3 权重共 ~172MB,加上 PyTorch 自身约 1GB
磁盘 ≥ 1GB 可用 源码 ~300KB + 模型 ~220MB + PyInstaller 打包产物 ~500MB
显卡 可选 代码自动检测 CUDA(model1.py:21),无 GPU 退回 CPU
摄像头 USB 摄像头一台 代码硬编码 camera_index=1(详见 2.5)

2.2 Python 环境

推荐:conda 隔离环境

conda create -n monitor python=3.10 -y
conda activate monitor

真实依赖清单

仓库自带的 requirements.txt 只显式列了 pyinstaller,其余依赖被注释为"可选"。这与实际不符——源码 import 了下列包,必须装全才能跑通:

# 必需依赖(从 import 推断)
torch>=1.9.0,<2.5.0
torchvision>=0.10.0
efficientnet_pytorch>=0.7.0
opencv-python>=4.5.0
Pillow>=8.0.0
numpy>=1.20.0

# 打包时才需要
pyinstaller>=5.0.0

一键安装:

pip install torch torchvision efficientnet_pytorch opencv-python Pillow numpy

CUDA 版本提示:若需 GPU 推理,请按 pytorch.org 官方指令选择匹配的 CUDA 版本。代码不会强制要求 CUDA。


2.3 模型权重定位

文件 路径 大小 用途 加载位置
best_model1.pth models/best_model1.pth 43 MB 含水量分类:35-40% vs 30-35% model1.py:39
best_model2.pth models/best_model2.pth 43 MB 含水量分类:40-45% vs 35-40% model2.py:38
best_model3.pth models/best_model3.pth 43 MB 含水量分类:40-45% vs 30-35% model3.py:39
best_model4.pth models/best_model4.pth 43 MB 膨胀二分类:膨胀 vs 不膨胀 model4.py:49
efficientnet_b3_pytorch.pth models/efficientnet_b3_pytorch.pth 48 MB EfficientNet-B3 backbone 参考权重 未在推理中加载,仅供参考(代码用 from_name 不下载预训练)

5 个 .pth 文件总计 ~220MB,已随仓库一并提交(用 git 时注意 LFS 或仓库大小限制)。


2.4 跑通推理的三种方法

方法一:直接启动主程序(推荐,老师演示场景)

python main.py

启动后会出现 600×500 的 Tkinter 窗口,包含「启动膨胀检测」「启动含水量检测」「停止所有检测」「退出程序」按钮(main.py:285-392)。点击启动按钮会新开 OpenCV 窗口实时显示摄像头画面与分类结果。

方法二:单独运行检测子模块(开发调试场景)

# 仅跑膨胀检测
python -m swellcamera

# 仅跑含水量检测
python -m watercamera

入口分别在 swellcamera/__main__.pywatercamera/__main__.py,绕过 Tkinter GUI 直接进入 OpenCV 主循环。退出方式:在 OpenCV 窗口里按 q

方法三:跑打包好的 exe(最终用户场景)

pyinstaller --clean CameraMonitorSystem.spec
.\dist\CameraMonitorSystem\CameraMonitorSystem2.1.exe

打包细节见 07 · 打包与部署

方法四:纯模型推理(无摄像头时的最小验证)

python -c "from models.model4 import AgeClassifier; m = AgeClassifier('models/best_model4.pth'); print('model4 loaded OK')"

可一句话验证权重文件与依赖装好了。model1/2/3 是无参构造:

python -c "from models.model1 import AgeClassifier; AgeClassifier(); print('model1 loaded OK')"

注意:model1/2/3 与 model4 的构造接口不一致(详见 06 · 模型与推理)。


2.5 常见故障排查

Q1:无法打开摄像头,请检查索引 1 是否正确

原因swellcamera.py:165watercamera.py:156 硬编码 camera_index = 1(非默认 0)。这是 gxl 为「外接 USB 摄像头」准备的配置。

临时绕过(不改代码):用 USB 摄像头并保证它是系统第二个摄像头设备。

修代码方案:把 camera_index = 1 改成 0,或加 fallback 逻辑(08 · 问题与改进 P0-3)。


Q2:ModuleNotFoundError: No module named 'efficientnet_pytorch'

原因:依赖装不全。

修复

pip install efficientnet_pytorch

Q3:含水量检测窗口里文字是乱码或方框

原因watercamera.py:113 硬编码 simhei.ttf 相对路径,Linux/macOS 上找不到。

临时绕过:确认 Windows 已装黑体字体(系统默认就有),或把工作目录切到含 fonts/simhei.ttf 的位置。

膨胀检测没这个问题——swellcamera.py:55-74 实现了字体路径搜索,会先找 fonts/simhei.ttf 再退回 Windows 系统字体。


Q4:torch.load_pickle.UnpicklingError

原因:PyTorch 2.6+ 默认 weights_only=True,而本项目代码未指定此参数(model1.py:40 等)。

修复:降级到 PyTorch < 2.6,或修代码加 weights_only=False(详见 08 · 问题与改进 P1-4,注意安全风险)。


Q5:点了「停止膨胀检测」按钮,按钮文字变了但 OpenCV 窗口还在动

原因模块停止机制失效。这是项目最大 P0 bug——main.py:117-119 设置 swell_stop_event.set()swell_running = False,但 swellcamera.py:179-196 的主循环根本不检查这个 Event

临时绕过:在 OpenCV 窗口按 q 键退出。

修复方案:见 08 · 问题与改进 P0-1。


Q6:膨胀检测结果和直觉相反

原因swellcamera.py:48-53 有一段 label_mapping 标签对调

self.label_mapping = {
    "膨胀": "不膨胀",
    "不膨胀": "膨胀",
    "expanded": "normal",
    "normal": "expanded"
}

模型实际推理出 "膨胀" 后会被映射成 "不膨胀" 再显示。这很可能是训练时标签错位的事后补救,需向 gxl 确认。详见 05 · 检测模块 第 5.3 节。


Q7:tkinter.TclError: Can't find a usable init.tcl(打包后才出现)

原因:PyInstaller 找不到 Tcl/Tk 库。本项目已为此设计了三层防护:

  1. main.py:32-55 运行时 fix_tkinter_for_pyinstaller() 设置环境变量
  2. hook-tkinter.py PyInstaller 钩子收集库文件
  3. CameraMonitorSystem.spec:50-57 spec 中显式收集 tcl 目录

修复:先确认打包时用了 pyinstaller --clean CameraMonitorSystem.spec(而非 pyinstaller main.py);若仍失败见 07 · 打包与部署 7.7 节。


2.6 一次最简单的端到端冒烟测试

如果你只想 5 分钟内验证「环境没问题」:

# 1. 装依赖
pip install torch torchvision efficientnet_pytorch opencv-python Pillow numpy

# 2. 验证四个模型权重都能加载
python -c "from models.model1 import AgeClassifier as M1; M1()"
python -c "from models.model2 import AgeClassifier as M2; M2()"
python -c "from models.model3 import AgeClassifier as M3; M3()"
python -c "from models.model4 import AgeClassifier as M4; M4('models/best_model4.pth')"

# 3. 用一张随机图过一次推理
python -c "
import numpy as np
from PIL import Image
img = Image.fromarray(np.random.randint(0,255,(300,300,3),dtype=np.uint8))
img.save('test.jpg')
from models.model4 import AgeClassifier
m = AgeClassifier('models/best_model4.pth')
print(m.predict('test.jpg'))
import os; os.remove('test.jpg')
"

# 4. 启动 GUI(看到主窗口即成功,不点检测按钮也行)
python main.py

四步都通过 = 环境就绪。