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

OpenCV提取视频帧至2.5万张时触发imwrite断言失败报错求解

视频帧提取报错排查

问题表现

待处理视频总帧数约9万帧,帧提取程序运行至成功提取25000帧时抛出运行错误,中断执行。

原实现代码

import cv2
import time
import os

def video_to_frames(input_loc, output_loc):
    """Function to extract frames from input video file
    and save them as separate frames in an output directory.
    Args:
        input_loc: Input video file.
        output_loc: Output directory to save the frames.
    Returns:
        None
    """
    try:
        os.mkdir(output_loc)
    except OSError:
        pass
    # Log the time
    time_start = time.time()
    # Start capturing the feed
    cap = cv2.VideoCapture(input_loc)
    # Find the number of frames
    video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - 1
    print ("Number of frames: ", video_length)
    count = 0
    print ("Converting video..n")
    # Start converting the video
    while cap.isOpened():
        # Extract the frame
        ret, frame = cap.read()
        # Write the results back to output location.
        cv2.imwrite(output_loc + "/%#05d.jpg" % (count+1), frame)
        count = count + 1
        # If there are no more frames left
        if (count > (video_length-1)):
            # Log the time again
            time_end = time.time()
            # Release the feed
            cap.release()
            # Print stats
            print ("Done extracting frames.n%d frames extracted" % count)
            print ("It took %d seconds forconversion." % (time_end-time_start))
            break

if __name__=="__main__":

    input_loc = 'E:/Fish  Project DataSet/06-30/D01_20210630002157.mp4'
    output_loc = 'E:/Fish  Project DataSet/06-30 pictures/D01_20210630002157  frames/'
    video_to_frames(input_loc, output_loc)

报错信息

error: OpenCV(4.5.5) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:801: error: (-215:Assertion failed) !_img.empty() in function 'cv::imwrite'

根因分析

  • 报错直接触发点:cv2.imwrite接口接收到的待写入图像为空矩阵,触发内置断言校验失败。OpenCV的图像写入接口要求传入的参数必须是非空的有效图像矩阵,传入空值时会直接抛出该错误。
  • 代码逻辑漏洞:原代码调用cap.read()读取帧后,未校验读取返回状态就直接执行写入操作。cap.read()会返回两个值:第一个是布尔类型的状态标记ret,只有ret=True时代表成功解码得到有效帧;当视频存在损坏帧、解码失败、读取到视频末尾时,ret会返回False,此时第二个返回值frame为空,直接传入写入接口就会触发崩溃。本次程序跑到25000帧时报错,就是该位置存在损坏/无法解码的帧,读取返回空值导致的。
  • 额外逻辑隐患:原代码完全依赖cv2.CAP_PROP_FRAME_COUNT获取的总帧数判断读取终止条件,部分编码格式的视频该属性返回值存在计数偏差,容易导致逻辑判断失效;另外代码中控制台输出的换行符书写错误,将\n写为n,会导致输出文本格式错乱;硬编码拼接路径的写法在不同操作系统下存在兼容性问题。

修复方案

修复逻辑覆盖以下几点:

  • 每次读取帧后优先校验ret状态,读取失败时直接终止循环(如果需要跳过损坏帧继续读取,可加计数后直接进入下一轮循环,不执行写入操作)
  • 修正换行符书写错误,将提示文本中写错的n替换为正确的转义换行符\n
  • 路径拼接改用os.path.join实现,兼容不同操作系统的路径规则
  • 不将预获取的总帧数作为唯一终止判断条件,以帧读取的返回状态作为核心终止依据,避免总帧数计数不准导致的异常
  • 替换原有的os.mkdir异常捕获写法,用os.makedirs加exist_ok=True参数自动处理目录已存在的场景,逻辑更简洁

修复后可直接运行的代码如下:

import cv2
import time
import os

def video_to_frames(input_loc, output_loc):
    """Function to extract frames from input video file
    and save them as separate frames in an output directory.
    Args:
        input_loc: Input video file.
        output_loc: Output directory to save the frames.
    Returns:
        None
    """
    os.makedirs(output_loc, exist_ok=True)
    time_start = time.time()
    cap = cv2.VideoCapture(input_loc)
    video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - 1
    print("Number of frames: ", video_length)
    count = 0
    print("Converting video...\n")
    
    while cap.isOpened():
        ret, frame = cap.read()
        # 读取失败直接终止,避免空帧写入
        if not ret:
            break
        # 路径拼接改用os.path.join,兼容多系统
        save_path = os.path.join(output_loc, f"{count+1:05d}.jpg")
        cv2.imwrite(save_path, frame)
        count += 1
        # 达到预获取总帧数时提前终止
        if count > (video_length -1):
            break

    time_end = time.time()
    cap.release()
    print(f"Done extracting frames.\n{count} frames extracted")
    print(f"It took {int(time_end-time_start)} seconds for conversion.")

if __name__=="__main__":
    input_loc = 'E:/Fish  Project DataSet/06-30/D01_20210630002157.mp4'
    output_loc = 'E:/Fish  Project DataSet/06-30 pictures/D01_20210630002157  frames/'
    video_to_frames(input_loc, output_loc)

如果需要跳过视频中间的损坏帧、不中断整体提取流程,可以把if not ret: break修改为if not ret: count +=1; continue,即可跳过无法解码的帧继续读取后续内容。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:21:21