Python - 提取和保存视频帧

GSh*_*ked 92 python opencv python-2.7

所以我已经按照本教程,但似乎没有做任何事情.什么都没有.它等待几秒钟然后关闭程序.这段代码有什么问题?

import cv2
vidcap = cv2.VideoCapture('Compton.mp4')
success,image = vidcap.read()
count = 0
success = True
while success:
  success,image = vidcap.read()
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file
  if cv2.waitKey(10) == 27:                     # exit if Escape is hit
      break
  count += 1
Run Code Online (Sandbox Code Playgroud)

另外,在评论中它说这会将帧限制为1000?为什么?

编辑:我尝试先做success = True,但没有帮助.它只创建了一个0字节的图像.

fir*_*ant 163

这里下载此视频,以便我们有相同的视频文件进行测试.确保将该mp4文件放在python代码的同一目录中.然后还要确保从同一目录运行python解释器.

然后修改代码,沟通waitKey浪费时间也没有窗口它无法捕获键盘事件.我们还打印该success值以确保它成功读取帧.

import cv2
vidcap = cv2.VideoCapture('big_buck_bunny_720p_5mb.mp4')
success,image = vidcap.read()
count = 0
while success:
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file      
  success,image = vidcap.read()
  print('Read a new frame: ', success)
  count += 1
Run Code Online (Sandbox Code Playgroud)

