我的Python代码无法将视频帧保存为图像。

3

我正在尝试使用Python和CV2抓取视频中特定的帧(例如第0帧,第10帧,第20帧...)并将它们保存为图像。但由于某些原因,我的代码只保存了第一帧。所有其他帧都被创建了,但大小为0(它们是损坏的)。

我该如何解决这个问题?

import cv2
from numpy import integer

number = 10;
filename = "18s.mp4";

def uniform():
    cap = cv2.VideoCapture(filename);
    frame_count= int(cap.get(cv2.CAP_PROP_FRAME_COUNT));
    print(frame_count)

    for x in range(0, number):
            frame_no = 1*(x/number)
            frame_no_int=int(frame_no*frame_count)

            cap.set(2,frame_no);
            ret, frame = cap.read()
            cv2.imwrite(filename+'_frame_'+str(frame_no_int)+'.jpg', frame);

    # When everything done, release the capture
    cap.release()

if __name__ == '__main__':
    uniform()

cap.set(2,frame_no) 应该改为 cap.set(2,frame_no_int) 吗? - CupinaCoffee
2
不,它需要一个范围在[0,1]之间的浮点数。我使用了cap.set(1,frame_no_int)代替,这个可以工作。行为很奇怪。 - Tina J
1个回答

2

显然,你在cap.set()中使用的常量2 CAP_PROP_POS_AVI_RATIO 的效果不佳。看一下你修改后脚本的输出:

import cv2
from numpy import integer

number = 10
filename = 'chaplin.mp4'

def uniform():
    cap = cv2.VideoCapture(filename)
    frame_count= int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    print(frame_count)

    for x in range(0, number):
        frame_pos_ratio = 1.0*x/number
        frame_no_int=int(frame_pos_ratio*frame_count)
        cap.set(cv2.CAP_PROP_POS_FRAMES, frame_no_int)
        print (frame_no_int, cap.get(cv2.CAP_PROP_POS_AVI_RATIO))
        ret, frame = cap.read()
        cv2.imwrite('_frame_'+str(frame_no_int)+'.jpg', frame)

    # Attempt to go the end of film
    cap.set(cv2.CAP_PROP_POS_AVI_RATIO, 1)
    print (cap.get(cv2.CAP_PROP_POS_FRAMES))

    # When everything done, release the capture
    cap.release()

if __name__ == '__main__':
    uniform()

输出:

172
(0, 6.510416666666667e-05)
(17, 6.510416666666667e-05)
(34, 6.510416666666667e-05)
(51, 6.510416666666667e-05)
(68, 6.510416666666667e-05)
(86, 6.510416666666667e-05)
(103, 6.510416666666667e-05)
(120, 6.510416666666667e-05)
(137, 6.510416666666667e-05)
(154, 6.510416666666667e-05)
150.0

正如您所看到的,在循环内部,cap.get(cv2.CAP_PROP_POS_AVI_RATIO) 只返回一个常量 6.51e-05

即使有174帧,cap.set(cv2.CAP_PROP_POS_AVI_RATIO, 1) 也只会跳转到第150帧,这明显是一个错误。

这种行为与这个问题相符。

P.S. 有趣的是,甚至 cv2.CAP_PROP_FRAME_COUNT 也不能正常工作。 显然,我的视频文件只包含了150帧,但它们从22到171编号,这可以通过 ffprobe -show_frames chaplin.mp4 | grep coded_picture_number 来证明。 因此,CAP_PROP_FRAME_COUNT 的输出只是 max(frame_no)+1。


我明白了!我猜的没错。我使用了 cap.set(1,frame_no_int),这个行得通。行为很奇怪。 - Tina J
你知道我们是否可以在Python中获取关键帧(I-frame)列表吗? - Tina J
1
@TinaJ,请查看我在这里的答案中的get_frame_types函数:https://dev59.com/sqDha4cB1Zd3GeqP8ADy#51666059 - 这个解决方案使用了调用ffprobe来识别帧类型。 - Andriy Makukha
谢谢。看起来很有帮助! - Tina J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接