nikki
nikki

Reputation: 353

how to make a video from extracted frames?

I extracted the video frames into a folder called "images". After getting images saved in my folder, I use the following code to create the video again. I get the video but the frames are ordered randomly, how can I arrange them in sequential order? thanks for the post

import cv2
import os


image_folder = 'images'
video_name = 'video.avi'

images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
frame = cv2.imread(os.path.join(image_folder, images[0]))
height, width, layers = frame.shape

video = cv2.VideoWriter(video_name, 0, 1, (width,height))

for image in images:
    video.write(cv2.imread(os.path.join(image_folder, image)))

cv2.destroyAllWindows()
video.release()

please advise, how do I fix this? I'd like the videos to be at the same rate as the original video, and frames to be in sequential order.

Upvotes: 5

Views: 2268

Answers (6)

user2853437
user2853437

Reputation: 780

  1. Print your images list and look at the order of your images? Are they sorted?
  2. What's the filename of your images? It's helpful to choose an increasing number like 00001.jpg and 00002.jpg instead of 1.jpg and 2.jpg this can mess up sorting.

    1. Sort the images after reading from os.listdir('.'): This is an example with pathlib library.
for filename in sorted([e for e in path.iterdir() if e.is_file() and str(e).endswith(".png")]):
    print(filename)
    img = cv2.imread(str(filename))
    img_array.append(img)

Or just using: for filename in sorted(os.listdir(path))

Upvotes: 3

Mo Khalefa
Mo Khalefa

Reputation: 576

This works fine with me

import cv2
import os


image_folder = 'c:\\m\\'
video_name = 'c:\\m\\avideo.avi'

images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]


frame = cv2.imread(os.path.join(image_folder, images[0]))
height, width, layers = frame.shape

#1 fps
#video = cv2.VideoWriter(video_name, 0, 1, (width,height))


#25 fps
video = cv2.VideoWriter(video_name, 0, 25, (width,height))

for image in images:
    video.write(cv2.imread(os.path.join(image_folder, image)))

cv2.destroyAllWindows()
video.release()

materials and result Here

Upvotes: 0

user3041840
user3041840

Reputation: 422

It seems you need natural sorting, so try natsort library:

from natsort import natsorted

images = natsorted(images)

Install using pip:

pip install natsort

Upvotes: 0

Jayendra Kantipudi
Jayendra Kantipudi

Reputation: 26

Try glob for listing files and sort the list. I have edited your code using glob. (Assuming your filenames of images are in the sequence you want)

import cv2
import os
import glob

video_name = 'video.avi'

images = glob.glob('images/*.jpg')
images.sort()

frame = cv2.imread(images[0])
height, width, layers = frame.shape

video = cv2.VideoWriter(video_name, 0, 1, (width,height))

for image in images:
    video.write(cv2.imread(image))

cv2.destroyAllWindows()
video.release() 

Upvotes: 0

Raburgos
Raburgos

Reputation: 1

Maybe you could try instead of saving images and load them again, make video captures from your source video and pass it to out object (demo_output.avi in this case) ...something like this:

import cv2

cap = cv2.VideoCapture('path to video/video.mp4')

fourcc = cv2.VideoWriter_fourcc(*'XVID')
ret, frame = cap.read()
fps_video=cap.get(cv2.CAP_PROP_FPS)
height,width = frame.shape[:2]
out = cv2.VideoWriter('demo_output.avi',fourcc, fps_video, (width,height)) ##can be set with your width,height values




while ret:
    frame = cv2.resize(frame, None, fx=1.0, fy=1.0, interpolation=cv2.INTER_AREA)

    out.write(frame)
    ret, frame = cap.read()

cap.release()
out.release()
cv2.destroyAllWindows()      

UPDATE:

If you want images and then save video file:

import cv2
import os
import numpy as np

vidcap = cv2.VideoCapture('path to video/video.mp4')
success,image = vidcap.read()
fps_video = vidcap.get(cv2.CAP_PROP_FPS)
height,width = image.shape[:2]
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

vidcap.release()
lista = [[x[5:-4],x] for x in os.listdir() if x.endswith('jpg')]

result=[]
for x in lista:
    t1,t2 = np.int(x[0]),x[1]
    result.append([t1,t2])

result.sort()

#recording video back
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('demo_output.avi',fourcc, fps_video, (width,height)) ##can be set with your width,height values

for img in result:
    frame = cv2.imread(img[1])
    out.write(frame)
out.release()

Upvotes: 0

soumith
soumith

Reputation: 616

If your requirement needs you to store the frames, try this

import cv2
import os


image_folder = 'images'
video_name = 'video.avi'

images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
frame = cv2.imread(os.path.join(image_folder, images[0]))
height, width, layers = frame.shape

video = cv2.VideoWriter(video_name, 0, 1, (width,height))

for i in range(len(images)):
    video.write(cv2.imread(os.path.join(image_folder, 'a'+str(i)+'.jpg')))

cv2.destroyAllWindows()
video.release()

Upvotes: 0

Related Questions