Python - Mengekstrak dan Menyimpan Bingkai Video


134

Jadi saya telah mengikuti tutorial ini tetapi sepertinya tidak melakukan apa-apa. Tidak ada apa-apa. Ini menunggu beberapa detik dan menutup program. Apa yang salah dengan kode ini?

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

Juga, di komentar dikatakan bahwa ini membatasi frame menjadi 1000? Mengapa?

EDIT: Saya mencoba melakukan success = Truedulu tetapi itu tidak membantu. Itu hanya membuat satu gambar yang berukuran 0 byte.


1
Apa nilainya success?
101

2
Apa nilainya ? The Tipe mungkin boolean, tetapi apakah itu Trueatau False?
That1Guy

1
Ya, tapi apa nilai Anda ? Mungkin salah dalam hal ini program Anda hanya akan "menunggu beberapa detik dan menutup". Dengan kata lain, tambahkan suatu print successtempat.
101

1
Tidak masuk akal untuk memaksa success; jika salah maka itu berarti pembacaan video gagal karena beberapa alasan. Anda perlu sedikit bekerja dulu.
101

1
Readh Anda gagal. Sudahkah Anda membangun opencv dengan python dan ffmpeg seperti yang diinstruksikan dalam tutorial? brew install opencv --python27 --ffmpegjika Anda menggunakan versi Python yang berbeda, Anda perlu mengubahnya ke versi Anda.
Knells

Jawaban:


227

Dari sini unduh video ini sehingga kami memiliki file video yang sama untuk pengujian. Pastikan untuk memiliki file mp4 di direktori yang sama dengan kode python Anda. Kemudian pastikan juga untuk menjalankan interpreter python dari direktori yang sama.

Kemudian ubah kodenya, selokan waitKeyyang membuang-buang waktu juga tanpa jendela tidak dapat menangkap acara keyboard. Juga kami mencetak successnilai untuk memastikan itu membaca bingkai dengan sukses.

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

Bagaimana hasilnya?


4
Ini menyimpan file jpeg kosong, dan kembaliRead a new frame: False

3
Artinya opencv tidak bisa membaca videonya. Kemungkinan besar itu tidak dapat mengakses ffmpeg. OS apa yang Anda gunakan?
pemadam kebakaran


3
Google petunjuk untuk versi spesifik opencv Anda dan ikuti dengan tepat tentang cara membuat ffmpeg dan opencv-python bekerja di Windows.
pemadam kebakaran

3
Jadi saya menggunakan pertanyaan ini untuk menyelesaikan masalah saya dengan kompatibilitas. Saya harus mengganti nama DLL menjadi opencv_ffmpeg300.dll (karena instalasi Python OpenCV2 adalah 3.0.0). Saya menempatkannya ke direktori Python saya (C: \ Python27). Saya tidak perlu menginstal versi windows dari ffmpeg atau opencv, tetapi saya memang membutuhkan DLL yang disertakan dengan OpenCV, tetapi saya menghapus sisa OpenCV setelah itu. Bagaimanapun, saya akan memilih ini sebagai jawaban, tetapi siapa pun yang membaca ini harus tahu tentang DLL ESENSIAL ini.

37

Untuk memperluas pertanyaan ini (& jawaban oleh @ user2700065) untuk kasus yang sedikit berbeda, jika ada yang tidak ingin mengekstrak setiap frame tetapi ingin mengekstrak frame setiap satu detik. Jadi video 1 menit akan memberikan 60 frame (gambar).

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)

Saya menggunakan opencv-2.4.9, jadi alih-alih cv2.CAP_PROP_POS_MSECsaya harus menggunakancv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
Bagaimana cara mengubah kode jika saya ingin frame setiap katakan 5 detik?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar

@BhushanBabar seharusnya tidak ada cv2.imwrite()di awal loop karena Anda memanggil cv2.imread()sebelum loop?
mLstudent33

@ mLstudent33 maaf, tidak mengerti, tolong jelaskan.
Bhushan Babar

12

Ini adalah tweak dari jawaban sebelumnya untuk python 3.x dari @GShocked, saya akan mempostingnya ke komentar, tetapi tidak memiliki reputasi yang cukup

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

