使用OpenCV+pyzbar处理大体积预录视频时输出卡顿的解决求助
问题根因
cv2.CAP_PROP_FPS参数仅对摄像头采集场景生效,无法修改本地预录视频的读取帧率,调整该参数不会产生任何效果。- 原代码逐帧执行pyzbar识别,该操作算力开销较高,大视频帧数量多,处理速度跟不上原视频帧率,同时输出视频的帧率参数和实际写入帧的频率不匹配,播放时就会出现卡顿。
- 原有代码存在逻辑缺陷:没有判断视频读取结束的标识,VideoWriter的尺寸、帧率参数设置不合理,也会导致输出视频异常。
解决方案
- 跳帧处理减少无效识别
条形码/二维码在连续帧中不会发生变化,可设置计数器,每N帧仅处理1帧,其余帧直接写入输出文件即可,大幅降低算力开销。如果需要所有输出帧都显示识别框,可将最近一次识别到的条码坐标、内容缓存下来,未到处理间隔的帧直接用缓存的结果绘制即可,不需要重新识别。 - 匹配输出视频帧率
输出视频的帧率需和实际写入的帧频率对应,例如原视频帧率为30fps,每3帧处理写入1帧,输出帧率需设置为10fps,避免播放速度异常。 - 优化识别效率
- 识别前先将帧缩小到合适尺寸,识别到坐标后再映射回原帧尺寸绘制标记,可将识别速度提升3~5倍。
- 给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
相关产品推荐
相关产品推荐

