☰
交通标志识别毕设实战:Django+PyTorch+MySQL全栈部署指南
2026/10/10 11:55:12 网站建设 项目流程

简介:这是一套面向本科毕业设计与课程设计的完整交通标志识别系统实现方案,基于YOLOv5深度学习模型与Django Web框架构建,解决实景图像、摄像头实时流及低质环境(如雨雾、黑夜、模糊、远距)下的多场景交通标志检测与分类问题。资源包共570个文件,涵盖47个核心Python源码文件(含模型推理、Web后端与数据库交互逻辑)、107个PNG与39个JPG图像资源、151个GIF动图(多用于界面交互演示)、62个JS与31个CSS前端脚本(集成Bootstrap、Layui、jQuery-UI等主流UI库),以及MySQL建表SQL、说明文档与训练权重文件,整体压缩包达578.97MB,结构清晰、模块完整。已有66人学习下载。读者可直接部署运行前后端系统,获取带GUI界面的本地化检测工具、适配真实复杂路况的YOLOv5训练流程、MySQL数据库设计与Navicat可视化操作示例,以及包含环境配置、模型调优与异常处理的全流程说明文档。

1. 为什么交通标志识别系统毕业设计总卡在“跑不起来”?——Django+MySQL+PyTorch三件套的真实落地水位线

你手头这份标着【python毕业设计】的“基于深度学习的交通标志识别系统(Django)源码”,不是玩具Demo,而是典型工业级轻量部署闭环:前端网页上传图片 → 后端Django接收请求 → 调用PyTorch训练好的CNN模型推理 → 查MySQL数据库匹配标签语义 → 返回带置信度的结构化结果。它踩中了三个硬核交汇点:CV模型推理的精度与速度平衡、Web框架对异步IO和模型加载的调度能力、关系型数据库对标签元数据的可靠管理。很多同学解压就报错、pip install一堆红、页面上传后500、模型加载卡死——根本不是代码写得烂,而是没看清这个架构里每个组件的真实水位线:PyTorch模型必须用.pt或.pth格式且需适配CPU推理;Django不能直接import模型文件,得封装成独立服务或用django.core.cache预加载;MySQL表结构必须含id, class_name, description, example_image_path四字段才能支撑前端展示。这不是“照着教程走一遍”就能通关的项目,而是检验你是否真正理解模型、框架、数据库三者间数据流与生命周期边界的实战沙盒。适合正在做毕设、想用真实CV项目夯实全栈能力、且已掌握Python基础和Linux命令行的同学。


2. 搭建最小可运行环境:从conda创建隔离环境到Django服务监听成功

2.1 创建专用conda环境并安装核心依赖(避坑关键第一步)

很多同学直接在base环境pip install,结果PyTorch版本与CUDA驱动冲突、Django与mysqlclient编译失败。必须用conda创建干净环境,这是后续所有步骤稳定的地基:

# 创建Python 3.8环境(Django 4.x与PyTorch 1.12+兼容性最佳) conda create -n traffic_sign python=3.8 conda activate traffic_sign # 安装PyTorch CPU版(毕业设计无需GPU,避免NVIDIA驱动问题) # 注意:务必按官网https://pytorch.org/get-started/locally/选择CPU版本命令 pip install torch==1.12.1+cpu torchvision==0.13.1+cpu torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cpu # 安装Django与数据库驱动(mysqlclient需先装系统依赖) # Ubuntu/Debian系统: sudo apt-get install python3-dev default-libmysqlclient-dev build-essential # CentOS/RHEL系统: sudo yum install python3-devel mysql-devel gcc pip install django==4.2.7 mysqlclient==2.1.1 pillow==10.0.1 opencv-python==4.8.0.76

提示:mysqlclient是Django官方推荐的MySQL驱动,比pymysql性能高且事务支持更完整。若pip install mysqlclient报错,90%概率是缺python3-dev或mysql-devel系统包,绝不是pip源问题。

