保姆级教程:用Django+OpenCV从零搭建一个疲劳驾驶检测Web应用(附完整源码)
2026/4/6 4:35:12 网站建设 项目流程
从零构建基于Django与OpenCV的智能疲劳驾驶检测系统1. 环境配置与项目初始化在开始构建疲劳驾驶检测系统之前我们需要搭建完整的开发环境。这个项目将整合Python后端、计算机视觉算法和Web前端技术创建一个功能完备的实时监测平台。1.1 Python环境准备首先确保系统中安装了Python 3.8或更高版本。推荐使用虚拟环境来管理项目依赖python -m venv venv source venv/bin/activate # Linux/macOS venv\Scripts\activate # Windows安装核心依赖包pip install django4.2 opencv-python4.7.0 dlib19.24.0 ultralytics8.0.0注意dlib安装可能需要先安装CMake和C编译工具。在Windows上可以直接下载预编译的whl文件安装。1.2 Django项目初始化创建Django项目和应用django-admin startproject fatigue_detection cd fatigue_detection python manage.py startapp detection配置项目结构如下fatigue_detection/ ├── detection/ │ ├── utils/ # 算法工具包 │ │ ├── __init__.py │ │ ├── dlib_detector.py │ │ └── yolo_detector.py │ ├── templates/ # 前端模板 │ ├── static/ # 静态文件 │ ├── models.py # 数据模型 │ ├── views.py # 视图函数 │ └── urls.py # 应用路由 ├── fatigue_detection/ │ ├── settings.py # 项目配置 │ └── urls.py # 主路由 └── manage.py # 管理脚本2. 核心算法模块实现2.1 基于dlib的面部特征点检测在detection/utils/dlib_detector.py中实现面部特征点检测逻辑import dlib import cv2 import numpy as np from scipy.spatial import distance class DlibDetector: def __init__(self, predictor_path): self.detector dlib.get_frontal_face_detector() self.predictor dlib.shape_predictor(predictor_path) self.EYE_AR_THRESH 0.25 # 眼睛纵横比阈值 self.MOUTH_AR_THRESH 0.75 # 嘴巴纵横比阈值 def eye_aspect_ratio(self, eye): # 计算眼睛纵横比(EAR) A distance.euclidean(eye[1], eye[5]) B distance.euclidean(eye[2], eye[4]) C distance.euclidean(eye[0], eye[3]) return (A B) / (2.0 * C) def mouth_aspect_ratio(self, mouth): # 计算嘴巴纵横比(MAR) A distance.euclidean(mouth[2], mouth[10]) B distance.euclidean(mouth[4], mouth[8]) C distance.euclidean(mouth[0], mouth[6]) return (A B) / (2.0 * C) def detect_fatigue(self, frame): gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces self.detector(gray, 0) results { face_detected: False, eye_aspect_ratio: 0, mouth_aspect_ratio: 0, yawn_detected: False, fatigue_level: 0 } if len(faces) 0: results[face_detected] True shape self.predictor(gray, faces[0]) shape np.array([(p.x, p.y) for p in shape.parts()]) # 提取左右眼和嘴巴特征点 left_eye shape[36:42] right_eye shape[42:48] mouth shape[48:68] # 计算EAR和MAR left_ear self.eye_aspect_ratio(left_eye) right_ear self.eye_aspect_ratio(right_eye) ear (left_ear right_ear) / 2.0 mar self.mouth_aspect_ratio(mouth) results[eye_aspect_ratio] float(ear) results[mouth_aspect_ratio] float(mar) results[yawn_detected] mar self.MOUTH_AR_THRESH # 判断疲劳等级 if ear self.EYE_AR_THRESH * 0.7: results[fatigue_level] 4 # 严重疲劳 elif ear self.EYE_AR_THRESH: results[fatigue_level] 3 if results[yawn_detected] else 2 else: results[fatigue_level] 1 if results[yawn_detected] else 0 return results2.2 基于YOLO的行为检测在detection/utils/yolo_detector.py中实现行为检测逻辑from ultralytics import YOLO import cv2 class YOLODetector: def __init__(self, model_path): self.model YOLO(model_path) self.class_names [face, smoke, phone, water] self.conf_threshold 0.5 def detect(self, frame): results self.model(frame, verboseFalse)[0] detections { face_detected: False, smoking_detected: False, phone_detected: False, drinking_detected: False, detections: [] } for box in results.boxes: class_id int(box.cls[0]) confidence float(box.conf[0]) if confidence self.conf_threshold: continue if class_id 0: detections[face_detected] True elif class_id 1: detections[smoking_detected] True elif class_id 2: detections[phone_detected] True elif class_id 3: detections[drinking_detected] True detections[detections].append({ class_id: class_id, class_name: self.class_names[class_id], confidence: confidence, box: box.xyxy[0].tolist() }) return detections3. Django后端实现3.1 数据模型设计在detection/models.py中定义数据模型from django.db import models from django.contrib.auth.models import User class DetectionSession(models.Model): SESSION_TYPES ( (realtime, 实时检测), (video, 视频分析) ) user models.ForeignKey(User, on_deletemodels.CASCADE) session_type models.CharField(max_length10, choicesSESSION_TYPES) start_time models.DateTimeField(auto_now_addTrue) end_time models.DateTimeField(nullTrue, blankTrue) source_file models.CharField(max_length255, nullTrue, blankTrue) status models.CharField(max_length20, defaultin_progress) result_summary models.JSONField(nullTrue, blankTrue) class DetectionResult(models.Model): session models.ForeignKey(DetectionSession, on_deletemodels.CASCADE) timestamp models.DateTimeField(auto_now_addTrue) eye_aspect_ratio models.FloatField(nullTrue, blankTrue) yawn_detected models.BooleanField(defaultFalse) fatigue_level models.IntegerField(default0) face_detected models.BooleanField(defaultFalse) smoking_detected models.BooleanField(defaultFalse) phone_detected models.BooleanField(defaultFalse) drinking_detected models.BooleanField(defaultFalse) frame_image_path models.CharField(max_length255, nullTrue, blankTrue) detection_details models.JSONField(nullTrue, blankTrue) class SystemConfig(models.Model): config_key models.CharField(max_length50, uniqueTrue) config_value models.CharField(max_length255) description models.TextField(nullTrue, blankTrue)3.2 视图函数实现在detection/views.py中实现核心视图逻辑import json import base64 import cv2 import numpy as np from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render from .models import DetectionSession, DetectionResult, SystemConfig from .utils.dlib_detector import DlibDetector from .utils.yolo_detector import YOLODetector # 全局检测器实例 dlib_detector None yolo_detector None def init_detectors(): global dlib_detector, yolo_detector if dlib_detector is None: dlib_detector DlibDetector(weights/shape_predictor_68_face_landmarks.dat) if yolo_detector is None: yolo_detector YOLODetector(weights/best.pt) def realtime_detection(request): if not request.user.is_authenticated: return redirect(login) session DetectionSession.objects.create( userrequest.user, session_typerealtime ) return render(request, detection/realtime.html, { session_id: session.id }) csrf_exempt def process_frame(request): if request.method ! POST: return JsonResponse({error: Invalid request method}, status400) try: data json.loads(request.body) session_id data.get(session_id) image_data data.get(image_data).split(,)[1] # 去除Base64前缀 # 解码图像 nparr np.frombuffer(base64.b64decode(image_data), np.uint8) frame cv2.imdecode(nparr, cv2.IMREAD_COLOR) # 初始化检测器 init_detectors() # 执行检测 fatigue_result dlib_detector.detect_fatigue(frame) behavior_result yolo_detector.detect(frame) # 合并结果 combined_result {**fatigue_result, **behavior_result} # 保存结果到数据库 DetectionResult.objects.create( session_idsession_id, eye_aspect_ratiocombined_result.get(eye_aspect_ratio), yawn_detectedcombined_result.get(yawn_detected), fatigue_levelcombined_result.get(fatigue_level), face_detectedcombined_result.get(face_detected), smoking_detectedcombined_result.get(smoking_detected), phone_detectedcombined_result.get(phone_detected), drinking_detectedcombined_result.get(drinking_detected), detection_detailscombined_result ) # 判断是否需要预警 alert False if combined_result[fatigue_level] 3: alert True if any([combined_result[smoking_detected], combined_result[phone_detected], combined_result[drinking_detected]]): alert True return JsonResponse({ success: True, result: combined_result, alert: alert }) except Exception as e: return JsonResponse({ error: str(e) }, status500)4. 前端界面开发4.1 实时检测页面创建detection/templates/detection/realtime.html{% extends base.html %} {% block content %} div classcontainer mt-4 div classrow div classcol-md-8 div classcard div classcard-header h5实时疲劳驾驶检测/h5 /div div classcard-body div classvideo-container mb-3 video idvideo width640 height480 autoplay muted/video canvas idcanvas width640 height480 styledisplay:none;/canvas /div div classcontrols button idstartBtn classbtn btn-primary开始检测/button button idstopBtn classbtn btn-danger disabled停止检测/button /div /div /div /div div classcol-md-4 div classcard div classcard-header h5检测状态/h5 /div div classcard-body div idstatusPanel p眼睛纵横比(EAR): span idearValue0.00/span/p p嘴巴纵横比(MAR): span idmarValue0.00/span/p p疲劳等级: span idfatigueLevel0/span/p p检测到打哈欠: span idyawnStatus否/span/p p检测到抽烟: span idsmokeStatus否/span/p p检测到打电话: span idphoneStatus否/span/p p检测到喝水: span iddrinkStatus否/span/p /div div idalertPanel classalert alert-danger mt-3 styledisplay:none; strong警告!/strong 检测到疲劳驾驶或危险行为! /div /div /div /div /div /div script const sessionId {{ session_id }}; let video document.getElementById(video); let canvas document.getElementById(canvas); let ctx canvas.getContext(2d); let processing false; let alertAudio new Audio(/static/sounds/alert.mp3); document.getElementById(startBtn).addEventListener(click, startDetection); document.getElementById(stopBtn).addEventListener(click, stopDetection); // 获取摄像头访问权限 navigator.mediaDevices.getUserMedia({ video: true }) .then(stream { video.srcObject stream; }) .catch(err { console.error(摄像头访问错误:, err); alert(无法访问摄像头: err.message); }); function startDetection() { document.getElementById(startBtn).disabled true; document.getElementById(stopBtn).disabled false; processing true; processFrame(); } function stopDetection() { document.getElementById(startBtn).disabled false; document.getElementById(stopBtn).disabled true; processing false; } function processFrame() { if (!processing) return; // 捕获当前帧 ctx.drawImage(video, 0, 0, canvas.width, canvas.height); let imageData canvas.toDataURL(image/jpeg); // 发送到后端处理 fetch(/detection/process_frame/, { method: POST, headers: { Content-Type: application/json, X-CSRFToken: {{ csrf_token }} }, body: JSON.stringify({ session_id: sessionId, image_data: imageData }) }) .then(response response.json()) .then(data { if (data.success) { updateStatusPanel(data.result); if (data.alert) { showAlert(); } else { hideAlert(); } } else { console.error(处理错误:, data.error); } // 继续处理下一帧 setTimeout(processFrame, 100); // 约10FPS }) .catch(err { console.error(请求错误:, err); setTimeout(processFrame, 100); }); } function updateStatusPanel(result) { document.getElementById(earValue).textContent result.eye_aspect_ratio.toFixed(2); document.getElementById(marValue).textContent result.mouth_aspect_ratio.toFixed(2); document.getElementById(fatigueLevel).textContent result.fatigue_level; document.getElementById(yawnStatus).textContent result.yawn_detected ? 是 : 否; document.getElementById(smokeStatus).textContent result.smoking_detected ? 是 : 否; document.getElementById(phoneStatus).textContent result.phone_detected ? 是 : 否; document.getElementById(drinkStatus).textContent result.drinking_detected ? 是 : 否; } function showAlert() { document.getElementById(alertPanel).style.display block; alertAudio.play(); } function hideAlert() { document.getElementById(alertPanel).style.display none; } /script {% endblock %}4.2 仪表盘页面创建detection/templates/detection/dashboard.html{% extends base.html %} {% block content %} div classcontainer mt-4 h2驾驶行为分析仪表盘/h2 div classrow mt-4 div classcol-md-4 div classcard text-white bg-primary mb-3 div classcard-body h5 classcard-title总检测次数/h5 p classcard-text display-4{{ total_sessions }}/p /div /div /div div classcol-md-4 div classcard text-white bg-warning mb-3 div classcard-body h5 classcard-title疲劳驾驶次数/h5 p classcard-text display-4{{ fatigue_count }}/p /div /div /div div classcol-md-4 div classcard text-white bg-danger mb-3 div classcard-body h5 classcard-title危险行为次数/h5 p classcard-text display-4{{ danger_count }}/p /div /div /div /div div classrow mt-4 div classcol-md-6 div classcard div classcard-header h5疲劳等级分布/h5 /div div classcard-body canvas idfatigueChart height250/canvas /div /div /div div classcol-md-6 div classcard div classcard-header h5危险行为统计/h5 /div div classcard-body canvas idbehaviorChart height250/canvas /div /div /div /div div classrow mt-4 div classcol-12 div classcard div classcard-header h5最近检测记录/h5 /div div classcard-body table classtable table-striped thead tr thID/th th类型/th th开始时间/th th持续时间/th th疲劳等级/th th危险行为/th /tr /thead tbody {% for session in recent_sessions %} tr td{{ session.id }}/td td{{ session.get_session_type_display }}/td td{{ session.start_time }}/td td {% if session.end_time %} {{ session.end_time|timeuntil:session.start_time }} {% else %} 进行中 {% endif %} /td td {% if session.result_summary.max_fatigue_level %} {{ session.result_summary.max_fatigue_level }} {% else %} - {% endif %} /td td {% if session.result_summary.danger_behaviors %} {{ session.result_summary.danger_behaviors|join:, }} {% else %} 无 {% endif %} /td /tr {% endfor %} /tbody /table /div /div /div /div /div script srchttps://cdn.jsdelivr.net/npm/chart.js/script script // 疲劳等级图表 const fatigueCtx document.getElementById(fatigueChart).getContext(2d); const fatigueChart new Chart(fatigueCtx, { type: pie, data: { labels: [正常(0), 轻微(1), 中度(2), 严重(3), 危险(4)], datasets: [{ data: {{ fatigue_distribution }}, backgroundColor: [ #28a745, #ffc107, #fd7e14, #dc3545, #6c757d ] }] } }); // 危险行为图表 const behaviorCtx document.getElementById(behaviorChart).getContext(2d); const behaviorChart new Chart(behaviorCtx, { type: bar, data: { labels: [抽烟, 打电话, 喝水], datasets: [{ label: 检测次数, data: {{ behavior_counts }}, backgroundColor: [ #dc3545, #17a2b8, #007bff ] }] }, options: { scales: { y: { beginAtZero: true } } } }); /script {% endblock %}5. 系统部署与优化5.1 生产环境部署对于生产环境建议使用以下配置Web服务器Nginx Gunicorn数据库PostgreSQL或MySQL静态文件使用Nginx直接服务静态文件媒体文件配置Django使用AWS S3或其他云存储示例Nginx配置server { listen 80; server_name yourdomain.com; location /static/ { alias /path/to/your/project/static/; } location /media/ { alias /path/to/your/project/media/; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }使用Gunicorn启动Django应用gunicorn --workers 4 --bind 127.0.0.1:8000 fatigue_detection.wsgi:application5.2 性能优化建议算法优化使用更轻量级的YOLO模型版本如YOLO-Nano实现帧跳过策略如每3帧处理1帧使用多线程处理视频帧前端优化使用WebSocket替代轮询进行实时通信实现客户端帧缓冲以减少网络延迟使用Web Workers进行图像预处理后端优化实现结果缓存使用Celery进行异步任务处理启用Gzip压缩硬件加速启用CUDA加速如有NVIDIA GPU使用OpenCV的DNN模块进行推理优化6. 扩展功能与未来方向6.1 扩展功能建议多驾驶员支持扩展系统以同时检测多个驾驶员状态驾驶习惯分析基于历史数据提供驾驶行为分析报告移动端适配开发响应式界面或专用移动应用API集成提供REST API供第三方系统集成离线模式支持在没有网络连接时进行本地检测6.2 算法改进方向深度学习替代传统算法使用端到端的深度学习模型替代EAR/MAR计算时序建模引入LSTM或Transformer模型分析时间序列特征多模态融合结合语音、方向盘数据等其他传感器信息自适应阈值根据驾驶员个体特征自动调整检测阈值更丰富的行为检测扩展可识别的危险行为类型7. 实际应用中的挑战与解决方案在将疲劳驾驶检测系统投入实际使用时会遇到各种环境和技术挑战。以下是常见问题及应对策略光照条件变化实现自适应直方图均衡化使用红外摄像头减少光照依赖训练模型时加入多种光照条件的数据增强驾驶员多样性收集不同年龄、性别、种族的面部数据实现个性化校准流程使用更鲁棒的特征表示方法实时性要求优化模型结构和参数实现多级检测策略快速初检精细分析使用硬件加速GPU/TPU系统稳定性实现完善的错误处理和恢复机制监控系统资源使用情况定期维护和更新模型隐私保护实现本地化处理不存储原始图像提供数据匿名化选项遵守相关数据保护法规

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

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

立即咨询