
广州交警针对的士、网约车违停霸占公交站的行为发布加强查处力度的消息后不少做智慧交通、视频监控系统的开发者都在讨论这类违停行为靠人工巡检效率太低有没有可能通过AI视频分析自动发现、自动取证、自动推送其实这正是智能交通系统里非常典型的“视频结构化 违法行为识别”场景。本文围绕公交站违停识别的完整技术链路从视频流接入、车辆检测、多目标跟踪、电子围栏判定、车牌识别到告警推送整理一套可以直接落地参考的实战方案。1. 背景与核心概念1.1 从一条交通治理新闻说起公交车站在设计上是公交车专用停靠区域但实际出行场景中的士、网约车为了上下客方便经常直接停在公交站区域内。这样一来公交车无法正常进站乘客只能跨车道上下车既影响通行效率也存在不小的安全隐患。交警部门加强查处力度是治理手段之一但单纯依靠人工巡查存在覆盖时间有限、取证成本高、现场执法难度大等问题。从技术视角来看这是一个典型的“视频AI识别 违法取证 告警闭环”问题。如果能在已有监控摄像头的基础上自动识别出“车辆进入公交站区域并停留超过一定时间”同时抓拍车牌、保存证据图片和视频片段就能为交通管理部门提供高效、可追溯的执法依据。1.2 公交站违停识别要解决什么问题要让系统真正可用需要解决以下几个核心问题第一目标识别。系统必须从视频画面中准确识别出“车”并且区分小汽车、公交车、货车等常见车辆类型避免把行人、电动车等非机动车误判为违停车辆。第二稳定跟踪。违停是一个持续状态不是某一帧里出现了车就算违停。系统需要判断“同一辆车”是否持续停在公交站区域内这就需要对车辆进行跨帧跟踪给每一辆车分配稳定的ID。第三区域判定。公交站区域需要在视频画面中划定通常是一个不规则多边形。系统需要判断车辆是否进入该区域、在区域内停留了多久、什么时候离开。第四证据留存。执法场景不能只发一条告警还需要保存违停发生时的现场图片、视频片段、车牌号码、违停起止时间等信息形成完整的证据链。1.3 涉及的AI与工程概念这个系统涉及的技术点比较集中目标检测负责“找出画面中的车辆”多目标跟踪负责“保持同一辆车的ID稳定”电子围栏负责“划定公交站区域”车牌识别负责“确认是哪辆车”告警推送负责“把结果同步给执法或管理人员”。此外工程上还需要考虑视频流拉取、抽帧频率控制、结果入库、Webhook推送、系统稳定性等问题。下面会按照一条完整的开发链路逐步展开。2. 系统整体设计与技术选型2.1 业务需求拆解在设计系统之前先把业务需求拆分成可实现的模块。以一个公交站监控点位为例核心需求如下实时读取公交站附近摄像头的视频流识别画面中的机动车过滤公交车和无关目标对进入公交站区域的车辆进行持续跟踪当车辆在区域内停留超过设定时长例如30秒时判定为疑似违停识别违停车辆车牌并保存现场图和视频片段生成违停记录通过接口或消息推送通知管理人员同一辆车在冷却时间内不重复告警。需要特别说明的是“停留多久算违停”取决于当地交通管理规则和场景要求本文示例中采用可配置的时长阈值实际项目请按业务规则调整。2.2 技术选型整体技术方案采用Python作为原型开发语言原因在于AI生态成熟、代码表达简洁适合快速验证算法链路。下面是一份参考选型模块技术方案说明视频流接入OpenCV FFmpeg支持RTSP、HTTP等常见视频流车辆检测YOLOv8ultralytics使用COCO预训练模型可扩展自定义训练多目标跟踪ByteTrack / 简化IOU跟踪保持车辆ID稳定计算停留时长车牌识别PaddleOCR / HyperLPR识别中文车牌字符后端服务Python FastAPI提供告警查询接口与推送服务结构化存储MySQL保存违停记录、设备信息证据文件本地磁盘 / MinIO保存现场图片和视频片段告警推送企业微信 / 钉钉 Webhook发送文本、图片和跳转链接版本方面不写死具体版本号因为YOLOv8、PaddleOCR等组件迭代较快建议按实际安装环境为准。重点演示的是整体实现思路代码中使用的API以常见稳定版本为例。2.3 整体处理流程整个系统的处理流程可以概括为以下步骤视频流模块按固定帧率抽帧检测模块对每一帧执行车辆检测输出车辆边界框跟踪模块将当前帧检测框与已有轨迹进行匹配更新车辆ID判定模块根据车辆位置与公交站ROI的关系维护每辆车的停留状态当停留时长超过阈值时触发车牌识别证据模块保存现场图片、裁剪车牌图片和视频片段告警模块写入数据库并推送Webhook执法平台或管理人员查看记录并处置。这套流程既能用于公交站违停也能迁移到消防通道占用、应急车道占用等其他违法停车场景只需要调整ROI区域、检测类别和判定规则。3. 环境准备与项目结构3.1 运行环境与依赖建议使用Python 3.8以上版本有NVIDIA GPU的机器可以显著提高检测速度没有GPU也能用CPU跑只是处理帧率会下降。核心依赖如下pip install opencv-python pip install ultralytics pip install paddleocr paddlepaddle pip install fastapi uvicorn pip install requests pip install pymysql说明PaddleOCR安装时需要匹配PaddlePaddle版本如果只是测试车牌识别可以先使用CPU版本的PaddlePaddle。实际生产环境建议根据服务器硬件选择合适的安装方式。3.2 项目目录结构建议按照功能模块组织代码下面是一个参考结构bus_stop_violation/ ├── main.py # 主程序入口串联整个流程 ├── config.py # 全局配置ROI、阈值、数据库等 ├── modules/ │ ├── stream.py # 视频流接入与抽帧 │ ├── detector.py # 车辆检测 │ ├── tracker.py # 多目标跟踪 │ ├── judge.py # 违停判定逻辑 │ ├── plate.py # 车牌识别 │ ├── evidence.py # 证据保存 │ └── notifier.py # 告警推送 ├── evidences/ # 证据文件存放目录 └── requirements.txt这样的结构方便后续扩展例如增加新的检测模型、替换跟踪算法或接入更多摄像头点位。3.3 准备测试视频流开发调试阶段不一定需要真实摄像头可以先用手机录制一段公交站场景视频或者从公开数据集找一段包含车辆的监控视频转成RTSP流或直接使用本地视频文件。OpenCV的VideoCapture既支持视频文件也支持RTSP地址调试时可以用文件输入保证代码逻辑稳定后再切换到实时流。4. 视频流接入与车辆检测4.1 拉取RTSP视频流视频流接入是整个系统的基础。OpenCV的VideoCapture支持传入RTSP地址但需要注意拉流稳定性。摄像头断流、网络抖动都会导致cap.read()返回False因此代码中必须加入自动重连机制。下面是一个简单的视频流读取模块# 文件路径modules/stream.py import time import cv2 def video_stream_reader(stream_url, frame_interval0.1): 读取视频流并按指定间隔逐帧返回。 :param stream_url: 视频文件路径或RTSP地址 :param frame_interval: 抽帧间隔单位秒 cap cv2.VideoCapture(stream_url) if not cap.isOpened(): raise RuntimeError(无法打开视频流请检查地址是否正确) next_time time.time() while True: ret, frame cap.read() if not ret: print(读取视频帧失败尝试重连...) cap.release() time.sleep(2) cap cv2.VideoCapture(stream_url) continue now time.time() if now next_time: next_time now frame_interval yield frame if cv2.waitKey(1) 0xFF ord(q): break cap.release()这里有两个关键点。第一frame_interval用于控制抽帧频率假设检测模型单帧推理需要0.1秒那么抽帧间隔建议也设置在0.1秒以上避免推理速度跟不上视频帧率。第二断流重连非常重要摄像头长时间运行时难免出现网络闪断没有重连机制会导致程序退出。4.2 基于YOLOv8的车辆检测车辆检测使用YOLOv8实现。COCO预训练模型支持80个类别其中与车辆相关的类别主要有car小汽车、bus公交车、truck卡车。在实际场景中公交车本身是公交站的使用者通常需要过滤掉只保留car和truck作为分析对象。# 文件路径modules/detector.py from ultralytics import YOLO # 加载预训练模型可按需替换成自己训练的车检模型 model YOLO(yolov8l.pt) # COCO中car2, truck7, bus5 VEHICLE_CLASSES [2, 7] def detect_vehicles(frame, conf_threshold0.5): 检测画面中的车辆。 返回列表每个元素为(x1, y1, x2, y2, score, cls) results model(frame, classesVEHICLE_CLASSES, confconf_threshold, verboseFalse) boxes [] for r in results: for box in r.boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) score float(box.conf[0]) cls int(box.cls[0]) boxes.append((x1, y1, x2, y2, score, cls)) return boxes说明classes[2, 7]表示只保留COCO数据集中car和truck两个类别这样可以直接过滤行人、骑行者等无关目标。如果你在真实场景中误检较多建议采集现场数据后微调模型或者增加一版专门针对车辆检测的训练数据。4.3 帧率控制与性能考虑实时视频分析最常见的性能瓶颈是单帧推理耗时。YOLOv8l模型在GPU上单帧推理约需要几十毫秒在CPU上可能需要几百毫秒到数秒不等。因此需要通过帧interval来控制送入检测模型的帧率而不是每帧都跑推理。一般建议将检测帧率控制在5到10 FPS之间也就是每0.1到0.2秒处理一帧。这个频率足以判断车辆停留状态也能明显降低GPU和CPU压力。如果单路视频都压力大可以换用YOLOv8s或YOLOv8n轻量模型。5. 多目标跟踪与违停判定5.1 为什么需要多目标跟踪如果只是单帧检测无法知道上一帧出现的那辆车和当前帧这辆车是不是同一辆。比如一辆出租车停在公交站如果跟踪不稳定系统可能会把它当成“一会儿出现、一会儿消失”的多辆车导致停留时间计算错误。多目标跟踪可以给每一辆车分配一个唯一的track_id。只要ID不丢失就能维护每辆车的进入区域时间、当前停留时长和离开时间。成熟的跟踪算法包括ByteTrack、DeepSORT、StrongSORT等。本文先用一个简化版IOU跟踪器说明核心逻辑实际项目建议直接使用ByteTrack获得更好的效果。5.2 简化版IOU跟踪器实现IOU跟踪的核心思路是如果当前帧某个检测框与上一帧某个轨迹的检测框重叠比例较高就认为是同一辆车。下面给出一个可运行的简化版本# 文件路径modules/tracker.py import numpy as np def compute_iou(box1, box2): 计算两个边界框的IOU。 box格式(x1, y1, x2, y2) x1 max(box1[0], box2[0]) y1 max(box1[1], box2[1]) x2 min(box1[2], box2[2]) y2 min(box1[3], box2[3]) inter_w max(0, x2 - x1) inter_h max(0, y2 - y1) inter_area inter_w * inter_h area1 (box1[2] - box1[0]) * (box1[3] - box1[1]) area2 (box2[2] - box2[0]) * (box2[3] - box2[1]) union_area area1 area2 - inter_area if union_area 0: return 0.0 return inter_area / union_area class IOUTracker: def __init__(self, iou_threshold0.3, max_miss_frames10): self.iou_threshold iou_threshold self.max_miss_frames max_miss_frames self.tracks {} self.next_id 1 def update(self, detections): 输入当前帧检测框列表每个元素为(x1, y1, x2, y2, score, cls) 返回匹配后的轨迹列表每个元素为(track_id, x1, y1, x2, y2, cls) matched_tracks [] for det in detections: box det[:4] best_track_id None best_iou 0.0 for track_id, track in self.tracks.items(): if track[miss_count] 0: continue iou compute_iou(box, track[box]) if iou best_iou: best_iou iou best_track_id track_id if best_track_id is not None and best_iou self.iou_threshold: track self.tracks[best_track_id] track[box] box track[miss_count] 0 track[cls] det[5] matched_tracks.append((best_track_id, *box, det[5])) else: track_id self.next_id self.next_id 1 self.tracks[track_id] { box: box, miss_count: 0, cls: det[5] } matched_tracks.append((track_id, *box, det[5])) for track_id, track in self.tracks.items(): if track_id not in [m[0] for m in matched_tracks]: track[miss_count] 1 expired [tid for tid, t in self.tracks.items() if t[miss_count] self.max_miss_frames] for tid in expired: del self.tracks[tid] return matched_tracks这个跟踪器只用了IOU匹配优点是代码简单、容易理解缺点是当车辆被遮挡、快速移动时ID容易丢失。实际项目可以换成ByteTrack逻辑类似但会加入卡尔曼滤波和更精细的匹配策略。5.3 电子围栏ROI设计公交站区域在视频画面里通常不是标准的矩形用多边形ROI更贴近实际。可以先用图像标注工具如LabelMe或OpenCV的cv2.selectROI预先标定公交站四角坐标然后保存到配置文件。# 文件路径config.py # 公交站区域多边形坐标按顺序连接 BUS_STOP_ROI [ (150, 320), (650, 300), (700, 520), (120, 540) ] # 违停判定阈值单位秒 PARKING_THRESHOLD_SECONDS 30 # 告警冷却时间单位秒 ALARM_COOLDOWN_SECONDS 300判断车辆是否在ROI内可以采用两种方式一是判断车辆中心点是否落在多边形内二是计算检测框与ROI的交叠面积比例。前者实现简单后者更稳定。下面使用OpenCV的pointPolygonTest来实现中心点判断。# 文件路径modules/judge.py import cv2 import numpy as np def is_point_in_roi(point, roi_points): 判断点是否在多边形区域内 pts np.array(roi_points, dtypenp.int32) result cv2.pointPolygonTest(pts, (point[0], point[1]), False) return result 0 def is_bbox_in_roi(bbox, roi_points): 判断检测框是否命中区域要求中心点在区域内 x1, y1, x2, y2 bbox[:4] cx (x1 x2) / 2 cy (y1 y2) / 2 return is_point_in_roi((cx, cy), roi_points)5.4 停留时间判定与报警消抖停留时间判定不能只依赖单帧结果。模型偶尔会漏检或误检如果一个车辆只在某几帧被检测到不能直接认为它进入了公交站。更稳妥的方式是维护一个“进入候选状态”连续N帧检测到车辆在ROI内才正式记录进入时间。下面是一个违停判定器的实现# 文件路径modules/judge.py import time class ParkingJudge: def __init__(self, roi_points, threshold_seconds30, confirm_frames5): self.roi_points roi_points self.threshold_seconds threshold_seconds self.confirm_frames confirm_frames # track_id - {enter_time, confirm_count, last_frame_time, notified} self.vehicle_state {} def update(self, tracks, current_timeNone): 输入跟踪后的轨迹列表每个元素为(track_id, x1, y1, x2, y2, cls) 返回需要告警的轨迹信息列表每个元素为(track_id, enter_time, duration) if current_time is None: current_time time.time() alarms [] current_track_ids set() for track in tracks: track_id track[0] bbox track[1:5] cls track[5] # 只判断车辆类公交车单独过滤 if cls not in [2, 7]: continue current_track_ids.add(track_id) in_roi is_bbox_in_roi(bbox, self.roi_points) if track_id not in self.vehicle_state: self.vehicle_state[track_id] { enter_time: None, confirm_count: 0, last_in_roi: False, notified: False } state self.vehicle_state[track_id] if in_roi: if not state[last_in_roi]: state[confirm_count] 1 if state[confirm_count] self.confirm_frames: state[enter_time] current_time else: if state[enter_time] is None: state[confirm_count] 1 if state[confirm_count] self.confirm_frames: state[enter_time] current_time else: duration current_time - state[enter_time] if duration self.threshold_seconds and not state[notified]: alarms.append((track_id, state[enter_time], duration)) state[notified] True else: state[confirm_count] 0 state[enter_time] None state[notified] False state[last_in_roi] in_roi # 清理不存在的轨迹防止内存膨胀 expired_ids [tid for tid in self.vehicle_state if tid not in current_track_ids] for tid in expired_ids: del self.vehicle_state[tid] return alarms这段代码的核心是“连续确认”和“一次性告警”。车辆进入ROI后需要连续多帧确认避免单帧误检导致误报。告警触发后通过notified字段防止同一辆车重复报警。当车辆离开ROI后状态重置这样车辆下一次进入时可以再次触发判定。6. 车牌识别与证据链留存6.1 车牌识别思路当违停行为被判定后下一步是识别车牌号码。实际项目中比较靠谱的做法是两级级联第一步用目标检测模型定位画面中的车牌区域第二步用OCR识别车牌字符。用YOLO训练一个“车牌检测”小模型是非常常见的方案训练数据可以从公开车牌数据集或自采数据中准备。在原型阶段可以先使用PaddleOCR直接对车辆检测框区域进行文字识别但要注意结果里可能混入车身上的其他文字。更稳妥的方式是先按车辆下半部分裁剪出可能的车牌区域再进行OCR识别。# 文件路径modules/plate.py from paddleocr import PaddleOCR ocr PaddleOCR(use_angle_clsTrue, langch) def recognize_plate(vehicle_bbox, frame): 简化版车牌识别。 实际项目中建议先用车牌检测模型定位车牌再做OCR。 x1, y1, x2, y2 vehicle_bbox[:4] # 车牌通常位于车辆下半部分这里按比例截取 plate_area_h int((y2 - y1) * 0.5) crop frame[y2 - plate_area_h:y2, x1:x2] result ocr.ocr(crop, clsTrue) texts [] if result and result[0]: for line in result[0]: texts.append(line[1][0]) return .join(texts)需要提醒的是PaddleOCR识别速度快慢与图片大小、是否使用GPU有关。生产环境建议将车牌检测和OCR识别放到独立服务中避免阻塞主检测流程。6.2 证据图片与视频留存执法场景的证据链必须完整。一条违停记录通常需要保存以下内容车辆在公交站区域内停留的原始现场图片车牌区域的放大裁剪图从车辆进入到离开的关键视频片段摄像机编号、地理位置、时间戳等元数据。现场图片可以直接用OpenCV保存# 文件路径modules/evidence.py import os import cv2 from datetime import datetime def save_evidence(camera_id, frame, plate_crop, plate_text, track_id): 保存违停证据图片 timestamp datetime.now().strftime(%Y%m%d_%H%M%S) dir_path os.path.join(evidences, camera_id) os.makedirs(dir_path, exist_okTrue) scene_path os.path.join(dir_path, f{timestamp}_{plate_text}_{track_id}_scene.jpg) plate_path os.path.join(dir_path, f{timestamp}_{plate_text}_{track_id}_plate.jpg) cv2.imwrite(scene_path, frame) cv2.imwrite(plate_path, plate_crop) return scene_path, plate_path视频片段的截取一般用FFmpeg命令行完成可以记录开始时间点然后从视频文件或录像中截取前后10秒的片段。如果摄像头支持录像回放这一步会和监控平台对接。6.3 违停记录入库设计结构化记录建议使用MySQL保存。下面是一张简化版的违停记录表CREATE TABLE violation_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, camera_id VARCHAR(64) NOT NULL COMMENT 摄像头编号, location_name VARCHAR(128) NOT NULL COMMENT 地点名称, plate_no VARCHAR(16) COMMENT 车牌号码, track_id BIGINT COMMENT 跟踪ID, vehicle_type VARCHAR(16) COMMENT 车辆类型, enter_time DATETIME NOT NULL COMMENT 进入公交站区域时间, duration_seconds INT NOT NULL COMMENT 停留时长秒数, scene_image_path VARCHAR(256) COMMENT 现场图片路径, plate_image_path VARCHAR(256) COMMENT 车牌图片路径, video_path VARCHAR(256) COMMENT 视频片段路径, status TINYINT DEFAULT 0 COMMENT 0待处理 1已处置, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT公交站违停记录表;执行建表语句前请先在测试环境验证确认字段满足实际业务需要后再到生产库执行。涉及删改数据的操作务必提前备份。7. 告警推送与执法平台对接7.1 多渠道告警推送违停记录生成后需要第一时间通知相关人员。当前最常见的告警渠道是企业微信、钉钉机器人Webhook。这类机器人配置简单只需要一个Webhook地址就能发送文本和图片消息。# 文件路径modules/notifier.py import requests def send_webhook(webhook_url, title, content, image_urlNone): 发送Markdown格式消息到企业微信或钉钉机器人 markdown_text content if image_url: markdown_text f\n payload { msgtype: markdown, markdown: { title: title, text: markdown_text } } response requests.post(webhook_url, jsonpayload, timeout5) return response.status_code, response.text调用示例send_webhook( webhook_urlhttps://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxxx, title公交站违停告警, content**违停告警**\n地点广州大道中公交站\n车牌粤A12345\n停留时长45秒\n请及时处理。, image_urlhttps://your-server.com/evidences/001_xxx_scene.jpg )注意Webhook地址属于敏感配置建议放在环境变量或配置中心中不要硬编码到代码仓库里。7.2 与执法平台的标准接口对接除了消息推送违停记录还需要同步到交通管理平台。通常由平台方提供标准的上报接口例如POST /api/traffic/violations Content-Type: application/json Authorization: Bearer token请求体示例{ cameraId: CAM001, locationName: 广州大道中公交站, plateNo: 粤A12345, vehicleType: car, enterTime: 2025-01-01 08:30:00, durationSeconds: 45, sceneImageUrl: https://your-server.com/evidences/CAM001/xxx_scene.jpg, plateImageUrl: https://your-server.com/evidences/CAM001/xxx_plate.jpg, videoUrl: https://your-server.com/evidences/CAM001/xxx.mp4 }对接时要注意接口鉴权、幂等性和失败重试。比如平台接口偶发超时如果直接丢弃记录会导致数据丢失建议在本地先保存记录再通过异步任务同步到平台并记录同步状态。7.3 数据鉴权与安全边界这类系统采集的是公共场所视频数据涉及敏感个人信息使用边界必须清晰。首先系统只能用于合法授权的交通管理业务接入的摄像头点位需要经过管理方同意。其次告警图片和视频内容应当限制访问权限不能任意扩散。最后涉及个人信息的数据需要按照最小必要原则处理比如只提取车牌号用于执法不额外采集驾驶员人脸信息或者对人脸区域进行打码处理。8. 常见问题与排查思路8.1 高频问题速查表问题现象常见原因解决思路画面卡顿检测延迟高单帧推理耗时过长降低抽帧频率换用轻量模型开启GPU推理车辆重复报警跟踪ID频繁丢失又重建调整IOU阈值更换ByteTrack加入冷却时间车牌识别不准光线、角度、模糊增加车牌检测模型做图像增强补光处理电动车、行人被误判检测模型类别过滤不足检查classes过滤配置补充场景数据重训模型车辆停很久不报警中心点判定区域过严改用检测框与ROI交叠比例判定摄像头断流后程序退出缺少重连机制在read失败后自动重连并做健康检查8.2 如何定位漏报与误报排查漏报和误报建议按照“数据链路”顺序逐层检查第一步检查检测层。将检测结果可视化确认车辆是否被正确框出、类别是否正确。如果漏检优先考虑模型问题或conf阈值过高。第二步检查跟踪层。观察车辆在连续帧中的track_id是否稳定。如果ID频繁跳变说明跟踪失效停留时间计算也会出错重点排查IOU阈值和miss帧数。第三步检查判定层。查看车辆进入ROI时的中心点坐标确认是否真的落在区域内。ROI标定不准确是误报漏报的重要原因。第四步检查业务层。确认告警冷却时间、停留阈值等参数是否符合实际需求尤其是“停留多久算违停”这类业务规则需要和管理方确认清楚。9. 最佳实践与工程建议9.1 从试点到推广的节奏这类AI识别系统不建议一上来就大规模上线。比较稳妥的做法是先选一个公交站作为试点跑通“检测—跟踪—判定—取证—推送”完整链路重点记录两类样本误报样本和漏报样本。试点阶段至少要运行一到两周覆盖白天、夜晚、雨天等多个场景。根据真实场景数据调整ROI坐标、停留时长阈值、模型置信度等参数。当误报率和漏报率都达到可接受范围后再逐步扩展到更多点位。9.2 数据合规与隐私保护视频分析系统必须重视数据合规。摄像头点位需要经过合法授权采集到的视频流和证据图片要设置访问控制不能暴露到公网。建议做以下几件事视频流、图片文件存储在内网通过鉴权接口访问告警图片中的行人人脸区域做打码处理违停记录设置保留期限到期自动清理系统操作日志完整记录谁看了什么数据、什么时候看的都要可追溯。9.3 性能优化与模型迭代性能优化方面常见手段包括用NVIDIA TensorRT对检测模型加速、把视频拉流和模型推理放到独立的常驻进程、使用Redis缓存车辆轨迹状态、用消息队列实现告警模块解耦。如果摄像头路数较多可以按点位拆分处理任务独立部署服务实例。模型迭代方面建议持续采集违停场景数据定期评估模型在真实场景中的表现。车牌识别模型和车辆检测模型都要建立评测集每次更新模型前先在评测集上对比准确率避免“更新后反而变差”的情况。10. 总结与后续演进本文从“的士、网约车违停霸占公交站”这一交通治理场景出发详细拆解了一套公交站违停识别系统的完整实现方案。核心链路包括视频流接入、车辆检测、多目标跟踪、电子围栏判定、车牌识别、证据留存和告警推送。代码示例覆盖了从OpenCV拉流到YOLOv8检测、从简化IOU跟踪器到违停判定逻辑的主要环节可以作为原型开发的起点。下一步如果想把这个项目落地到真实环境建议优先做两件事一是采集目标公交站的真实视频数据用于验证和调整参数二是把车辆检测和车牌识别换成针对实际场景优化过的模型并补充业务侧的证据链管理和执法平台对接。实际项目中误报率控制、系统稳定性和数据合规往往比算法精度更影响最终效果需要投入足够的精力去打磨。