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

使用OpenCV+pyzbar处理大体积预录视频时输出卡顿的解决求助

问题根因

  1. cv2.CAP_PROP_FPS参数仅对摄像头采集场景生效,无法修改本地预录视频的读取帧率,调整该参数不会产生任何效果。
  2. 原代码逐帧执行pyzbar识别,该操作算力开销较高,大视频帧数量多,处理速度跟不上原视频帧率,同时输出视频的帧率参数和实际写入帧的频率不匹配,播放时就会出现卡顿。
  3. 原有代码存在逻辑缺陷:没有判断视频读取结束的标识,VideoWriter的尺寸、帧率参数设置不合理,也会导致输出视频异常。

解决方案

  • 跳帧处理减少无效识别
    条形码/二维码在连续帧中不会发生变化,可设置计数器,每N帧仅处理1帧,其余帧直接写入输出文件即可,大幅降低算力开销。如果需要所有输出帧都显示识别框,可将最近一次识别到的条码坐标、内容缓存下来,未到处理间隔的帧直接用缓存的结果绘制即可,不需要重新识别。
  • 匹配输出视频帧率
    输出视频的帧率需和实际写入的帧频率对应,例如原视频帧率为30fps,每3帧处理写入1帧,输出帧率需设置为10fps,避免播放速度异常。
  • 优化识别效率
    1. 识别前先将帧缩小到合适尺寸,识别到坐标后再映射回原帧尺寸绘制标记,可将识别速度提升3~5倍。
    2. 给pyzbar的decode方法指定需要识别的码类型,无需全类型扫描,进一步提升识别速度。
  • 修复原有代码逻辑漏洞
    增加视频读取结束的判断,确保VideoWriter的尺寸参数和写入帧的尺寸完全匹配,不需要预览时可以关闭窗口渲染,进一步提升处理速度。

优化后可直接运行的代码

import cv2
import numpy as np
from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol

# 配置参数,可根据实际需求调整
PROCESS_INTERVAL = 3  # 每3帧执行一次识别
SCALE_RATIO = 0.5  # 识别时缩小帧的比例,提升识别速度

cap = cv2.VideoCapture('2016_0806_040333_0081.mp4')
# 读取原视频的固有参数
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
ori_fps = cap.get(cv2.CAP_PROP_FPS)
# 自动计算输出帧率,也可手动固定
OUTPUT_FPS = ori_fps

# 初始化视频写入对象,尺寸和原视频严格一致
result = cv2.VideoWriter('processed_video.avi', 
                         cv2.VideoWriter_fourcc(*'MJPG'),
                         OUTPUT_FPS, 
                         (frame_width, frame_height))

frame_count = 0
# 缓存最近一次识别结果,用于非识别帧绘制
last_barcodes = []
while True:
    ret, frame = cap.read()
    # 读到视频末尾直接退出循环
    if not ret:
        break
    
    current_barcodes = last_barcodes
    # 到处理间隔才执行新的识别
    if frame_count % PROCESS_INTERVAL == 0:
        current_barcodes = []
        # 缩小帧用于识别
        small_frame = cv2.resize(frame, None, fx=SCALE_RATIO, fy=SCALE_RATIO)
        # 仅识别指定类型的码,可根据需求增删类型
        for barcode in decode(small_frame, symbols=[ZBarSymbol.QRCODE, ZBarSymbol.CODE128, ZBarSymbol.EAN13]):
            myData = barcode.data.decode('utf-8')
            # 坐标映射回原帧尺寸
            pts = np.array([barcode.polygon], np.int32)
            pts = (pts / SCALE_RATIO).astype(np.int32)
            pts = pts.reshape((-1,1,2))
            text_pos = (int(barcode.rect[0]/SCALE_RATIO), int(barcode.rect[1]/SCALE_RATIO))
            current_barcodes.append({"pts": pts, "text": myData, "text_pos": text_pos})
        # 更新缓存
        last_barcodes = current_barcodes
    
    # 绘制识别结果
    for barcode in current_barcodes:
        cv2.polylines(frame, [barcode["pts"]], True, (255,0,255),5)
        cv2.putText(frame, barcode["text"], barcode["text_pos"], 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.9, (255, 0, 255), 2)
    
    # 写入处理后的帧
    result.write(frame)
    # 不需要预览可以注释掉下面两行,处理速度会大幅提升
    cv2.imshow('Result', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    
    frame_count += 1

# 释放所有资源
cap.release()
result.release()
cv2.destroyAllWindows()
print("The video was successfully saved")

内容的提问来源于stack exchange,提问作者user13973948

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:27:03