219

So I've followed this tutorial but it doesn't seem to do anything. Simply nothing. It waits a few seconds and closes the program. What is wrong with this code?

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

Also, in the comments it says that this limits the frames to 1000? Why?

EDIT: I tried doing success = True first but that didn't help. It only created one image that was 0 bytes.

Chris
  • 112,704
  • 77
  • 249
  • 231
GShocked
  • 3,606
  • 7
  • 25
  • 43
  • 1
    What's the value of `success`? – 101 Oct 23 '15 at 20:49
  • Its a boolean I believe, the code is from the tutorial I linked to. –  Oct 23 '15 at 20:50
  • 2
    What is the _value_? The _type_ may be boolean, but is it `True` or `False`? – That1Guy Oct 23 '15 at 20:50
  • 1
    Yes, but what is _your_ value? It might be false in which case your program would simply "wait a few seconds and close". In other words, add a `print success` somewhere. – 101 Oct 23 '15 at 20:51
  • I tried setting it to `True` but that only made one frame that was empty (0 bytes) –  Oct 23 '15 at 20:52
  • 1
    It doesn't make sense to force `success`; if it's false then that means the video read has failed for some reason. You need get that bit working first. – 101 Oct 23 '15 at 20:59
  • I've tried doing a full path to my video, doing `./`, doing just the name (like in the code) and the results don't change. I've tried several videos, with and without audio, and nothing works. –  Oct 23 '15 at 21:06
  • 1
    Your readh is failing. Have you built opencv with python and ffmpeg as instructed in the tutorial? `brew install opencv --python27 --ffmpeg` if you are using a different version of Python you will need to change it to your version. – Knells Oct 28 '15 at 02:01
  • 1
    Are you using OSX? Linux? Windows? – fireant Oct 28 '15 at 19:18

12 Answers12

373

From here download this video so we have the same video file for the test. Make sure to have that mp4 file in the same directory of your python code. Then also make sure to run the python interpreter from the same directory.

Then modify the code, ditch waitKey that's wasting time also without a window it cannot capture the keyboard events. Also we print the success value to make sure it's reading the frames successfully.

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

How does that go?

fireant
  • 13,282
  • 4
  • 35
  • 47
  • 4
    This saves an empty jpeg file, and it returns `Read a new frame: False` –  Oct 28 '15 at 23:06
  • 4
    That means opencv can not read the video. Most likely it cannot access ffmpeg. what OS are you using? – fireant Oct 28 '15 at 23:10
  • I've also tried this instead of the `while` loop, but it just made 50 empty jpegs. `for i in range(50): success,image = vidcap.read() cv2.imwrite('Frame ' + str(i) + '.jpg',image) ` –  Oct 28 '15 at 23:10
  • I did not realize I needed ffmpeg. I've tried using ffmpeg alone to separate the frames, but I couldn't figure out how to install it. I did not know if I needed the regular ffmpeg or pyffmpeg, which was troublesome. –  Oct 28 '15 at 23:13
  • 1
    Look at this: http://kronoskoders.logdown.com/posts/256664-installing-opencv-and-ffmpeg-on-windows – fireant Oct 28 '15 at 23:14
  • Still, even after installing ffmpeg and its env variables, I get the same output. I've tested and ffmpeg works in windows cmd, but not in Python. –  Oct 28 '15 at 23:28
  • 3
    Google the instructions for your specific version of opencv and follow precisely on how to get ffmpeg and opencv-python working on Windows. – fireant Oct 28 '15 at 23:40
  • 3
    So I used [this](http://stackoverflow.com/questions/11699298/opencv-2-4-videocapture-not-working-on-windows) question to solve my problem with the compatibility. I had to rename the DLL to opencv_ffmpeg300.dll (as the Python-installation of OpenCV2 was 3.0.0). I placed it into my Python directory (C:\Python27). I didn't need to install the windows version of ffmpeg nor opencv, but I did need that DLL that comes with OpenCV, but I deleted the rest of OpenCV after that. Anyhow, I will select this as an answer, but anyone reading this must know about this ESSENTIAL DLL. –  Oct 29 '15 at 00:33
  • 1
    @GShocked that looks like you should write up your own answer with that information in it. – Bill Woodger Oct 30 '15 at 10:38
  • @BillWoodger I did now –  Oct 30 '15 at 15:45
  • Does this require a vidcap.release() to close things out properly? – auro Jul 05 '16 at 20:30
  • @auro I don't think so. I don't have the time to go check the code now, but the destructor is [supposed](http://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-release) to call release() – fireant Jul 14 '16 at 18:45
  • Its not working for python 3. How can I use this with python 3? – Anmol Monga Feb 13 '17 at 09:33
  • @AnmolMonga simply replace `print 'Read a new frame: ', success` with `print('Read a new frame: ', success)` – Danny Wang Jul 21 '17 at 01:29
  • Anyone have advice for installing opencv-python with support for ffmpeg on os x? I found [this post](http://blog.jiashen.me/2014/12/23/build-opencv-3-on-mac-os-x-with-python-3-and-ffmpeg-support/) but it references another post by @Luigolas that has since been removed. – daveaseeman Dec 11 '17 at 22:59
  • @daveaseeman there are some tutorials on how to install opencv using homebrew, I think that has a flag for ffmpeg. If those blog posts / stackoverflow posts are not much of help then should ask a new question here. – fireant Dec 12 '17 at 05:11
  • 1
    an easy fix is to run frame extractor code in the folder where videos are located.! Somehow, cv2.VideoCapture() doesn't recognise the given video_path – Anu Sep 28 '18 at 03:17
  • 1
    Thanks for this amazing answer, helped me out a lot! +1 – U12-Forward Dec 26 '18 at 11:04
  • @Peter I agree! – U12-Forward Jan 11 '19 at 07:15
  • 1
    Good stuff this worked for me and replaced FFMpeg which was giving me issues – MNM Dec 04 '19 at 02:47
  • 1
    It's worked thank you, Done in Windows 10 python v3, opencv v2 – Dang_Ho Dec 07 '19 at 08:13
  • this worked for me, how can i tell to capture a couple of frames every second ? and not all of them – PayamB. Apr 05 '20 at 08:51
64

To extend on this question (& answer by @user2700065) for a slightly different cases, if anyone does not want to extract every frame but wants to extract frame every one second. So a 1-minute video will give 60 frames(images).

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)
Arsen Khachaturyan
  • 7,335
  • 4
  • 37
  • 38
BeeBee8
  • 2,646
  • 1
  • 21
  • 38
22

This is Function which will convert most of the video formats to number of frames there are in the video. It works on Python3 with 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()
        if not ret:
            continue
        # 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)

It supports .mts and normal files like .mp4 and .avi. Tried and Tested on .mts files. Works like a Charm.

Harsh Patel
  • 361
  • 4
  • 16
14

This is a tweak from previous answer for python 3.x from @GShocked, I would post it to the comment, but dont have enough reputation

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
  • 179
  • 1
  • 8
13

After a lot of research on how to convert frames to video I have created this function hope this helps. We require opencv for this:

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)

change the value of fps(frames per second),input folder path and output folder path according to your own local locations

Puja Sharma
  • 141
  • 1
  • 4
  • 1
    files.sort(key = lambda x: int(x[5:-4])) ADDING THE ABOVE LINE which helps to sort the frames according to the number and not the string eg: initially frame1.jpg was followed by frame10.jpg not frame2.jpg ,the line above sorts the files according to the numbers in it . – Puja Sharma May 05 '17 at 05:12
  • 4
    Question was from video to frame – Santhosh Dhaipule Chandrakanth Nov 30 '18 at 05:35
11

The previous answers have lost the first frame. And it will be nice to store the images in a 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))