2.2 初始化Django项目并配置MySQL连接(验证数据库通路)

进入项目根目录(即解压后含manage.py的文件夹),执行:

# 进入项目目录(假设解压后文件夹名为traffic_sign_django) cd traffic_sign_django # 生成Django默认数据库迁移(会创建db.sqlite3,先确保基础能跑) python manage.py migrate # 启动开发服务器,访问http://127.0.0.1:8000确认Django首页显示 python manage.py runserver

若看到Django欢迎页,说明Python环境和Django本身OK。接下来替换为MySQL:

# 修改settings.py中的DATABASES配置(路径:traffic_sign_django/settings.py) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'traffic_sign_db', # 数据库名,需提前在MySQL中创建 'USER': 'root', # MySQL用户名 'PASSWORD': 'your_password', # MySQL密码 'HOST': '127.0.0.1', # 本地MySQL地址 'PORT': '3306', # 默认端口 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", 'charset': 'utf8mb4', }, } }
# 在MySQL中创建数据库(登录MySQL后执行) CREATE DATABASE traffic_sign_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 执行迁移,将Django模型同步到MySQL python manage.py makemigrations python manage.py migrate

参数说明:utf8mb4是必须项,否则中文标签名(如“禁止左转”)存入会乱码;STRICT_TRANS_TABLES开启严格模式,避免MySQL静默截断导致数据丢失。

2.3 加载预训练模型并验证推理通路(打通CV核心链路)

项目中模型文件通常位于model/目录下,常见命名如best_model.pth。不要直接在views.py里import torch.load(),这会导致每次HTTP请求都重新加载模型,内存暴涨且响应超时。正确做法是全局加载一次:

# 在traffic_sign_django/views.py顶部添加(注意:不是函数内!) import torch import torch.nn as nn from torchvision import transforms from PIL import Image import numpy as np # 全局加载模型(应用启动时执行一次) model_path = 'model/best_model.pth' device = torch.device('cpu') # 强制CPU,避免GPU未初始化报错 model = torch.load(model_path, map_location=device) model.eval() # 切换为推理模式,关闭dropout等 # 定义图像预处理(必须与训练时一致!) transform = transforms.Compose([ transforms.Resize((64, 64)), # 常见交通标志输入尺寸 transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # 验证模型能否正常推理(在views.py中加测试函数) def test_model_inference(): dummy_img = Image.new('RGB', (64, 64), color='red') input_tensor = transform(dummy_img).unsqueeze(0) # 添加batch维度 with torch.no_grad(): output = model(input_tensor) print("Model output shape:", output.shape) # 应输出类似torch.Size([1, 43]),对应GTSRB数据集43类

在python manage.py shell中执行test_model_inference(),若打印出正确shape且无报错,说明模型加载与推理链路已通。


3. 核心业务逻辑实现:从图片上传到数据库查表返回结果的完整闭环

3.1 设计上传接口与图像处理管道(拒绝原始文件直传)

Django默认上传文件保存在内存,大图易OOM。必须配置MEDIA_ROOT并使用InMemoryUploadedFile安全处理:

