Python - витяг та збереження відеокадрів


134

Тому я дотримувався цього підручника, але, здається, він нічого не робить. Просто нічого. Він чекає кілька секунд і закриває програму. Що не так з цим кодом?

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? Чому?

EDIT: Я спробував зробити success = Trueперший, але це не допомогло. Він створив лише одне зображення, яке було 0 байт.


1
У чому цінність success?
101

2
Яка цінність ? Тип може бути логічним, але це Trueабо False?
That1Guy

1
Так, але яка ваша цінність? Це може бути помилковим, у такому випадку ваша програма просто "зачекає кілька секунд і закриється". Іншими словами, print successдесь додайте .
101

1
Не має сенсу змушувати success; якщо це неправда, то це означає, що прочитане відео чомусь не вдалося. Перш за все, вам потрібно працювати.
101

1
Ваш readh провалюється. Чи побудували ви opencv з python та ffmpeg згідно інструкцій у підручнику? brew install opencv --python27 --ffmpegякщо ви використовуєте іншу версію Python, вам потрібно буде змінити її на свою версію.
Встає

Відповіді:


227

Від сюди завантажити це відео таким чином , ми маємо той же відеофайл для тестування. Переконайтеся, що цей 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. яку ОС ви використовуєте?
пожежник

1
Подивіться на це: kronoskoders.logdown.com/posts/…
пожежний

3
Інструкції Google щодо вашої конкретної версії opencv і точно дотримуйтесь того, як змусити ffmpeg і opencv-python працювати в Windows.
пожежник

3
Тому я використав це питання, щоб вирішити свою проблему із сумісністю. Мені довелося перейменувати DLL на opencv_ffmpeg300.dll (оскільки встановлення Python OpenCV2 становило 3.0.0). Я помістив його у свій каталог Python (C: \ Python27). Мені не потрібно було встановлювати версію Windows ffmpeg ні opencv, але мені була потрібна DLL, яка постачається з OpenCV, але решту OpenCV я видалив після цього. Так чи інакше, я виберу це як відповідь, але кожен, хто читає це, повинен знати про цю ОСНОВНУ DLL.

37

Поширити це питання (& відповідь від @ 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
Пратік Кумар

1
Як змінити код, якщо я хочу кадри кожні 5 хвилин?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan

@BhushanBabar, чи не повинно бути cv2.imwrite()на початку циклу, оскільки ви дзвонили cv2.imread()перед циклом?
mLstudent33

@ mLstudent33 Вибачте, не зрозумійте, будь ласка, докладно.
Bhushan

12

Це налаштування з попередньої відповіді на python 3.x від @GShocked, я б опублікував це до коментаря, але не маю достатньої репутації

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)

змінити значення кадрів в секунду (кадрів в секунду), шлях вхідної папки та шлях до папки відповідно до ваших місцевих локацій


files.sort (key = lambda x: int (x [5: -4])) ДОБАВЛЕННЯ ВІДПОВІДНОЇ ЛІНІЇ, яка допомагає сортувати кадри за кількістю, а не за рядком, наприклад: спочатку frame1.jpg супроводжувався frame10.jpg не frame2.jpg, рядок вище сортує файли за номерами, що містяться в ньому.
Пуджа Шарма

3
Питання було від відео до кадру
Santhosh Dhaipule Chandrakanth

не зберігаючи відео для мене чомусь
Ракша

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

До речі, ви можете перевірити рамку щура e за допомогою VLC. Перейдіть до Windows -> інформація про медіа -> деталі кодека


Чи є спосіб збільшити частоту кадрів під час вилучення?
Пратік Хадлоя

Ні. Коли зроблено відео, частота кадрів фіксується. Ви не можете витягти більше цього.
Ючао Цзян

Яка дивовижна відповідь. Для мене прекрасно працювали. Чи не було б способу змінити цикл у коді, щоб я отримав лише кадри з певного діапазону, наприклад, кадрів 120 - 160? Дякую!
Боуен Лю

Ви можете використовувати кількість змінних, щоб вказати кадри, які ви хочете витягти.
Ючао Цзян

що мені робити, якщо я хочу витягнути з відео, скажімо, 15 кадрів, розміщених рівномірно за часом від початку відео до кінця відео? Я дізнався, що мені потрібно користуватися cv.CAP_PROP_POS_AVI_RATIO, але не знаю як. tnx
NeStack

7

Цей код витягує кадри з відео та зберігає кадри у форматі .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

Я використовую Python через програмне забезпечення Spyder Anaconda. Використовуючи оригінальний код, перелічений у питанні цієї теми від @Gshocked, код не працює (python не прочитає файл mp4). Тому я завантажив OpenCV 3.2 і скопіював "opencv_ffmpeg320.dll" і "opencv_ffmpeg320_64.dll" з папки "bin". Я вставив обидва ці файли dll у папку "Dlls" Анаконда.

Анаконда також має папку "pckgs" ... Я скопіював і вставив всю папку "OpenCV 3.2", яку я завантажив у папку Anaconda "pckgs".

Нарешті, у Anaconda є папка "Бібліотека", в якій є підпапка "bin". Я вставив файли "opencv_ffmpeg320.dll" і "opencv_ffmpeg320_64.dll" у цю папку.

Після закриття та перезавантаження Spyder код спрацював. Я не впевнений, який із трьох методів працював, і я лінивий, щоб повернутися назад і зрозуміти це. Але це працює так, ура!


4

Ця функція витягує зображення з відео з 1 кадром в секунду, В ДОДАТКІ він визначає останній кадр і зупиняє читання також:

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

Наступний сценарій буде витягувати кадри кожні півсекунди всіх відео в папці. (Працює на 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.