如何用OpenCV Cuda Video Reader在Python中读取视频特定帧?
OpenCV CUDA VideoReader 读取特定帧问题解答
环境信息
- 编译环境:OpenCV 4.8.0(搭配CUDA 10.2、cudNN 7.6.5.32、Video_Codec_SDK_12.1.14)
- 运行环境:Python 3.9.13
需求与现有代码
想要用CUDA版VideoReader实现和CPU版VideoCapture一样的特定帧读取功能,CPU版核心代码:
cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
当前可运行的CUDA版代码:
video_reader = cv2.cudacodec.createVideoReader('video.mkv') fps_received, fps = video_reader.get(cv2.CAP_PROP_FPS) total_frames_received, total_frames = video_reader.get(cv2.CAP_PROP_FRAME_COUNT) for second in range(1, int(total_frames // fps) + 1): target_frame = int(second * fps) # TODO: Read only the target_frame and skip the rest
尝试过调用setVideoReaderProps设置PROP_DECODED_FRAME_IDX(属性ID 0),但返回值始终为False,无法实现帧跳转。
问题1:如何用CUDA Video Reader读取视频中的特定帧?
CUDA VideoReader受硬件解码架构限制,随机帧定位支持远不如CPU版灵活,推荐两种可行方案:
方案一:预解码缓存(适合多次读取特定帧)
先遍历视频将所有帧解码后缓存,后续直接通过索引读取:
import cv2 video_reader = cv2.cudacodec.createVideoReader('video.mkv') frame_cache = [] # 预解码所有帧并缓存 while True: has_frame, frame = video_reader.nextFrame() if not has_frame: break # 若需在CPU处理,可调用frame.download()转CPU帧缓存,否则直接存CUDA帧 frame_cache.append(frame) # 读取目标帧 target_frame = 100 if 0 <= target_frame < len(frame_cache): target_cuda_frame = frame_cache[target_frame] # 转换为CPU帧(按需使用) cpu_frame = target_cuda_frame.download()
方案二:关键帧跳转+逐帧解码(适合单次读取,节省内存)
视频中只有关键帧(I帧)支持随机访问,非关键帧依赖前置帧解码。可尝试通过时间戳跳转后逐帧解码到目标帧:
import cv2 video_reader = cv2.cudacodec.createVideoReader('video.mkv') _, fps = video_reader.get(cv2.CAP_PROP_FPS) target_frame = 100 # 计算目标帧对应的时间戳(毫秒) target_msec = (target_frame / fps) * 1000 # 尝试跳转到目标时间点(兼容性取决于视频编码与硬件) video_reader.set(cv2.CAP_PROP_POS_MSEC, target_msec) current_frame_idx = 0 target_cuda_frame = None # 逐帧解码直到目标帧 while True: has_frame, frame = video_reader.nextFrame() if not has_frame: break if current_frame_idx == target_frame: target_cuda_frame = frame break current_frame_idx += 1 if target_cuda_frame is not None: cpu_frame = target_cuda_frame.download() # 后续处理逻辑
注意:若时间戳跳转失败(set返回False),则只能从视频开头逐帧解码到目标帧。
问题2:Cuda版是否有类似CAP_PROP_POS_FRAMES的属性?
没有。CUDA VideoReader没有直接等价于CAP_PROP_POS_FRAMES的属性:
- 你尝试的
PROP_DECODED_FRAME_IDX仅用于指定retrieve()方法要获取的已解码帧队列中的索引,而非跳转到视频中的目标帧位置,因此调用setVideoReaderProps会返回False。 - CUDA VideoReader对大部分
CAP_PROP_*属性仅支持get操作,set操作的兼容性极差,这是硬件解码的架构限制导致的,无法像CPU版那样灵活实现随机帧定位。
内容的提问来源于stack exchange,提问作者Vaio
相关产品推荐
相关产品推荐

