跳转至

MonitorSystem 摄像头检测系统 — 调研报告

项目来源:用户通过 SCP 上传的 MonitorSystem.zip 调研日期:2026-05-14 调研环境:Ubuntu 24.04 (LXD 容器)


一、项目概述

1.1 基本信息

项目 内容
项目名称 摄像头检测系统 (MonitorSystem)
版本 v1.0.0
技术栈 Python 3.7+ / Tkinter / OpenCV / PyTorch / EfficientNet-B3
运行平台 Windows 10/11(设计目标),Linux 可适配
打包方式 PyInstaller
项目规模 ~1,500 行 Python 代码 + 220MB 模型权重

1.2 功能定位

工业场景下的实时视觉检测系统,包含两个独立模块:

  1. 膨胀检测模块(swellcamera)— 判断物料是否发生膨胀(二分类)
  2. 含水量检测模块(watercamera)— 判断物料含水量区间(三分类:30-35% / 35-40% / 40-45%)

二、项目结构

MonitorSystem/
├── main.py                         # 主程序(Tkinter GUI,848 行)
├── README.md                       # 项目说明文档
├── requirements.txt                # 依赖清单
├── CameraMonitorSystem.spec        # PyInstaller 打包配置
├── add_hidden_imports.py           # PyInstaller 隐藏导入辅助
├── hook-tkinter.py                 # PyInstaller Tkinter 钩子
├── logo.ico                        # 程序图标
├── fonts/
│   └── simhei.ttf                  # 中文字体(黑体)
├── models/                         # AI 模型定义与权重
│   ├── model1.py                   # 含水量分类器 1(35-40 vs 30-35)
│   ├── model2.py                   # 含水量分类器 2(40-45 vs 35-40)
│   ├── model3.py                   # 含水量分类器 3(40-45 vs 30-35)
│   ├── model4.py                   # 膨胀分类器(膨胀 vs 不膨胀)
│   ├── __init__.py
│   ├── best_model1.pth             # 训练权重(43MB)
│   ├── best_model2.pth             # 训练权重(43MB)
│   ├── best_model3.pth             # 训练权重(43MB)
│   ├── best_model4.pth             # 训练权重(43MB)
│   └── efficientnet_b3_pytorch.pth # EfficientNet-B3 backbone(48MB)
├── swellcamera/                    # 膨胀检测模块
│   ├── swellcamera.py              # 膨胀检测主逻辑(208 行)
│   ├── __main__.py                 # 模块入口
│   └── __init__.py
├── watercamera/                    # 含水量检测模块
│   ├── watercamera.py              # 含水量检测主逻辑(221 行)
│   ├── __main__.py                 # 模块入口
│   └── __init__.py
└── utils/
    └── model_loader.py             # 动态模型加载器

三、架构分析

3.1 整体架构

┌─────────────────────────────────────────────────┐
│                  main.py (GUI)                  │
│              Tkinter + threading                │
├─────────────────┬───────────────────────────────┤
│  ModuleManager  │    CameraDetectionApp         │
│  (线程管理)      │    (界面 + 状态同步)           │
├─────────┬───────┴───────────────────────────────┤
│ swellcamera │         watercamera               │
│ (膨胀检测)   │         (含水量检测)               │
├─────────────┴───────────────────────────────────┤
│              models/ (PyTorch)                  │
│         EfficientNet-B3 + 分类头                │
├─────────────────────────────────────────────────┤
│            OpenCV + PIL (图像处理)               │
└─────────────────────────────────────────────────┘

3.2 数据流

膨胀检测流程

摄像头(索引1) → 逐帧采集 → 写入 temp_frame.jpg → PIL 打开 →
EfficientNet-B3 推理 → model4 二分类 → 标签映射 → OpenCV 显示

含水量检测流程

摄像头(索引1) → 每 5 秒采集 1 帧 → 写入临时文件 → PIL 打开 →
model1/model2/model3 各自推理 → 置信度过滤(>0.1) → 加权投票 →
最终含水量区间 → PIL 绘制中文 → OpenCV 显示

3.3 模型架构

所有模型共享同一个 backbone:

  • Backbone: EfficientNet-B3(通过 efficientnet_pytorch 库的 from_name 加载,不加载 ImageNet 预训练)
  • 输入尺寸: 300×300 RGB
  • 分类头: 替换最终全连接层为 Linear(1536→256) → BatchNorm → Linear(256→1) + Sigmoid