By the way, you can check the frame rate by VLC. Go to windows -> media information -> codec details

Yuchao Jiang
  • 2,944
  • 27
  • 20
  • Is there a way to increase frame rate while extraction? – Pratik Khadloya Aug 19 '18 at 00:41
  • No. When a video is made, the frame rate is fixed. You can't extract more than that. – Yuchao Jiang Aug 20 '18 at 21:43
  • What an amazing answer. Worked perfectly for me. Would there be a way to tweak the loop in the code so that I only get frames from a certain range, like frame 120 - 160? Thanks! – Bowen Liu Feb 06 '20 at 01:03
  • You can use the variable count to specify the frames you would like to extract. – Yuchao Jiang Feb 07 '20 at 04:14
  • what do I have to do if I want to extract from the video let's say 15 frames that are positioned equidistantly in time from the video beginning to the video end? I found out I have to use `cv.CAP_PROP_POS_AVI_RATIO`, but I don't know how. tnx – NeStack Jun 26 '20 at 19:05
10

This code extract frames from the video and save the frames in .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
Rejoice T J
  • 109
  • 1
  • 4
9

Following script will extract frames every half a second of all videos in folder. (Works on 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)
Nishan
  • 2,776
  • 1
  • 23
  • 36
  • @KSp Because of `frameRate = 0.5` it extracts a frame every half a second, If your video length is 3 seconds, number of frames will be 6. – Nishan Feb 06 '21 at 09:10
7

This function extracts images from video with 1 fps, IN ADDITION it identifies the last frame and stops reading also:

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
Bence Kővári
  • 155
  • 1
  • 8
5

I am using Python via Anaconda's Spyder software. Using the original code listed in the question of this thread by @Gshocked, the code does not work (the python won't read the mp4 file). So I downloaded OpenCV 3.2 and copied "opencv_ffmpeg320.dll" and "opencv_ffmpeg320_64.dll" from the "bin" folder. I pasted both of these dll files to Anaconda's "Dlls" folder.

Anaconda also has a "pckgs" folder...I copied and pasted the entire "OpenCV 3.2" folder that I downloaded to the Anaconda "pckgs" folder.

Finally, Anaconda has a "Library" folder which has a "bin" subfolder. I pasted the "opencv_ffmpeg320.dll" and "opencv_ffmpeg320_64.dll" files to that folder.

After closing and restarting Spyder, the code worked. I'm not sure which of the three methods worked, and I'm too lazy to go back and figure it out. But it works so, cheers!

0

There are several reasons to extract slides/frames from a video presentation, especially in the case of education or conference related videos. It allows you to access the study notes without watching the whole video. I have faced this issue several times, so I decided to create a solution for it myself using python. I have made the code open-source, you can easily set up this tool and run it in few simple steps. Refer to this for youtube video tutorial. Steps on how to use this tool.

  • Clone this project video2pdfslides
  • Set up your environment by running "pip install -r requirements.txt"
  • Copy your video path
  • Run "python video2pdfslides.py <video_path>" Boom! the pdf slides will be available in in output folder Make notes and enjoy!
Kaushik J
  • 740
  • 3
  • 12
0

i might be late here but you can use this pip package to quickly generate images from videos. You can also get images using specific fps.

pip install videoToImages

then type the following command in terminal

videoToimages --videoFolder [pathToVideosFolder]

Example: videoToimages --videoFolder "c:/videos"

for specific output fps , set --fps 10 to any required value. --fps 1 means one image per one second of the video.

Full commands:

  • videoToimages --videoFolder "c:/videos"

  • videoToimages --videoFolder "c:/videos" --fps 10 --img_size (512, 512)

Ali Waqas
  • 109
  • 1
  • 10