怎么样?

  • 这会保存一个空的jpeg文件,并返回`Read a new frame:False` (4认同)
  • 这意味着opencv无法读取视频.很可能它无法访问ffmpeg.你在用什么操作系统? (2认同)
  • Google针对您的特定版本的opencv的说明,并严格遵循如何在Windows上使用ffmpeg和opencv-python. (2认同)
  • 所以我使用[this](http://stackoverflow.com/questions/11699298/opencv-2-4-videocapture-not-working-on-windows)问题来解决我的兼容性问题.我不得不将DLL重命名为opencv_ffmpeg300.dll(因为OpenCV2的Python安装是3.0.0).我将它放入我的Python目录(C:\ Python27).我不需要安装Windows版本的ffmpeg和opencv,但我确实需要OpenCV附带的DLL,但之后我删除了其余的OpenCV.无论如何,我会选择这个作为答案,但任何阅读此内容的人都必须知道这个ESSENTIAL DLL. (2认同)
  • 就像魅力一样:应该是公认的答案! (2认同)

GSh*_*ked 38

所以这里有最终的代码:

import cv2
print(cv2.__version__)
vidcap = cv2.VideoCapture('big_buck_bunny_720p_5mb.mp4')
success,image = vidcap.read()
count = 0
success = True
while success:
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file
  success,image = vidcap.read()
  print 'Read a new frame: ', success
  count += 1
Run Code Online (Sandbox Code Playgroud)

所以要做到这一点,你必须得到一些东西.首先,下载OpenCV2.然后为Python 2.7.x 安装它.转到第三方文件夹内的ffmpeg文件夹(类似的东西C:\OpenCV\3rdparty\ffmpeg,但我不确定).复制opencv_ffmpeg.dll(如果您的python版本是x64,则为x64版本)并将其粘贴到Python文件夹中(可能C:\Python27).opencv_ffmpeg300.dll如果您的opencv版本是3.0.0(您可以在此处找到),请重命名,并根据您的版本进行相应更改.顺便说一句,你必须在你的环境路径中有你的python文件夹.


Bhu*_*bar 24

要扩展这个问题(和@ user2700065的回答)略有不同的情况,如果有人不想提取每一帧但想要每秒提取帧.所以1分钟的视频将提供60帧(图像).

import sys
import argparse

import cv2
print(cv2.__version__)

def extractImages(pathIn, pathOut):
    count = 0
    vidcap = cv2.VideoCapture(pathIn)
    success,image = vidcap.read()
    success = True
    while success:
      vidcap.set(cv2.CAP_PROP_POS_MSEC,(count*1000))    # added this line 
      success,image = vidcap.read()
      print ('Read a new frame: ', success)
      cv2.imwrite( pathOut + "\\frame%d.jpg" % count, image)     # save frame as JPEG file
      count = count + 1

if __name__=="__main__":
    print("aba")
    a = argparse.ArgumentParser()
    a.add_argument("--pathIn", help="path to video")
    a.add_argument("--pathOut", help="path to images")
    args = a.parse_args()
    print(args)
    extractImages(args.pathIn, args.pathOut)
Run Code Online (Sandbox Code Playgroud)


Fir*_*ger 11

到 2022 年,您还可以选择使用ImageIO来执行此操作,恕我直言,这更加轻松且可读。

import imageio.v3 as iio

for idx, frame in enumerate(iio.imiter("imageio:cockatoo.mp4")):
    iio.imwrite(f"extracted_images/frame{idx:03d}.jpg", frame)
Run Code Online (Sandbox Code Playgroud)

旁注1:"imageio:cockatoo.mp4"是ImageIO提供的标准图像,用于测试和演示目的。您只需将其替换为"path/to/your/video.mp4".

旁注 2:您必须安装 ImageIO 的可选依赖项之一才能读取视频数据,这可以通过pip install imageio-ffmpeg或 来完成pip install av


你可以与 OpenCV 进行比较,你会发现,在这方面从 OpenCV 中也没有太多收获:

Read-Only Timings
=================
OpenCV:         0.453
imageio_ffmpeg: 0.765
imageio_pyav:   0.272
Run Code Online (Sandbox Code Playgroud)
Read + Write Timings
====================
OpenCV:         3.237
imageio_ffmpeg: 1.597
imageio_pyav:   1.506
Run Code Online (Sandbox Code Playgroud)

默认情况下,OpenCV 和 ImageIO+av 读取时的速度大致相同。两者都直接绑定到底层的 FFmpeg 库,因此这并不奇怪。然而,ImageIO 允许您调整 FFmpeg 的默认线程模型 ( thread_type="FRAME"),该模型在批量读取时速度更快。

更重要的是,与 OpenCV 相比,ImageIO写入 JPEG 的速度要快得多这是因为 Pillow 比 ImageIO 所利用的 OpenCV 更快。在这种情况下,写入图像在运行时占据主导地位,因此使用 ImageIO 而不是 OpenCV 时,您最终会获得 2 倍的整体改进。

这是供参考的代码:

Read-Only Timings
=================
OpenCV:         0.453
imageio_ffmpeg: 0.765
imageio_pyav:   0.272
Run Code Online (Sandbox Code Playgroud)


小智 9

这是来自@GShocked的python 3.x的上一个答案的调整,我会将其发布到评论中,但没有足够的声誉

import sys
import argparse

import cv2
print(cv2.__version__)

def extractImages(pathIn, pathOut):
    vidcap = cv2.VideoCapture(pathIn)
    success,image = vidcap.read()
    count = 0
    success = True
    while success:
      success,image = vidcap.read()
      print ('Read a new frame: ', success)
      cv2.imwrite( pathOut + "\\frame%d.jpg" % count, image)     # save frame as JPEG file
      count += 1

if __name__=="__main__":
    print("aba")
    a = argparse.ArgumentParser()
    a.add_argument("--pathIn", help="path to video")
    a.add_argument("--pathOut", help="path to images")
    args = a.parse_args()
    print(args)
    extractImages(args.pathIn, args.pathOut)
Run Code Online (Sandbox Code Playgroud)


Har*_*tel 8

此功能可将大多数视频格式转换为视频中的帧数。它的工作原理上Python3OpenCV 3+

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 = '/path/to/video/00009.MTS'
    output_loc = '/path/to/output/frames/'
    video_to_frames(input_loc, output_loc)
Run Code Online (Sandbox Code Playgroud)

它支持.mts和常规文件,例如.mp4.avi。在.mts文件上尝试和测试。奇迹般有效。

  • 只需添加“if not ret: continue”即可跳过格式错误的帧(如果存在)! (2认同)

Puj*_*rma 7

经过大量关于如何将帧转换为视频的研究后,我创建了这个函数,希望对此有所帮助.我们需要opencv:

import cv2
import numpy as np
import os

def frames_to_video(inputpath,outputpath,fps):
   image_array = []
   files = [f for f in os.listdir(inputpath) if isfile(join(inputpath, f))]
   files.sort(key = lambda x: int(x[5:-4]))
   for i in range(len(files)):
       img = cv2.imread(inputpath + files[i])
       size =  (img.shape[1],img.shape[0])
       img = cv2.resize(img,size)
       image_array.append(img)
   fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')
   out = cv2.VideoWriter(outputpath,fourcc, fps, size)
   for i in range(len(image_array)):
       out.write(image_array[i])
   out.release()


inputpath = 'folder path'
outpath =  'video file path/video.mp4'
fps = 29
frames_to_video(inputpath,outpath,fps)
Run Code Online (Sandbox Code Playgroud)

根据您自己的本地位置更改fps(每秒帧数),输入文件夹路径和输出文件夹路径的值

  • 问题是从视频到帧 (4认同)

Nis*_*nga 7

以下脚本将每半秒提取文件夹中所有视频的帧。(适用于python 3.7)

import cv2
import os
listing = os.listdir(r'D:/Images/AllVideos')
count=1
for vid in listing:
    vid = r"D:/Images/AllVideos/"+vid
    vidcap = cv2.VideoCapture(vid)
    def getFrame(sec):
        vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
        hasFrames,image = vidcap.read()
        if hasFrames:
            cv2.imwrite("D:/Images/Frames/image"+str(count)+".jpg", image) # Save frame as JPG file
        return hasFrames
    sec = 0
    frameRate = 0.5 # Change this number to 1 for each 1 second
    
    success = getFrame(sec)
    while success:
        count = count + 1
        sec = sec + frameRate
        sec = round(sec, 2)
        success = getFrame(sec)
Run Code Online (Sandbox Code Playgroud)


Ben*_*ári 6

此功能以 1 fps 从视频中提取图像,此外,它还识别最后一帧并停止读取:

import cv2
import numpy as np

def extract_image_one_fps(video_source_path):

    vidcap = cv2.VideoCapture(video_source_path)
    count = 0
    success = True
    while success:
      vidcap.set(cv2.CAP_PROP_POS_MSEC,(count*1000))      
      success,image = vidcap.read()

      ## Stop when last frame is identified
      image_last = cv2.imread("frame{}.png".format(count-1))
      if np.array_equal(image,image_last):
          break

      cv2.imwrite("frame%d.png" % count, image)     # save frame as PNG file
      print '{}.sec reading a new frame: {} '.format(count,success)
      count += 1
Run Code Online (Sandbox Code Playgroud)


Yuc*_*ang 5

先前的答案丢失了第一帧。而且最好将图像存储在文件夹中。

# create a folder to store extracted images
import os
folder = 'test'  
os.mkdir(folder)
# use opencv to do the job
import cv2
print(cv2.__version__)  # my version is 3.1.0
vidcap = cv2.VideoCapture('test_video.mp4')
count = 0
while True:
    success,image = vidcap.read()
    if not success:
        break
    cv2.imwrite(os.path.join(folder,"frame{:d}.jpg".format(count)), image)     # save frame as JPEG file
    count += 1
print("{} images are extacted in {}.".format(count,folder))
Run Code Online (Sandbox Code Playgroud)

顺便说一下,您可以通过VLC 检查帧率。转到Windows->媒体信息->编解码器详细信息


小智 5

我通过 Anaconda 的 Spyder 软件使用 Python。使用@Gshocked 在该线程的问题中列出的原始代码,该代码不起作用(python 不会读取 mp4 文件)。所以我下载了 OpenCV 3.2 并从“bin”文件夹中复制了“opencv_ffmpeg320.dll”和“opencv_ffmpeg320_64.dll”。我将这两个 dll 文件都粘贴到 Anaconda 的“Dlls”文件夹中。

Anaconda 也有一个“pckgs”文件夹……我将下载的整个“OpenCV 3.2”文件夹复制并粘贴到 Anaconda 的“pckgs”文件夹中。

最后,Anaconda 有一个“Library”文件夹,其中有一个“bin”子文件夹。我将“opencv_ffmpeg320.dll”和“opencv_ffmpeg320_64.dll”文件粘贴到该文件夹​​中。

关闭并重新启动 Spyder 后,代码工作正常。我不确定这三种方法中的哪一种有效,我也懒得回去弄清楚。但它确实如此,干杯!


Rej*_*T J 5

此代码从视频中提取帧并将帧保存为.jpg formate

import cv2
import numpy as np
import os

# set video file path of input video with name and extension
vid = cv2.VideoCapture('VideoPath')


if not os.path.exists('images'):
    os.makedirs('images')

#for frame identity
index = 0
while(True):
    # Extract images
    ret, frame = vid.read()
    # end of frames
    if not ret: 
        break
    # Saves images
    name = './images/frame' + str(index) + '.jpg'
    print ('Creating...' + name)
    cv2.imwrite(name, frame)

    # next frame
    index += 1
Run Code Online (Sandbox Code Playgroud)