Python - извлечение и сохранение видеокадров

135

Итак, я следовал этому руководству, но, похоже, он ничего не делает. Просто ничего. Он ждет несколько секунд и закрывает программу. Что не так с этим кодом?

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 байт.

GShocked
источник
1
В чем ценность success?
101
2
В чем ценность ? Тип может быть логическим, но это Trueили False?
That1Guy
1
Да, но какова ваша ценность? Это может быть ложно, и в этом случае ваша программа просто «подождет несколько секунд и закроется». Другими словами, добавьте print successгде-нибудь.
101
1
Нет смысла заставлять success; если это false, значит, по какой-то причине чтение видео не удалось. Сначала вам нужно заставить этот бит работать.
101
1
Ваше чтение не работает. Вы создали opencv с помощью python и ffmpeg, как описано в руководстве? brew install opencv --python27 --ffmpegесли вы используете другую версию Python, вам нужно будет изменить ее на свою версию.
Knells

Ответы:

228

От сюда скачать это видео таким образом , мы имеем тот же видеофайл для тестирования. Убедитесь, что файл 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

Как это происходит?

FireAnt
источник
4
Это сохраняет пустой файл jpeg, и он возвращаетсяRead a new frame: False
3
Это означает, что opencv не может прочитать видео. Скорее всего, он не может получить доступ к ffmpeg. какую ОС вы используете?
fireant
1
Посмотрите на это: kronoskoders.logdown.com/posts/…
fireant
3
Погуглите инструкции для вашей конкретной версии opencv и точно следуйте тому, как заставить ffmpeg и opencv-python работать в Windows.
fireant
3
Поэтому я использовал этот вопрос, чтобы решить свою проблему с совместимостью. Мне пришлось переименовать DLL в opencv_ffmpeg300.dll (поскольку Python-установка OpenCV2 была 3.0.0). Я поместил его в свой каталог Python (C: \ Python27). Мне не нужно было устанавливать версию ffmpeg или opencv для Windows, но мне нужна была эта 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
Pratik Kumar
1
Как изменить код, если мне нужны кадры каждые, скажем, 5 секунд?
Soumya Boral
1
@SoumyaBoralcount = count + 5
Бхушан Бабар
@BhushanBabar не должно быть cv2.imwrite()в начале цикла, так как вы вызывали его cv2.imread()перед циклом?
mLstudent33
@ mLstudent33 извините, не понимаю, пожалуйста, уточнить.
Bhushan Babar
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)
XRarach
источник
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 (кадров в секунду), путь к папке ввода и путь к папке вывода в соответствии с вашими локальными местоположениями

Пуджа Шарма
источник
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))

Кстати, вы можете проверить количество кадров по VLC. Перейдите в окна -> информация о мультимедиа -> сведения о кодеке

Ючао Цзян
источник
Есть ли способ увеличить частоту кадров при извлечении?
Pratik Khadloya
Нет. При создании видео частота кадров фиксирована. Вы не можете извлечь большего.
Yuchao Jiang
Какой замечательный ответ. У меня отлично сработало. Есть ли способ настроить цикл в коде, чтобы я получал кадры только из определенного диапазона, например кадра 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
Радуйтесь, TJ
источник
4

Я использую Python через программу Anaconda Spyder. Используя исходный код, указанный в вопросе этой ветки @Gshocked, код не работает (python не читает файл mp4). Поэтому я загрузил OpenCV 3.2 и скопировал «opencv_ffmpeg320.dll» и «opencv_ffmpeg320_64.dll» из папки «bin». Я вставил оба этих файла dll в папку «Dlls» Anaconda.

У Anaconda также есть папка «pckgs» ... Я скопировал и вставил всю папку «OpenCV 3.2», которую я загрузил, в папку «pckgs» Anaconda.

Наконец, в Anaconda есть папка «Библиотека», в которой есть подпапка «bin». Я вставил в эту папку файлы «opencv_ffmpeg320.dll» и «opencv_ffmpeg320_64.dll».

После закрытия и перезапуска Spyder код заработал. Я не уверен, какой из трех методов сработал, и мне лень возвращаться и разбираться в этом. Но работает так, ура!

SpaceFarmer2020
источник
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)
Нишан Викрамаратна
источник