You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:19:52