2

I am trying to take 2 images present in a local folder and use OpenCV's Videowriter function to create a video from these images. I am using FrameRate of 1. So this creates a video of 2 seconds duration. Below is the code (I got it from here):

import cv2
import os

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

images = [img for img in os.listdir(image_folder) if img.endswith(".png")]
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()

Goal: I want to create a video of 10 seconds which will have these 2 images each being displayed for 5 seconds.

I think there might be a similar question like this in the forum but I am not able to find it. If someone can point me to the solution, it would be great.

Thank you.

Ram Kumar V
  • 103
  • 3
  • 8
  • 1
    whats the bug you have? and where you are stuck at? if you are using timing to control the output. Then shouldn`t you have a while loop, while not over 10 sec time. In if in first 5 sec do thing, else in later 5 sec do another, cv:;waitkey or direct timing/sequence check. not very sure fps can be 1 or not. usually it 15 -30. and we just pad the same image eover and over again. – Dr Yuan Shenghai Jun 08 '19 at 15:29
  • 1
    Why not just use `ffmpeg`? If your stills are called `image1.png` and `image2.png`, you can just run `ffmpeg -r 0.2 -i image%d.png -pix_fmt yuv420p video.avi` – Mark Setchell Jun 08 '19 at 16:20

2 Answers2

4

The below code snippet should solve your problem. Notice that you will have to specify each_image_duration. I used this variable to write the each image in the video for a specific duration. For this use case, you have to keep the fps as 1.0, so each video frame will be displayed for 1.0 sec. This makes the 3rd argument in cv2.Videowriter.

import cv2
import os

image_folder = 'images'
video_name = 'video.avi'
each_image_duration = 5 # in secs
fourcc = cv2.VideoWriter_fourcc(*'XVID') # define the video codec

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

video = cv2.VideoWriter(video_name, fourcc, 1.0, (width, height))

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

cv2.destroyAllWindows()
video.release()
Aditya
  • 533
  • 3
  • 11
  • Thank you @Dr Yuan Shenghai for the idea. I didn't think of padding the same image again and again for 5 secs which now seems the obvious thing to do. And thank you Aditya for implementing this idea. – Ram Kumar V Jun 09 '19 at 02:26
  • I'm trying to do this with 400 images but what happens is that from time to time a lot of images are displayed for less than 1 sec and then one image stays on the screen for 10 secs (I used image duration as 2). – pceccon Nov 10 '20 at 18:35
0

Here you can calculate fps dynamically based on how many frames you have and how many seconds of video you want to make.

See code below:

import cv2
import os

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

fourcc = cv2.VideoWriter_fourcc(*'XVID') # define the video codec

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

video = cv2.VideoWriter(video_name, fourcc, float(img_count/video_secs), (width, height))

for image in images:
    video.write(image)

cv2.destroyAllWindows()
video.release()
Enginerd Sunio
  • 333
  • 2
  • 12