Django + 深度学习车道线检测系统实战:从CNN训练到Web部署

发布时间:2026/10/2 10:05:52
Django + 深度学习车道线检测系统实战:从CNN训练到Web部署 简介面向毕业设计、课程设计或工程实训场景这份资源提供了一套基于深度学习的车道线检测系统采用Python编程语言与Django框架搭建后台并以YOLOv5算法作为核心检测手段实现对图片和视频中车道线的自动识别与提取系统覆盖首页、图片检测、图片管理、视频检测、个人信息、用户管理等模块适合希望从项目入手学习深度学习与Web开发结合的初学者或进阶学习者。压缩包共两千个文件包含xml标注数据、txt说明文档、yaml模型配置、py源码、sh脚本及sql数据库文件等整体约978MB数据集、模型训练脚本和配置文件分层存放便于按模块查阅目前已有八十九人学习下载适合作为毕设项目或大作业参考。资料不仅包含可运行的项目源码、数据库脚本还附带开题报告、任务书、设计文档和查重报告单等材料能够帮助快速梳理课题背景、系统设计与实现思路节省从零搭建环境的时间。1. 车道线检测不是玄学这份 Django 源码包到底能跑出什么跑过车道线检测的人都知道白天光线好的时候传统 Canny 加 Hough 变换还能凑合一旦遇到雨天反光、隧道出入口明暗交替那些手工设计的特征就集体失效了。基于深度学习的车道线检测——不管是分类思路还是分割思路——本质上是让模型在大数据里自己学出什么是车道线。这份以 Django 为壳、以 CNN 模型为核的毕业设计源码包把环境配置、模型训练、Web 展示串成了一整条能直接跑的链路。适合正在做毕设、或者想把深度学习落地成一个小系统的新手也适合被图像处理阈值调崩的老手拿来做对照参考。2. 系统拆解与技术选型Django 加深度学习是怎么串起来的2.1 Django 在这个项目里到底干了什么很多第一次接触毕设源码的同学会有一个误解以为车道线检测系统的主要工作量在模型上Django 不过是个摆设。实际上Django 在这个项目里承担的是业务外壳的角色它管理路由、接收上传图片、调用模型推理、把结果渲染回前端页面。换句话说模型负责看Django 负责说给人听。整个系统的数据流是一条直线前端 HTML 页面上传一张道路图片Django 的视图函数收到文件后调用训练好的 PyTorch 模型模型输出的掩码图或关键点数组在服务端被转成坐标再以 JSON 形式返回前端用 Canvas 把车道线画在原图上。这个流程在代码里看起来简单但真正串起来时BGR 和 RGB 的转换、输入尺寸的归一化、模型加载时机任何一步出错都会让结果变成一张纯黑图。这套选型是合理的。Django 自带模板渲染和静态文件管理不需要额外搭前端工程PyTorch 的模型导出和加载又足够灵活能够直接在视图函数里调用。如果你熟悉 Flask会发现这个项目换成 Flask 也能跑但 Django 的 admin 后台和 ORM 对毕设展示来说加分不少尤其需要管理用户上传记录或训练日志时会省很多事。2.2 资源包目录与依赖清单拿到压缩包解压后第一件事是把目录结构认全。常见做法是模型目录和 Web 目录分开模型权重用相对路径引用这样项目整体搬移时不会因为绝对路径问题翻车。目录 / 文件作用models/存放训练好的权重文件常见格式为.pth或.ptdetect/核心检测模块封装模型加载与推理django_project/Django 工程配置目录包含settings.py、urls.pydetection_app/业务应用目录包含视图函数、模板、静态资源templates/HTML 模板用于上传界面与结果展示static/CSS、JS、图片等静态资源scripts/train.py模型训练脚本requirements.txt依赖清单按我拆工程的习惯先看requirements.txt再动手装环境比直接pip install一锅端要稳得多。这个项目里通常包含torch、torchvision、opencv-python、numpy、Django、pillow。注意torch和torchvision的版本要匹配否则 import 时会直接报错而且报错信息看起来像是安装坏了实际是版本不兼容。# 创建干净的环境避免把系统 Python 搞乱 conda create -n lane_detect python3.8 -y conda activate lane_detect # 安装核心依赖先装 PyTorch再装其他库 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python numpy pillow django这里解释一下为什么用conda而不是直接pip。深度学习项目里 OpenCV 和 PyTorch 对底层库版本很敏感conda 能把libjpeg、libpng这些系统级依赖一起管起来遇到装上了但 import 崩溃的概率会小很多。PyTorch 的安装地址里cu118代表 CUDA 11.8 版本如果你机器上没有 NVIDIA 显卡或者没装 CUDA把--index-url去掉安装 CPU 版本即可训练慢一点但跑 demo 足够。2.3 启动前的环境检查清单环境装完不要急着启动 Django先跑一段脚本确认关键库能正常协作。这也是我踩出来的习惯模型加载报错和数据库配置报错经常混在一起早发现早定位。import torch import cv2 import django print(PyTorch:, torch.__version__) print(CUDA available:, torch.cuda.is_available()) print(OpenCV:, cv2.__version__) print(Django:, django.get_version()) # 检查能否读取一张随机图 import numpy as np fake_img np.random.randint(0, 255, (288, 800, 3), dtypenp.uint8) print(Image shape:, fake_img.shape)这段脚本能跑通说明基础环境没问题。torch.cuda.is_available()返回False不代表项目不能跑只是推理会用 CPU速度慢一些。如果这里返回True但之后模型加载却报 CUDA out of memory多半是权重文件和当前显存不匹配后面会详细说。3. 模型训练与参数设定车道线检测背后的 CNN 与损失函数3.1 车道线模型怎么选分割、关键点还是行分类车道线检测在深度学习领域不是一个统一的任务主流做法有三类语义分割、关键点回归、行分类。这个毕设项目一般选用的是轻量化的分割网络或基于 ResNet 的变体。分割思路是把每个像素分类成车道线或背景输出一张和输入同等尺寸的掩码图可视化效果直观做毕设答辩时也容易讲清楚。选型时有个常见的误区一上来就换重的模型比如 DeepLab 或大型 Transformer 结构。对于车道线这个任务输入通常是 288x800 或 256x512 的长条形图像背景占比远大于目标区域重型网络不仅训练慢而且在小数据集上容易过拟合。我一般会建议优先跑通项目自带的轻量网络再去考虑替换骨干网络。3.2 数据准备标注格式与路径组织数据集的选择直接影响训练效果。常用的开源数据集是 TuSimple 和 CULane但毕设场景里如果只是 demo不一定需要完整数据集。项目包里的scripts/train.py一般会限定数据目录结构比如training/gt_image放原图、training/gt_binary_image放二值标注图。学习率、批大小、迭代次数这些参数在数据集是几千张图片的情况下推荐从较小的数值开始探路。下面是一份常见的训练脚本解读不是照抄官方文档而是按项目实际能跑的方式写的。# scripts/train.py 的核心训练配置部分 import torch from torch.utils.data import DataLoader from torchvision import transforms from models.lane_net import LaneNet # 数据预处理统一缩放 转张量 归一化 transform transforms.Compose([ transforms.Resize((288, 800)), transforms.ToTensor(), transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)), ]) # 初始化模型num_classes2 表示背景车道线 model LaneNet(num_classes2, pretrainedTrue) optimizer torch.optim.Adam(model.parameters(), lr1e-4, weight_decay1e-5) criterion torch.nn.CrossEntropyLoss() # 训练循环里检查点保存 for epoch in range(50): for batch_idx, (inputs, labels) in enumerate(train_loader): outputs model(inputs) loss criterion(outputs, labels.long()) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 10 0: torch.save(model.state_dict(), fcheckpoints/lane_net_epoch_{epoch}.pth)说几个关键参数的含义。Resize((288, 800))是很多车道线模型的默认输入尺寸长宽比接近真实道路画面的感受野比直接缩成正方形更能保留远端车道的形状。pretrainedTrue表示加载 ImageNet 预训练权重对收敛速度帮助很大如果你是在低配机器上从头训练loss 会像心电图一样跳动很难压下去。损失函数用CrossEntropyLoss针对二分类分割任务够用了但要注意背景像素远多于车道线像素如果发现模型全预测成背景下一节会提到解决办法。还有一个细节值得注意训练脚本里labels.long()是把标注图从浮点类型转成整型索引CrossEntropyLoss要求目标值必须是torch.long类型。如果标注图读进来是uint8直接用会报错新手很容易在这里卡半小时。3.3 训练参数怎么调学习率、批大小与类别不平衡训练层面最容易翻车的三个参数是学习率、批大小和类别权重。学习率设成1e-3在预训练模型上问题不大但如果是从零开始训练这个值就偏大了。批大小受限于显存常见值是 8 或 16如果显存不够先把输入尺寸降到224x608而不是强行堆批大小。类别不平衡是车道线分割里最典型的坑。一张道路图片里车道线像素占比可能不到 5%模型天然倾向于把所有像素都预测成背景因为这样 loss 也会很低。解决办法是在损失函数里给前景类更高权重PyTorch 里可以直接给CrossEntropyLoss传一个weight张量。# 给前景类更高的权重抑制类别不平衡 class_weights torch.tensor([1.0, 5.0]) # 索引0是背景索引1是车道线 criterion torch.nn.CrossEntropyLoss(weightclass_weights)class_weights里的两个数代表背景和车道线的加权比例。5.0意味着把车道线像素的误差放大五倍模型为了降低 loss 就不得不认真对待前景区域。调试时如果发现预测结果里车道线断成一截一截可以把权重继续调大如果背景区域出现大量白色噪点说明权重太高往回降。4. Django 整合与推理落地从图片上传到车道线回显4.1 Django 视图函数接收图片、调用模型、返回结果模型训练完成后剩下的工作就是把它塞进 Django 应用里。这个项目里的核心视图函数一般叫detect_lane它接收前端 POST 上来的图片先保存到临时目录再调模型推理。关键是模型加载不能放在视图函数内部否则每次请求都要重新读一遍权重系统就卡死了。# detection_app/views.py 的核心推理视图 import cv2 import numpy as np import torch from django.shortcuts import render from django.http import JsonResponse from .models import LaneDetector # 视图函数接收上传图片返回车道线坐标 def detect_lane(request): if request.method POST: img_file request.FILES.get(image) if not img_file: return JsonResponse({status: error, msg: 未接收到图片}) # 读取上传图片为 OpenCV 格式 img_bytes np.frombuffer(img_file.read(), np.uint8) img_bgr cv2.imdecode(img_bytes, cv2.IMREAD_COLOR) img_rgb cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # 统一缩放至模型输入尺寸 img_resized cv2.resize(img_rgb, (800, 288)) img_tensor torch.from_numpy(img_resized).permute(2, 0, 1).unsqueeze(0).float() # 调用全局模型检测 lane_img, points detector.predict(img_tensor) # 将绘制好车道线的图片编码为 base64 返回前端 _, buffer cv2.imencode(.jpg, lane_img) import base64 img_base64 base64.b64encode(buffer).decode(utf-8) return JsonResponse({status: ok, img_base64: img_base64, points: points}) return render(request, detection_app/upload.html)这里有几个必讲的细节。np.frombuffer加cv2.imdecode是把上传的二进制文件直接还原成图像的标准做法不要用cv2.imread因为上传文件不在本地磁盘路径上。cv2.COLOR_BGR2RGB这行是很多深度学习推理翻车的根源OpenCV 读图是 BGR而 PyTorch 预训练模型接受 RGB顺序错了车道线检测结果会像被加了滤镜一样乱成一团。permute(2, 0, 1)是把 HWC 改成 CHWunsqueeze(0)是增加 batch 维度。4.2 前端模板上传组件与 Canvas 画线回显前端页面在这个项目里不需要很复杂一个图片上传控件加一个结果展示区就够了。Django 的模板语言{% static %}用来引用静态资源注意settings.py里必须配置STATICFILES_DIRS否则图片和 JS 文件全部加载不出来白屏哭都没用。!-- detection_app/templates/detection_app/upload.html -- !DOCTYPE html html head title车道线检测系统/title {% load static %} link relstylesheet href{% static css/style.css %} /head body h2上传道路图片进行车道线检测/h2 form iduploadForm enctypemultipart/form-data methodpost {% csrf_token %} input typefile nameimage acceptimage/* required button typesubmit开始检测/button /form div idresult img idresultImg alt检测结果 stylemax-width: 100%; /div script src{% static js/upload.js %}/script /body /html模板里最容易忽略的是{% csrf_token %}。Django 对 POST 请求有 CSRF 防护不加这个标签表单提交会直接返回 403 错误页面显示Forbidden而且控制台不一定有明显提示。upload.js用 AJAX 把图片异步提交给后端拿到返回的 base64 图片后塞进img标签的src属性这样整个检测过程不刷新页面体验上更像一个小型应用。4.3 摄像头帧接入从本地图片到实时流如果你不满足于单张图片想把项目升级成摄像头实时检测思路并不复杂。前端用getUserMedia获取摄像头画面定时截取当前帧发送给后端后端跑一次推理返回结果。压缩包里的静态 demo 一般只做了单张图片上传但视图函数已经支持接收任意图片所以摄像头接入不需要改后端协议只需要前端把帧传上来。// static/js/camera.js 截取摄像头帧并发送 const video document.getElementById(camera); const canvas document.getElementById(snapshot); const ctx canvas.getContext(2d); // 每 200 毫秒截一帧发送给后端 setInterval(() { ctx.drawImage(video, 0, 0, 800, 288); canvas.toBlob((blob) { const formData new FormData(); formData.append(image, blob, frame.jpg); fetch(/detect/, { method: POST, body: formData, }) .then(res res.json()) .then(data { const img document.getElementById(resultImg); img.src data:image/jpeg;base64, data.img_base64; }); }, image/jpeg, 0.9); }, 200);setInterval的间隔时间需要根据你机器的推理速度调整。如果后端跑一帧要 1 秒前端每 200 毫秒发一帧就会造成请求堆积表现为页面越来越卡。我一般会先测一次推理耗时再把这个间隔设定为推理耗时的两倍留出网络传输余量。5. 避坑记录环境、路径、推理性能的几处翻车5.1 现象模型加载时报 No such file or directory 或路径里出现反斜杠原因训练脚本里的权重路径是models/lane_net.pth在 Windows 下被解析成models\lane_net.pth而代码里用了os.path.join拼接绝对路径的一部分导致路径一半是斜杠一半是反斜杠。解决统一用相对路径且不要手写路径分隔符。在settings.py或模型加载代码里用BASE_DIR拼出完整路径。我一般会在项目根目录创建一个config.py集中管理权重路径# config.py 统一管理路径避免反斜杠地狱 from pathlib import Path BASE_DIR Path(__file__).resolve().parent MODEL_PATH BASE_DIR / models / lane_net.pth用pathlib的好处是跨平台无痛Windows、Linux、macOS 都能正确识别路径分隔符。从那以后我写深度学习项目一律不用手工拼接字符串路径。5.2 现象图片上传后页面一直转圈后端日志显示推理耗时 3 秒以上原因模型在 CPU 上跑且detector.predict里每次都对输入做了重复归一化和 resize。还有一种可能是视图函数里每次请求都重新加载了模型。解决第一确认视图函数外的全局变量是否加载了模型不要在detect_lane函数内部写torch.load。第二对输入图像做预处理的算子尽量用 OpenCV 完成不要转成 PIL 再转回来。第三如果一定要 CPU 推理把模型转换成半精度float16推理速度能提升一半# 在模型加载完成后转为半精度仅推理场景使用 model model.half() model.eval()注意half()之后输入张量也要转成half类型否则报类型不匹配。GPU 推理时不要随便用半精度某些层会精度溢出。5.3 现象检测结果全是黑色但原图上传后能正常显示原因这是最经典的 BGR/RGB 顺序问题。模型输入要求 RGBOpenCV 读出来是 BGR直接把 BGR 数据喂给模型模型提取的特征完全错乱输出自然是一团糟。解决在预处理代码里强制加一行cv2.cvtColor(img, cv2.COLOR_BGR2RGB)。同时如果结果图片在cv2.imencode时用的是 OpenCV 的 BGR 数据前端能正常显示因为 JPEG 编码器会处理颜色空间。这个坑特别隐蔽因为不报错只是结果全黑排查时容易以为是模型没训练好。5.4 现象训练时 loss 一直不降或者过拟合严重原因数据集太小加上没有做数据增强。车道线场景中图片大多是连续视频帧截出来的彼此之间相似度很高模型很快记住了这些样本验证集上表现却很差。解决在训练脚本里加入随机裁剪、亮度扰动、随机翻转。车道线左右翻转后语义不变这是最有效的增强方式。注意翻转时必须同步翻转标注图不能只翻原图否则训练时标注错位模型学出来就是条歪线。# 数据增强随机水平翻转原图和标注同步翻转 if random.random() 0.5: img img[:, ::-1] mask mask[:, ::-1]5.5 现象Django 启动后无法访问页面或者改了模板不生效原因忘记开 DEBUG 模式或者浏览器缓存了旧页面。Django 在DEBUGTrue时才会自动重载模板文件生产部署时DEBUGFalse模板改动不会被主动发现。另外浏览器对同名 JS 文件缓存很严重。解决开发阶段settings.py里DEBUG True并添加localhost到ALLOWED_HOSTS。改动 JS 或 CSS 后强制刷新浏览器或者在静态文件路径后面加版本号参数比如style.css?v20240301。6. 从图片到实时视频模型导出与性能验证如果说前面的内容是在跑通这一章要讲的是怎么跑得更快。车道线检测最终要上车或上嵌入式设备不可能在 Django 后端里扛着一整个 PyTorch 模型做实时推理。常见的做法是把 PyTorch 模型导出为 ONNX再用 ONNX Runtime 或 OpenVINO 推理。# 导出 ONNX 模型利用静态图优化推理速度 import torch import torch.onnx model LaneNet(num_classes2, pretrainedFalse) model.load_state_dict(torch.load(models/lane_net.pth, map_locationcpu)) model.eval() dummy_input torch.randn(1, 3, 288, 800) torch.onnx.export( model, dummy_input, lane_net.onnx, opset_version11, input_names[input], output_names[output], dynamic_axes{input: {0: batch_size}, output: {0: batch_size}} )导出后Django 视图函数里不再用torch.load而是用onnxruntime跑推理。这里dynamic_axes让 batch 维度是动态的这样前端传单张图片时不用再包一层 batch代码更简洁。实测在同样 CPU 条件下ONNX Runtime 的推理速度往往比 PyTorch 的 eager 模式快 20% 到 50%不算夸张但能明显缓解 Web 页面的卡顿感。验证模型输出也很重要。不要只肉眼看图把模型输出的二值掩码图统计一下像素分布算出预测出的车道线像素占整张图的比例如果比例超过 30%大概率是把背景误检成车道线了。更规范的做法是拿 TuSimple 数据集的一小部分算一下准确率和召回率但毕设场景下跑通全流程比刷指标更实际。这个项目的完整链路是PyTorch 训练模型Django 包一层 Web 外壳OpenCV 负责图像处理前端 Canvas 负责可视化。每一层都有各自的地雷而这些都是我在实际拆项目的过程中替大家踩过的。从那以后我每次把一个训练好的模型塞进 Django 之前都会强制走一遍环境清单、路径检查、BGR 转 RGB 确认、模型加载位置确认这四件事把 80% 的翻车提前拦在启动之前。希望帮到你。本文还有配套的精品资源点击获取