Python-ビデオフレームの抽出と保存


133

だから私はこのチュートリアルに従いましたが、それは何もしていません。単に何もない。数秒待ってプログラムを閉じます。このコードの何が問題になっていますか?

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

また、コメントでは、これによりフレームが1000に制限されると述べていますか?どうして?

編集:私はsuccess = True最初にやってみましたが、それは助けにはなりませんでした。0バイトのイメージを1つだけ作成しました。


1
の価値はsuccess何ですか?
101

2
は何ですか?タイプはブールかもしれないが、それはありますTrueFalse
That1Guy、2015年

1
はい、でもあなたの価値は何ですか?プログラムが単に「数秒待って閉じる」だけの場合は、falseになる可能性があります。つまり、print successどこかに追加します。
101:

1
強制するのは意味がありませんsuccess。falseの場合は、何らかの理由でビデオの読み取りが失敗したことを意味します。最初にそのビットを機能させる必要があります。
101:

1
あなたのreadhは失敗しています。チュートリアルの指示に従って、pythonとffmpegでopencvをビルドしましたか?brew install opencv --python27 --ffmpeg別のバージョンのPythonを使用している場合は、それを自分のバージョンに変更する必要があります。
Knells、2015年

回答:


226

ここからこのビデオをダウンロードして、テスト用の同じビデオファイルを用意します。その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

どうですか?


4
これは空のjpegファイルを保存し、それを返しますRead a new frame: False

3
つまり、opencvはビデオを読み取ることができません。ほとんどの場合、ffmpegにアクセスできません。どのOSを使用していますか?
火薬2015年


3
opencvの特定のバージョンの手順をGoogleに示し、ffmpegとopencv-pythonをWindowsで動作させる方法を正確に説明します。
火薬2015年

3
だから私は互換性の問題を解決するためにこの質問を使いました。DLLの名前をopencv_ffmpeg300.dllに変更する必要がありました(OpenCV2のPythonインストールが3.0.0だったため)。Pythonディレクトリ(C:\ Python27)に配置しました。Windowsバージョンのffmpegやopencvをインストールする必要はありませんでしたが、OpenCVに付属しているDLLは必要でしたが、その後、残りのOpenCVを削除しました。とにかく、私はこれを回答として選択しますが、これを読んでいる人は誰でもこのESSENTIAL DLLについて知っている必要があります。

37

すべてのフレームを抽出するのではなく、1秒ごとにフレームを抽出したい場合に、少し異なるケースでこの質問(および@ 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__":
    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)

私はを使用opencv-2.4.9しているため、代わりcv2.CAP_PROP_POS_MSECに使用する必要がありましたcv2.cv.CAP_PROP_POS_MSEC
Pratik Ku​​mar

1
5秒ごとにフレームが必要な場合にコードを変更するにはどうすればよいですか?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar、

@BhushanBabarはcv2.imwrite()ループのcv2.imread()前に呼び出したので、ループの最初にaがあってはいけませんか?
mLstudent33

@ mLstudent33申し訳ありませんが、わかりません。詳しく説明してください。
Bhushan Babar

12

これは@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)

11

これは、ほとんどのビデオ形式をビデオ内のフレーム数に変換する関数です。それはで動作Python3しますOpenCV 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)

それサポート.mtsなど通常のファイル.mp4.avi.mtsファイルで試してテストしました。チャームのように機能します。


8

フレームをビデオに変換する方法について多くの調査を行った後、この機能が役立つことを願ってこの関数を作成しました。これには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)

独自のローカルの場所に応じて、fps(frames per second)、入力フォルダーパス、出力フォルダーパスの値を変更します


files.sort(key = lambda x:int(x [5:-4]))上記の行を追加すると、文字列ではなく番号に従ってフレームを並べ替えることができます。例:最初はframe1.jpgの後にframe10.jpgが続きましたframe2.jpgではなく、上の行はファイルをその中の番号に従ってソートします。
Puja Sharma

3
質問はビデオからフレームまででした
Santhosh Dhaipule Chandrakanth 2018

何らかの理由で私のためにビデオを保存しない
ラクシャ

7

以前の回答では、最初のフレームが失われました。また、画像をフォルダに保存すると便利です。

# 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))

ちなみに、VLCでフレームレートを確認できます。ウィンドウに移動->メディア情報->コーデックの詳細


抽出中にフレームレートを上げる方法はありますか?
Pratik Khadloya

いいえ。ビデオが作成されるとき、フレームレートは固定されます。それ以上は抽出できません。
Yuchao Jiang

なんて素晴らしい答えでしょう。私には完璧に働きました。コードのループを微調整して、フレーム120-160のような特定の範囲のフレームのみを取得する方法はありますか?ありがとう!
Bowen Liu

変数countを使用して、抽出するフレームを指定できます。
Yuchao Jiang

ビデオから抽出したい場合、ビデオの開始からビデオの終了まで時間的に等間隔に配置された15フレームとしましょう。を使用する必要cv.CAP_PROP_POS_AVI_RATIOがあることがわかりましたが、方法がわかりません。tnx
NeStack

7

このコードは、ビデオからフレームを抽出し、フレームを.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

4

AnacondaのSpyderソフトウェアを介してPythonを使用しています。@Gshockedによるこのスレッドの質問にリストされている元のコードを使用すると、コードは機能しません(Pythonはmp4ファイルを読み取りません)。そこで、OpenCV 3.2をダウンロードして「opencv_ffmpeg320.dll」と「opencv_ffmpeg320_64.dll」を「bin」フォルダからコピーしました。これらのdllファイルの両方をAnacondaの「Dlls」フォルダーに貼り付けました。

Anacondaには「pckgs」フォルダーもあります...ダウンロードした「OpenCV 3.2」フォルダー全体をAnacondaの「pckgs」フォルダーにコピーして貼り付けました。

最後に、Anacondaには「bin」サブフォルダーを持つ「Library」フォルダーがあります。「opencv_ffmpeg320.dll」と「opencv_ffmpeg320_64.dll」のファイルをそのフォルダに貼り付けました。

Spyderを閉じて再起動した後、コードは機能しました。3つの方法のどれが機能したかはわかりません。また、戻ってそれを理解するのが面倒です。しかし、それはうまくいきます、乾杯!


4

この関数は、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

0

次のスクリプトは、フォルダー内のすべての動画の0.5秒ごとにフレームを抽出します。(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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.