Open CV VideoWriter creates empty file - no error thrown

Viewed 197

I'm trying to convert frames stored in a folder into a video file. I'm using open cv2.VideoWriter() to do this, it doesn't throw any error but the files produced are empty. I was trying to change fourcc and frames per second but nothing works. Would you have a look at teh code and suggest what may cause this issue?

import cv2
import numpy as np
import os
from os.path import isfile, join
import re
import natsort 

def convert_frames_to_video(pathIn,pathOut,fps):
    frame_array = []
    files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]
    #for sorting the file names properly
    natsort.natsorted(files,reverse=True)
    #files.sort(key=lambda f: int(re.sub('\D', '', f)))
    for i in range(len(files)):
        filename=pathIn + files[i]
        #reading each files
        img = cv2.imread(filename)
        height = 407
        width = 724
        layers = 3
        #height, width, layers = cv2.imread(img).shape
        size = (width,height)
        print(filename)
        #inserting the frames into an image array
        frame_array.append(img)
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        out = cv2.VideoWriter(pathOut,fourcc, fps, size)
    for i in range(len(frame_array)):
        # writing to a image array
        out.write(frame_array[i])
    out.release()
def main():
    pathIn= '/content/CarND-LaneLines-P1/White Right Detected'
    pathOut = '/content/CarND-LaneLines-P1/vid4.mp4'
    fps = 8.0
    convert_frames_to_video(pathIn, pathOut, fps)
if __name__=="__main__":
    main()

Files stored in the folder are all .jpg format with names like: frame1, frame2 etc.

1 Answers

You're missing a forward slash / in the command filename=pathIn + files[i], and ended up adding None to your frame_array, because cv2.imread doesn't return any error indication if the path or image does not exist:

Even if the image path is wrong, it won't throw any error, but print img will give you None

In [135]: x = cv2.imread("NON_EXISTING_IMAGE")
In [136]: type(x)
Out[136]: NoneType

You also have to use the expected image size described in the cv2.VideoWriter(pathOut,fourcc, fps, size) for all your images. If that is not the case for the frames in your folder, you would've to use resize as the example below:

img = cv2.resize(img, size)

Im my test case I've used a different input image shape, so I apply the resize function to match your expected height and width:

/content
├── CarND-LaneLines-P1
│   ├── vid4.mp4
│   └── White Right Detected
│       ├── ezgif-frame-001.jpg  # (338, 600, 3)
│       ├── ezgif-frame-002.jpg  # (338, 600, 3)
│       ├── ezgif-frame-003.jpg  # (338, 600, 3)
|       ├── ...
|       ├── ...
import cv2
import numpy as np
import os
from os.path import isfile, join
import re
import natsort 

def convert_frames_to_video(pathIn,pathOut,fps):
    files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]
    #for sorting the file names properly
    natsort.natsorted(files,reverse=True)
    #files.sort(key=lambda f: int(re.sub('\D', '', f)))
    height = 407
    width = 724
    layers = 3
    #height, width, layers = cv2.imread(img).shape
    size = (width,height)    
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(pathOut,fourcc, fps, size)
    for frame_file in files:
        # use join here as in your early list comprehension
        filename= join(pathIn, frame_file)
        #reading each files
        img = cv2.imread(filename)
        #resize each file
        img = cv2.resize(img, size)
        out.write(img)
    out.release()

def main():
    pathIn= '/content/CarND-LaneLines-P1/White Right Detected'
    pathOut = '/content/CarND-LaneLines-P1/vid4.mp4'
    fps = 8.0
    convert_frames_to_video(pathIn, pathOut, fps)
if __name__=="__main__":
    main()
#ls -lah "/content/CarND-LaneLines-P1/vid4.mp4"
-rw-r--r-- 1 root root 1.4M May  9 14:42 /content/CarND-LaneLines-P1/vid4.mp4
Related