# settings.py中添加 import os MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 创建media文件夹存放上传图 # urls.py中添加媒体文件路由(主urls.py) from django.conf import settings from django.conf.urls.static import static urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# views.py中实现上传处理视图 from django.shortcuts import render from django.http import JsonResponse from django.core.files.storage import default_storage from django.core.files.base import ContentFile import os from PIL import Image import torch import numpy as np def upload_and_predict(request): if request.method == 'POST' and request.FILES.get('image'): # 1. 保存上传文件到media目录 uploaded_file = request.FILES['image'] file_name = default_storage.save(f'uploads/{uploaded_file.name}', uploaded_file) file_path = os.path.join(settings.MEDIA_ROOT, file_name) # 2. 读取并预处理图像 try: img = Image.open(file_path).convert('RGB') # 强制转RGB,避免RGBA报错 img_tensor = transform(img).unsqueeze(0) # 复用前面定义的transform except Exception as e: return JsonResponse({'error': f'图像读取失败: {str(e)}'}, status=400) # 3. 模型推理 with torch.no_grad(): output = model(img_tensor) probabilities = torch.nn.functional.softmax(output, dim=1) confidence, predicted_class = torch.max(probabilities, 1) confidence = confidence.item() predicted_class = predicted_class.item() # 4. 查询MySQL获取标签详情 from .models import TrafficSignClass # 假设已定义模型 try: sign_info = TrafficSignClass.objects.get(class_id=predicted_class) result = { 'class_name': sign_info.class_name, 'description': sign_info.description, 'confidence': round(confidence * 100, 2), 'example_image': sign_info.example_image.url if sign_info.example_image else None } except TrafficSignClass.DoesNotExist: result = {'error': '未找到对应交通标志类别'} return JsonResponse(result) return render(request, 'upload.html') # 返回上传页面

逻辑说明:transform复用前文定义的预处理流程,确保训练与推理输入完全一致;torch.nn.functional.softmax将logits转为概率分布,torch.max取最高置信度类别;数据库查询用class_id字段关联,该字段必须与模型输出索引一一对应。

3.2 定义TrafficSignClass模型并填充GTSRB标准标签(数据层基石)

交通标志识别必须基于标准数据集(如德国交通标志识别基准GTSRB),其43类标签需完整存入MySQL。在models.py中定义:

# models.py from django.db import models class TrafficSignClass(models.Model): class_id = models.IntegerField(unique=True, help_text="模型输出的类别索引,0-42") class_name = models.CharField(max_length=100, help_text="标志中文名称,如'限速30'") description = models.TextField(help_text="标志含义说明") example_image = models.ImageField(upload_to='examples/', blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.class_name class Meta: verbose_name = "交通标志类别" verbose_name_plural = "交通标志类别"

执行python manage.py makemigrations && python manage.py migrate后,需手动填充43条记录。最简方式是编写脚本:

# populate_signs.py(放在项目根目录,运行python populate_signs.py) from traffic_sign_django.models import TrafficSignClass gtsrb_classes = [ (0, "限速20", "表示前方路段最高车速不得超过20公里/小时"), (1, "限速30", "表示前方路段最高车速不得超过30公里/小时"), # ... 此处省略中间41条,实际需补全GTSRB全部43类 (42, "危险", "表示前方有危险情况,请谨慎驾驶") ] for class_id, name, desc in gtsrb_classes: TrafficSignClass.objects.get_or_create( class_id=class_id, defaults={'class_name': name, 'description': desc} ) print("GTSRB 43类标签已导入数据库")

参数说明:class_id必须严格对应模型输出的索引位置(如模型第0个输出节点代表"限速20");get_or_create避免重复插入;example_image字段用于前端展示示例图,需提前将GTSRB各分类示例图放入media/examples/目录。

3.3 构建前端上传页面与结果展示(用户可见的最后一环)

templates/upload.html内容精简实用:

