基于YOLOv7的多IP摄像头并行车牌识别系统性能下降求助
实时车牌识别系统性能问题排查与解决方案
项目概述
我正在使用YOLOv7与Python开发一套实时车牌识别系统,该系统采用两阶段YOLOv7模型完成车牌识别,两个模型均运行正常。系统需从停车场不同位置的IP摄像头抓取帧图像,检测是否存在车牌以进行后续处理。为此我为每个摄像头分配独立Process进程,期望实现各网关监控的并行独立运行,保障系统实时性。我使用Docker完成系统部署,以实现便捷安装与可移植性。
相关代码
main.py
# Receiving urls camera_urls = ['camera_1_url', 'camera_2_url'] for i, camera_url in enumerate(camera_urls): cameras.append(Process(target=camera_process, args=(i + 1, camera_url))) for camera in cameras: camera.start() for camera in cameras: camera.join()
camera_process.py
def camera_process(cam_id, url): cam = Camera(cam_id, url) plate_detector = PlateDetector(DETECTION_MODEL) plate_reader = PlateReader(OCR_MODEL) while True: if cam.stopped: cam.attempt_to_connect() im = cam.get_frame() if im is None: continue sleep(cam.FPS) detected, plate = plate_detector.detect(im) if detected: successful, prediction = plate_reader.predict(plate) if successful: send_plate(cam_id, url, prediction, plate) # send detected plate to core software to check for access
camera.py
class Camera: def __init__(self, id, src): self.src = src self.id = id self.FPS = setting.FPS self.capture = cv2.VideoCapture(self.src) self.stopped = True self.attempt_to_connect() def update(self): while self.capture.isOpened(): (self.status, self.frame) = self.capture.read() if not self.status: self.capture.release() break time.sleep(self.FPS) self.stopped = True def get_frame(self): return self.frame def attempt_to_connect(self): while not self.capture.isOpened(): time.sleep(5) self.capture = cv2.VideoCapture(self.src) self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 2) self.thread = Thread(target=self.update, args=()) self.thread.daemon = True self.thread.start() self.stopped = False
问题描述
在20核机器上运行单IP摄像头时,系统性能良好且响应迅速,但新增一个摄像头后性能显著下降。尽管CPU使用率达77%,我仍怀疑两者未真正并行运行。我尝试运行两个独立Docker镜像分别处理不同摄像头地址,但结果一致。搜索解决方案时发现一种无需为每个摄像头创建独立进程、通过循环抓取帧的方案,但不确定是否适用。目前我不知如何解决该问题,以实现不同摄像头数量下性能一致。
疑问点:
- 是否遗漏了某些关键点?
- 该问题是否与GIL有关?
- 是否有其他并行范式可采用?
- Python是否不适合该场景,需切换至其他语言(若需切换,推荐哪种?)
问题分析与解决方案
1. GIL是否是问题根源?
否。你使用的是multiprocessing.Process,每个进程拥有独立的Python解释器和GIL,完全绕开了GIL的限制。多进程本身就是Python中处理计算密集型任务的标准并行方案,因此GIL不是性能下降的原因。
2. 可能遗漏的关键点排查
- 模型重复加载:每个摄像头进程都独立加载了
DETECTION_MODEL和OCR_MODEL,YOLOv7模型体积较大,重复加载会占用大量内存和CPU资源,引发内存带宽竞争,直接降低推理速度。 - Camera类的线程安全与帧处理问题:
update方法中的time.sleep(self.FPS)可能导致帧堆积或延迟,cv2.VideoCapture本身有缓冲机制,额外sleep会打乱帧读取节奏。get_frame直接返回共享的self.frame,无线程安全保护,可能读取到未完全更新的帧数据。
- CPU资源分配与模型推理配置:
- 检查YOLOv7推理是否启用多线程,部分YOLO实现默认单线程运行,即使多核机器也无法充分利用资源。
- Docker容器未设置CPU配额时,两个容器可能抢占CPU资源,导致性能下降。可通过
--cpuset-cpus参数为每个容器分配固定核心。
3. 可采用的其他并行范式
- 进程池+任务队列:
不再为每个摄像头创建独立进程,而是用multiprocessing.Pool维护固定数量的推理worker进程;摄像头线程仅负责抓取帧,将帧放入任务队列,worker进程从队列取帧处理检测与OCR。此方案可复用模型实例,避免重复加载,同时控制并发数。 - 异步IO+多进程推理:
用asyncio异步读取IP摄像头流(IO密集型任务),将帧数据交给多进程推理池处理(计算密集型任务),实现IO与计算任务的解耦,提升资源利用率。 - 模型服务化:
将YOLOv7检测与OCR模型部署为独立服务(如FastAPI、TensorRT Serving),摄像头进程仅负责抓取帧并发送HTTP请求到模型服务获取结果。此方案可统一管理模型,多个摄像头共享模型实例,大幅降低资源占用。
4. Python是否适合该场景?是否需要切换语言?
Python完全适合该场景,通过优化并行方案与资源利用即可解决性能问题。若追求极致性能,可做以下优化:
- 用TensorRT或ONNX Runtime对YOLOv7模型进行量化、优化,大幅提升推理速度。
- 将核心推理逻辑用C实现(如OpenCV DNN、TensorRT C API),通过Python调用,兼顾开发效率与性能。
- 若必须切换语言,推荐C++,其在计算密集型场景下性能优势明显,但开发成本与复杂度会显著提升。
内容的提问来源于stack exchange,提问作者Norooz
相关产品推荐
相关产品推荐

