john
john

Reputation: 629

Python function to read video and convert to frames

I want to convert my input video to a set of frames. I have read the post on Python - Extracting and Saving Video Frames.

But I would like to have a function where I can insert the video as the parameter, not the location of the video file.

In the VideoCapture function below, it takes in the location of the video file.

import cv2
def vidtoframes(videoFile):
 vidcap = cv2.VideoCapture(videoFile)
 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

But is there a function or way to pass a video to the method and convert it to array of frames without saving anything onto the disk.

Upvotes: 3

Views: 4423

Answers (3)

VocoJax
VocoJax

Reputation: 1549

Yes! There is! But it will require a wee bit of setup. Everything is detailed here:

Streaming video in memory with OpenCV VideoWriter and Python BytesIO

The basics are that you need a tmpfs partition in linux, and utilize the tempfile functionality of Python (which just wraps mkstemp in linux again).

If you have a video file in memory already, something like:

video_bytes = s3.download('file.avi')

And just want to deal with it in memory (and continue to use OpenCV), then check out the other post I listed above.

Upvotes: 0

Assaf Genosar
Assaf Genosar

Reputation: 508

OO approch: write a sort of "VideoWrapper" class and derived classes:

from abc import abstractmethod

class VideoWrapper:
    def __init__(self, path: str, chunk_size: int = 1):
        self.path = path
        self.chunk_size = chunk_size

    @abstractmethod
    def __iter__(self): ...

class VideoFileWrapper(VideoWrapper):
    def __iter__(self):
        chunk = []
        cap = cv2.VideoCapture(self.path)
        while cap.isOpened():
            ret, frame = cap.read()
            chunk.append(frame)
            if len(chunk) == self.chunk_size:
                yield chunk
                chunk = []


class VideoFolderWrapper(VideoWrapper):
    def __iter__(self):
        chunk = []
        for frame_path in glob(os.path.join(self.path, '*')):
            frame = cv2.imread(frame_path)
            chunk.append(frame)
            if len(chunk) == self.chunk_size:
               yield chunk
               chunk = []

in that case you could pass a single class type across your code. an even nicer class would implement __enter__ and __exit__ methods in order to use the with statement, exception handling and so on. that might be too much, a simpler "Pythonic" version will be:

def video_wrapper(path):
    if os.path.isdir(path):
        frames = list(glob(os.path.join(path, '*.png')))
        frames.sort(key=file_name_order)
        for frame_path in frames:
            frame = cv2.cvtColor(cv2.imread(frame_path),cv2.COLOR_BGR2RGB)
            yield frame
    elif os.path.exists(path):
        cap = cv2.VideoCapture(path)
        while cap.isOpened():
        ret, frame = cap.read()
        yield frame

Upvotes: 0

hidrana jiglle
hidrana jiglle

Reputation: 34

The video that is taken must be saved to a directory and then we can perform the functions upon it. That is how an application would work as well.

Upvotes: 1

Related Questions