Ini adalah Fungsi yang akan mengubah sebagian besar format video ke jumlah bingkai yang ada di video. Ini bekerja Python3denganOpenCV 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)

Ini mendukung .mtsdan file normal seperti .mp4dan .avi. Dicoba dan Diuji pada .mtsfile. Bekerja seperti Mantra.


8

Setelah banyak penelitian tentang cara mengonversi bingkai ke video, saya telah membuat fungsi ini, semoga ini membantu. Kami membutuhkan opencv untuk ini:

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)

ubah nilai fps (frame per detik), jalur folder input dan jalur folder output sesuai dengan lokasi lokal Anda sendiri


files.sort (key = lambda x: int (x [5: -4])) MENAMBAHKAN GARIS DI ATAS yang membantu mengurutkan frame sesuai dengan nomor dan bukan stringnya misalnya: awalnya frame1.jpg diikuti oleh frame10.jpg bukan frame2.jpg, baris di atas mengurutkan file sesuai dengan nomor di dalamnya.
Puja Sharma

3
Pertanyaannya dari video ke frame
Santhosh Dhaipule Chandrakanth

tidak menyimpan video untuk saya karena suatu alasan
Raksha

7

Jawaban sebelumnya kehilangan frame pertama. Dan akan menyenangkan untuk menyimpan gambar dalam sebuah folder.

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

Ngomong-ngomong, Anda bisa mengecek frame rat e oleh VLC. Buka windows -> informasi media -> detail codec


Apakah ada cara untuk meningkatkan frekuensi gambar saat ekstraksi?
Pratik Khadloya

Tidak. Saat video dibuat, kecepatan bingkai ditetapkan. Anda tidak dapat mengekstrak lebih dari itu.
Yuchao Jiang

Jawaban yang luar biasa. Bekerja dengan sempurna untuk saya. Apakah akan ada cara untuk mengubah loop dalam kode sehingga saya hanya mendapatkan frame dari jarak tertentu, seperti frame 120 - 160? Terima kasih!
Bowen Liu

Anda dapat menggunakan jumlah variabel untuk menentukan bingkai yang ingin Anda ekstrak.
Yuchao Jiang

apa yang harus saya lakukan jika saya ingin mengekstrak dari video, katakanlah 15 frame yang diposisikan dengan jarak yang sama dari awal video hingga akhir video? Saya menemukan saya harus menggunakan cv.CAP_PROP_POS_AVI_RATIO, tetapi saya tidak tahu caranya. tnx
NeStack

7

Kode ini mengekstrak bingkai dari video dan menyimpan bingkai dalam format .jpg

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

Saya menggunakan Python melalui perangkat lunak Spyder Anaconda. Menggunakan kode asli yang tercantum dalam pertanyaan thread ini oleh @Gshocked, kode tersebut tidak berfungsi (python tidak akan membaca file mp4). Jadi saya mengunduh OpenCV 3.2 dan menyalin "opencv_ffmpeg320.dll" dan "opencv_ffmpeg320_64.dll" dari folder "bin". Saya menempelkan kedua file dll ini ke folder "Dlls" Anaconda.

Anaconda juga memiliki folder "pckgs" ... Saya menyalin dan menempelkan seluruh folder "OpenCV 3.2" yang saya download ke folder "pckgs" Anaconda.

Terakhir, Anaconda memiliki folder "Library" yang memiliki subfolder "bin". Saya menempelkan file "opencv_ffmpeg320.dll" dan "opencv_ffmpeg320_64.dll" ke folder itu.

Setelah menutup dan memulai ulang Spyder, kode tersebut berfungsi. Saya tidak yakin mana dari ketiga metode tersebut yang berhasil, dan saya terlalu malas untuk kembali dan mencari tahu. Tapi berhasil, selamat!


4

Fungsi ini mengekstrak gambar dari video dengan 1 fps, SELAIN itu, ini mengidentifikasi bingkai terakhir dan juga berhenti membaca:

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

Skrip berikut akan mengekstrak frame setiap setengah detik dari semua video di folder. (Bekerja pada 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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.