<!DOCTYPE html> <html> <head> <title>交通标志识别系统</title> <style> .result-box { margin-top: 20px; padding: 15px; border: 1px solid #ddd; } .confidence-bar { width: 200px; height: 20px; background-color: #eee; } .confidence-fill { height: 100%; background-color: #4CAF50; } </style> </head> <body> <h1>交通标志识别系统</h1> <form id="uploadForm" enctype="multipart/form-data"> <input type="file" name="image" accept="image/*" required> <button type="submit">上传识别</button> </form> <div id="result" class="result-box" style="display:none;"> <h3>识别结果:</h3> <p><strong>类别:</strong><span id="class_name"></span></p> <p><strong>说明:</strong><span id="description"></span></p> <p><strong>置信度:</strong><span id="confidence"></span>%</p> <div class="confidence-bar"> <div id="confidence_fill" class="confidence-fill" style="width:0%"></div> </div> <img id="example_img" src="" alt="示例图" style="max-width:200px; margin-top:10px;"> </div> <script> document.getElementById('uploadForm').onsubmit = async function(e) { e.preventDefault(); const formData = new FormData(this); const response = await fetch('/predict/', { method: 'POST', body: formData }); const data = await response.json(); if (data.error) { alert('识别失败:' + data.error); return; } document.getElementById('class_name').textContent = data.class_name; document.getElementById('description').textContent = data.description; document.getElementById('confidence').textContent = data.confidence; document.getElementById('confidence_fill').style.width = data.confidence + '%'; if (data.example_image) { document.getElementById('example_img').src = data.example_image; } document.getElementById('result').style.display = 'block'; }; </script> </body> </html>

关键点:enctype="multipart/form-data"是文件上传必需;fetch发送POST请求到/predict/(需在urls.py中配置路由);confidence_fill宽度动态绑定置信度,视觉化反馈更直观。


4. 避坑指南:90%同学栽在这些看似 trivial 的细节上

4.1 现象:Django启动时报错ModuleNotFoundError: No module named 'torch'

原因:虽然conda环境已装PyTorch,但Django进程未在该环境中运行。常见于用IDE(如PyCharm)直接右键runmanage.py,而IDE未正确激活conda环境。
解决:在终端中conda activate traffic_sign后,再执行python manage.py runserver;PyCharm中需在Settings > Project > Python Interpreter里选择conda环境路径(如~/miniconda3/envs/traffic_sign/bin/python)。

4.2 现象:上传图片后页面卡住,浏览器Network显示pending,日志无报错

原因:模型加载耗时过长(尤其未model.eval()时),Django单线程阻塞。Django默认开发服务器是单线程,模型加载在视图函数内会阻塞整个服务。
解决:将模型加载移至views.py顶层(如2.3节所示),确保只加载一次;或升级为gunicorn+nginx生产部署,但毕设阶段用--reload参数缓解:python manage.py runserver --reload。

4.3 现象:MySQL报错1366, "Incorrect string value: '\\xE5\\x8F\\xB7\\xE9\\x99\\x90...' for column 'class_name' at row 1"

原因:MySQL数据库、表、字段未统一设置为utf8mb4,导致中文无法存储。
解决:执行以下SQL(登录MySQL后):

ALTER DATABASE traffic_sign_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; ALTER TABLE traffic_sign_django_trafficsignclass CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

并在settings.py的DATABASES中加入'OPTIONS': {'charset': 'utf8mb4'}。

4.4 现象:模型推理返回predicted_class=0但数据库查不到,或所有图片都识别为同一类

原因:模型输入预处理与训练时不一致。常见错误包括:图像resize尺寸与训练尺寸不符(如训练用64x64,推理用224x224)、未做Normalize、RGB/BGR通道顺序错误(OpenCV默认BGR,PIL默认RGB)。
解决:检查训练代码中的transforms,严格复现;用print(img_tensor.mean(), img_tensor.std())验证归一化后数值是否在[-2.5, 2.5]合理范围;确保Image.open()而非cv2.imread()读图。

4.5 现象:python manage.py migrate报错django.db.utils.OperationalError: (1050, "Table 'xxx' already exists")

原因:之前用SQLite跑过migrate,切换MySQL后未清空migrations/文件夹中的旧记录。Django认为迁移已执行,但MySQL中无对应表。
解决:删除traffic_sign_django/migrations/目录下除__init__.py外所有文件;执行python manage.py makemigrations重新生成;再migrate。切勿手动删MySQL表!


5. 模型精度调优与部署稳定性加固:让毕设答辩多拿10分的关键动作

5.1 用混淆矩阵定位模型弱点(不靠玄学,靠数据)

毕业答辩常被问“你的模型哪里容易错?”。光说“准确率95%”不够,要拿出具体证据。在views.py中添加一个调试接口,返回详细预测分析:

# views.py中新增 from sklearn.metrics import confusion_matrix import matplotlib.pyplot as plt import io import base64 def debug_prediction(request): # 假设你有测试集图片路径列表(毕设可简化为固定几张图) test_images = ['media/test/stop.jpg', 'media/test/speed30.jpg'] true_labels = [14, 1] # 对应GTSRB class_id predictions = [] for img_path in test_images: img = Image.open(img_path).convert('RGB') img_tensor = transform(img).unsqueeze(0) with torch.no_grad(): output = model(img_tensor) _, pred = torch.max(output, 1) predictions.append(pred.item()) # 计算混淆矩阵 cm = confusion_matrix(true_labels, predictions) # 绘制热力图(仅调试用,不建议放生产) plt.figure(figsize=(8,6)) plt.imshow(cm, cmap='Blues') plt.title('Confusion Matrix') plt.colorbar() plt.xlabel('Predicted') plt.ylabel('True') buf = io.BytesIO() plt.savefig(buf, format='png') buf.seek(0) image_base64 = base64.b64encode(buf.read()).decode() return JsonResponse({ 'confusion_matrix': cm.tolist(), 'debug_image': f'data:image/png;base64,{image_base64}' })

价值点:答辩时展示这张图,指着某一行说“模型在‘禁止驶入’和‘禁止停车’间混淆较多,原因是两者形状相似,下一步可增加这两类的对抗样本训练”,立刻体现工程思维。

5.2 Django配置优化:防止生产环境崩溃的5个硬参数

毕设演示时最怕服务崩,这些配置能扛住10人并发:

配置项推荐值作用修改位置
DEBUGFalse关闭调试模式,避免敏感信息泄露settings.py
ALLOWED_HOSTS['127.0.0.1', 'localhost']限制访问域名,防止CSRF攻击settings.py
CONN_MAX_AGE60数据库连接复用60秒,减少握手开销settings.pyDATABASES内
LOGGING配置django.server日志级别为WARNING避免海量INFO日志刷屏settings.py
SECURE_CONTENT_TYPE_NOSNIFFTrue防止MIME类型嗅探攻击settings.py
# settings.py中追加 DEBUG = False ALLOWED_HOSTS = ['127.0.0.1', 'localhost'] CONN_MAX_AGE = 60 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'level': 'WARNING', 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.server': { 'handlers': ['console'], 'level': 'WARNING', 'propagate': False, }, }, } SECURE_CONTENT_TYPE_NOSNIFF = True

5.3 模型轻量化实操:把30MB的.pth压缩到5MB以内(答辩演示更流畅)

毕业设计不需SOTA精度,但要快。用PyTorch自带的torch.quantization做INT8量化:

# quantize_model.py(单独脚本,运行后生成量化模型) import torch from torchvision import models # 加载原模型 model = torch.load('model/best_model.pth', map_location='cpu') model.eval() # 准备量化配置 model_fused = torch.quantization.fuse_modules(model, [['conv1', 'bn1', 'relu']], inplace=True) model_quantized = torch.quantization.quantize_dynamic( model_fused, {torch.nn.Linear, torch.nn.Conv2d}, dtype=torch.qint8 ) # 保存量化模型 torch.save(model_quantized, 'model/best_model_quantized.pth') print(f"原模型大小: {os.path.getsize('model/best_model.pth') / 1024 / 1024:.2f} MB") print(f"量化后大小: {os.path.getsize('model/best_model_quantized.pth') / 1024 / 1024:.2f} MB")

效果:典型ResNet18结构模型,量化后体积减少60%,CPU推理速度提升2-3倍,精度下降<1%(对43类交通标志足够)。替换views.py中模型路径即可生效。

我带过三届毕设,最常看到同学花两周调模型,却因mysqlclient编译失败或utf8mb4没设,在答辩前夜通宵。后来我养成习惯:新项目第一件事,不是写代码,而是用conda list截图发群里,让所有人确认环境一致;第二件事,是跑通test_model_inference()和python manage.py dbshell连MySQL。这两个命令过了,后面全是体力活。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询