模型 用途 分类任务 分类头特点
model1 含水量 35-40% vs 30-35% Identity 占位层
model2 含水量 40-45% vs 35-40% Identity 占位层
model3 含水量 40-45% vs 30-35% Identity 占位层
model4 膨胀 膨胀 vs 不膨胀 Dropout(0.45/0.55) + ReLU

注意: model1-3 使用 Identity 层占位(训练时可能有 Dropout,推理时被替换),model4 保留了 Dropout 和 ReLU。两者分类头结构不一致。


四、问题清单

4.1 严重问题(🔴 必须修复)

P0-1:模块停止机制失效

位置: main.py ModuleManager + swellcamera.py / watercamera.py

问题: stop_swell_module() 仅设置 self.swell_stop_event,但 swellcamera.main() 的检测循环中完全没有检查该事件。用户点击"停止"按钮后,检测线程继续运行,只有在 OpenCV 窗口按 'q' 才能真正退出。

影响: GUI 状态与实际运行状态不同步,用户误以为已停止但摄像头仍在占用。

修复建议: 在检测循环中添加 stop_event.is_set() 检查,或改用共享的 threading.Event 控制循环退出。


P0-2:每帧写入临时文件

位置: swellcamera.py:66 / watercamera.py:73

问题:

cv2.imwrite("temp_frame.jpg", frame)
image = Image.open("temp_frame.jpg")
每一帧都先把 OpenCV 画面写成 JPG 文件,再用 PIL 读回来。

影响: - 性能极差(磁盘 I/O 成为瓶颈) - 膨胀检测每帧都写,约 30fps → 每秒 30 次磁盘写入 - 两个模块同时运行时,写同一个 temp_frame.jpg,产生文件冲突

修复建议: 使用内存转换:

image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))


P0-3:摄像头索引硬编码

位置: swellcamera.py:15 / watercamera.py:16

问题: camera_index = 1(非默认的 0),没有 fallback 逻辑。

影响: 在只有一台摄像头的设备上可能找不到摄像头;在无摄像头设备上直接崩溃。

修复建议: 改为可配置参数,添加 fallback(先试 1,失败试 0),或提供摄像头选择界面。


4.2 中等问题(🟡 建议修复)

P1-1:模型类名错误

位置: models/model1.py ~ model4.py

问题: 所有模型类都叫 AgeClassifier(年龄分类器),明显是从其他项目复制粘贴而来。

影响: 代码可读性差,维护时容易混淆。


P1-2:模型接口不统一

问题: - model1-3 的 predict() 返回 (pred_label, class_probs) 元组 - model4 的 predict() 返回 dict {class, probabilities, confidence}

影响: 调用方式不一致,增加维护成本。


P1-3:字体路径仅支持 Windows

位置: swellcamera.py / watercamera.py

问题: 字体搜索只列了 C:/Windows/Fonts/watercamera.py 硬编码 simhei.ttf

影响: 在 Linux/macOS 上运行时,中文显示会失败。


P1-4:torch.load 安全风险

位置: models/model1.py ~ model4.py

问题:

self.model.load_state_dict(torch.load(path, map_location=device))
未指定 weights_only=True,存在 pickle 反序列化攻击风险。


4.3 轻微问题(🟢 可选优化)

编号 问题 说明
P2-1 except: pass main.py:800,吞掉所有异常,调试困难
P2-2 无日志系统 全用 print(),无法控制级别、无法持久化
P2-3 模型无延迟加载 import 时就加载权重,启动慢
P2-4 硬编码 Windows 路径 测试代码中有 E:\kingtask\...
P2-5 无 requirements.txt 实质内容 大部分依赖被注释,缺少 opencv-pythontorchefficientnet_pytorch 等关键依赖
P2-6 .idea/ 目录未清理 PyCharm 配置文件被打包进了 zip
P2-7 tempCodeRunnerFile.py VS Code/PyCharm 临时文件,不应出现在项目中
P2-8 无训练代码 只有推理代码,无法复现训练过程

五、代码质量评估

