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


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

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


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)

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

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 код заработал. Я не уверен, какой из трех методов сработал, и мне лень возвращаться и разбираться в этом. Но работает так, ура!


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.