AR141
AR141

Reputation: 35

Extracting frames from multiple videos in for loop

I am trying to extract frames from multiple video files in a for loop, using OpenCV. I have found several ways online to do frame extraction from a single video, however I am struggling to run the frame extraction within a for loop.

The working code for frame extraction from a single video (video variable) is:

cap=cv2.VideoCapture(video)
i=0
while (cap.isOpened()):    #
    ret, frame=cap.read()
    if ret == False:
        break
    cv2.imwrite(str(i) + '.jpg', frame)
    i+=1

cap.release()
cv2.destroyAllWindows()

I would like to extend this to include a for loop so that I can iterate through several videos (paths in videos variable) and extract all the frames. I would like the frame number from the video paths to run one after the other- i.e. if Video 1 has 30 frames extracted, Video 2 frames will be saved as 31, 32, 33 etc.

I tried to put the above code into a for loop, but it seems to run eternally and not save anything:

i=0 #place i outside of for-loop so it doesn't reset each iteration
for v in videos:
    cap=cv2.VideoCapture(v)
    while (cap.isOpened()):    #
        ret, frame=cap.read()
        if ret == False:
        break
        cv2.imwrite(str(i) + '.jpg', frame)
        i+=1

cap.release()
cv2.destroyAllWindows()

Is anyone able to help? Thankyou!

Upvotes: 1

Views: 4064

Answers (1)

Rotem
Rotem

Reputation: 32094

Iterating few video files is not so different from your implementation:

  • Use cap = cv2.VideoCapture(intput_filename) at the beginning of each "video file iteration". As you did.
  • Use cap.release() at the end of each "video file iteration".
    In the code you posted, it looks like you put the cap.release() at the wrong place.
  • Keep advancing the images counter (for giving sequential file names).
    As you did.

I am not sure about your code:

    if ret == False:
    break

It looks like the break is not indented correctly.


I created a "self contained" code sample which:

  • Generates two synthetic video files (used as input).
  • Iterate the video file names (in an outer loop).
    • read frames from the video file (in an inner loop).
    • Write frames to JPEG image files.
    • Display video frames while reading (for testing).

Here is the code:

import numpy as np
import cv2
import os

intput_filename1 = 'input_vid1.avi'
intput_filename2 = 'input_vid2.avi'

# List of video file names
intput_filenames = [intput_filename1, intput_filename2]

# Generate two synthetic video files to be used as input:
###############################################################################
width, height, n_frames = 640, 480, 30  # 30 frames, resolution 640x480

# Use motion JPEG codec (for testing)
synthetic_out = cv2.VideoWriter(intput_filename1, cv2.VideoWriter_fourcc(*'MJPG'), 25, (width, height))

for i in range(n_frames):
    img = np.full((height, width, 3), 60, np.uint8)
    cv2.putText(img, str(i+1), (width//2-100*len(str(i+1)), height//2+100), cv2.FONT_HERSHEY_DUPLEX, 10, (30, 255, 30), 20)  # Green number
    synthetic_out.write(img)

synthetic_out.release()

width, height, n_frames = 320, 240, 20 # 20 frames, resolution 320x240
synthetic_out = cv2.VideoWriter(intput_filename2, cv2.VideoWriter_fourcc(*'MJPG'), 25, (width, height))

for i in range(n_frames):
    img = np.full((height, width, 3), 60, np.uint8)
    cv2.putText(img, str(i+1), (width//2-50*len(str(i+1)), height//2+50), cv2.FONT_HERSHEY_DUPLEX, 5, (255, 30, 30), 10)  # Blue number
    synthetic_out.write(img)

synthetic_out.release()
###############################################################################


i = 1  # Images file counter

# Iterate file names:
for intput_filename in intput_filenames:
    cap = cv2.VideoCapture(intput_filename)

    # Keep iterating break
    while True:
        ret, frame = cap.read()  # Read frame from first video

        if ret:
            cv2.imwrite(str(i) + '.jpg', frame)  # Write frame to JPEG file (1.jpg, 2.jpg, ...)
            cv2.imshow('frame', frame)  # Display frame for testing
            i += 1 # Advance file counter
        else:
            # Break the internal loop when res status is False.
            break

        cv2.waitKey(100) #Wait 100msec (for debugging)

    cap.release() #Release must be inside the outer loop

cv2.destroyAllWindows()

Update:

Put this into a function:

def extract_multiple_videos(intput_filenames):
    """Extract video files into sequence of images.
       Intput_filenames is a list for video file names"""

    i = 1  # Counter of first video

    # Iterate file names:
    for intput_filename in intput_filenames:
        cap = cv2.VideoCapture(intput_filename)

        # Keep iterating break
        while True:
            ret, frame = cap.read()  # Read frame from first video

            if ret:
                cv2.imwrite(str(i) + '.jpg', frame)  # Write frame to JPEG file (1.jpg, 2.jpg, ...)
                cv2.imshow('frame', frame)  # Display frame for testing
                i += 1 # Advance file counter
            else:
                # Break the interal loop when res status is False.
                break

            cv2.waitKey(100) #Wait 100msec (for debugging)

        cap.release() #Release must be inside the outer loop

Upvotes: 2

Related Questions