维度 评分 说明
功能完整性 ⭐⭐⭐ 两个检测模块基本可用,推理流程完整
代码质量 ⭐⭐ 大量复制粘贴、命名混乱、无注释规范、临时文件滥用
架构设计 ⭐⭐ 模块停止机制失效、接口不统一、无配置化
可维护性 ⭐⭐ 硬编码多、无日志、无文档注释
可部署性 ⭐⭐⭐ 有 PyInstaller 支持,但字体/摄像头硬编码
安全性 ⭐⭐ torch.load 无 weights_only、无输入验证

综合评价: 学生课程项目水平。核心功能(模型推理 + 摄像头采集)流程完整,但工程质量粗糙,存在多个影响实际使用的 bug。


六、下一步修改建议

6.1 优先级排序

优先级 任务 预计工作量 说明
P0 修复模块停止机制 1h 检测循环中添加 stop_event 检查
P0 消除临时文件写入 0.5h 改用内存中的 numpy→PIL 转换
P0 摄像头索引可配置化 0.5h 添加参数 + fallback 逻辑
P1 统一模型 predict() 接口 1h 统一返回 dict 格式
P1 修复字体路径(跨平台) 0.5h 添加 Linux/macOS 字体搜索路径
P1 torch.load 安全修复 0.5h 添加 weights_only=True
P2 清理项目文件 0.5h 删除 .idea/、tempCodeRunnerFile.py、pycache/
P2 补全 requirements.txt 0.5h 列出所有实际依赖及版本
P2 添加日志系统 1h 用 logging 替代 print
P2 修复裸 except 0.5h 改为具体异常类型

总预估工作量: 约 6-7 小时

6.2 建议的修改方案

阶段一:修复核心 Bug(P0)

  1. 停止机制:在 swellcamera.pywatercamera.py 的主循环中添加:

    if stop_event and stop_event.is_set():
        break
    

  2. 消除临时文件:替换 cv2.imwrite + Image.open 为:

    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    image = Image.fromarray(frame_rgb)
    

  3. 摄像头配置化

    def __init__(self, camera_index=0):
        self.camera_index = camera_index
    

阶段二:统一接口(P1)

  1. 统一 predict 返回值:所有模型返回统一的 dict 格式:

    {"class": str, "confidence": float, "probabilities": dict}
    

  2. 跨平台字体

    FONT_SEARCH_PATHS = [
        "C:/Windows/Fonts/",           # Windows
        "/usr/share/fonts/truetype/",   # Linux
        "/System/Library/Fonts/",       # macOS
        os.path.join(os.path.dirname(__file__), "fonts/"),  # 项目内
    ]
    

阶段三:工程优化(P2)

  1. 清理临时文件和 IDE 配置
  2. 补全 requirements.txt
  3. 添加 logging 日志系统
  4. 修复异常处理

七、测试方案

7.1 在当前环境(无摄像头 LXD 容器)可执行的测试

测试项 可行性 方法
模型权重加载 验证 4 个 .pth 文件能正确加载
模型推理流程 用随机 300×300 图片测试 predict()
模型结构一致性 对比 model1-3 和 model4 的分类头
Tkinter GUI 需要 DISPLAY
摄像头采集 需要摄像头设备
OpenCV 窗口显示 需要 GUI 环境

7.2 建议的测试脚本

# test_models.py — 验证模型加载和推理
import torch
from PIL import Image
import numpy as np

# 测试 model4(膨胀检测)
from models.model4 import AgeClassifier
classifier = AgeClassifier("models/best_model4.pth")
dummy_image = Image.fromarray(np.random.randint(0, 255, (300, 300, 3), dtype=np.uint8))
dummy_image.save("test_input.jpg")
result = classifier.predict("test_input.jpg")
print(f"膨胀检测结果: {result}")

八、附录

8.1 文件清单(排除 pycache 和 .idea)

共 31 个文件:
- Python 源码: 13 个 (.py)
- 模型权重: 5 个 (.pth, 共 220MB)
- 配置/打包: 3 个 (.spec, .txt, .bat)
- 资源文件: 2 个 (.ico, .ttf)
- 文档: 2 个 (.md)
- 其他: 6 个 (.idea/, tempCodeRunnerFile.py)

8.2 依赖清单(从代码推断)

# requirements.txt(实际需要的依赖)
torch>=1.9.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

8.3 已知训练信息

  • 训练日期:2025 年 6-7 月
  • Backbone:EfficientNet-B3(300×300 输入)
  • 训练数据:未包含在项目中
  • 训练代码:未包含在项目中
  • 训练日志:未包含在项目中

报告生成时间:2026-05-14