1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| import torch import torch.nn as nn import torchvision.transforms as transforms from PIL import Image
class MobileViTMicrosleepDetector(nn.Module): """ MobileViT轻量级微睡眠检测 论文: IEEE Trans. Human-Machine Systems, 2025 参数量: ~2M 输入: 面部图像序列 输出: 微睡眠概率 优势: 非接触式,无需EEG电极 劣势: 无法检测EEG先兆信号 """ def __init__(self, num_classes=2): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.BatchNorm2d(32), nn.SiLU(), nn.Conv2d(32, 32, 3, groups=32, padding=1), nn.Conv2d(32, 64, 1), nn.BatchNorm2d(64), nn.SiLU(), nn.Conv2d(64, 64, 3, groups=64, stride=2, padding=1), nn.Conv2d(64, 96, 1), nn.BatchNorm2d(96), nn.SiLU(), self._make_transformer_block(96, num_heads=3), nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(96, num_classes) ) def _make_transformer_block(self, dim, num_heads): """简化Transformer块""" return nn.Sequential( nn.LayerNorm([dim, 1, 1]) if False else nn.Identity(), nn.Conv2d(dim, dim, 1), nn.SiLU(), nn.Conv2d(dim, dim, 1) ) def forward(self, x): """ Args: x: 面部图像, shape=(B, 3, 224, 224) Returns: logits: shape=(B, 2) [normal, microsleep] """ return self.features(x)
class VisualMicrosleepPipeline: """ 视觉微睡眠检测完整管道 输入: 摄像头视频流 输出: 微睡眠告警 检测条件: 1. 闭眼持续 ≥ 500ms(非正常眨眼) 2. 头部前倾(点头角度 > 15°) 3. 两个条件同时满足 """ def __init__(self): self.model = MobileViTMicrosleepDetector() self.model.eval() self.transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) self.EAR_THRESHOLD = 0.2 self.EAR_CLOSED_MS = 500 self.HEAD_NOD_THRESHOLD = 15 self.eye_closed_start = None def detect(self, frame, ear, head_pitch): """ Args: frame: BGR图像 ear: 眼睛纵横比 (0-1) head_pitch: 头部俯仰角 (度) Returns: dict: 检测结果 """ import time current_ms = time.time() * 1000 eye_closed = ear < self.EAR_THRESHOLD head_nodded = head_pitch > self.HEAD_NOD_THRESHOLD if eye_closed: if self.eye_closed_start is None: self.eye_closed_start = current_ms closed_duration = current_ms - self.eye_closed_start if closed_duration >= self.EAR_CLOSED_MS and head_nodded: return { 'microsleep': True, 'eye_closed_ms': closed_duration, 'head_pitch': head_pitch, 'confidence': min(0.99, closed_duration / 1000 * 0.3 + 0.5) } elif closed_duration >= self.EAR_CLOSED_MS * 2: return { 'microsleep': True, 'eye_closed_ms': closed_duration, 'head_pitch': head_pitch, 'confidence': min(0.95, closed_duration / 2000 * 0.5 + 0.4) } else: self.eye_closed_start = None return {'microsleep': False, 'eye_closed_ms': 0, 'head_pitch': head_pitch}
|