Save video capture using opencv-python on Pop!_OS 22.04

Introduction

In previous posts:

I documented my installation of opencv-python and showed how to get video capture going. In this post, I'll focus on saving the video stream to an mp4 file on Pop!_OS (Ubuntu) 22.04. It turns out there are some issues, but I think I have things working.

The script

Let's start with the full script, given below. This is almost exactly the same as the the script in the previous post because many of the same things need to be done. The changes make sure the correct video codec is loaded for saving mp4 on Pop!_OS (Ubuntu) and telling the video writer that the video is grayscale (not color).

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2024 Christopher C. Strelioff <chris.strelioff@gmail.com>
#
# Distributed under terms of the MIT license.

"""
script02.py

Testing video capture and writing files on Pop_OS! (Ubuntu) 22.04
operating system.

Following documentation at:
https://docs.opencv.org/4.x/dd/d43/tutorial_py_video_display.html

"""

import numpy as np
import cv2

# pass argument 0 for device index (hopefully laptop cam)
vcap = cv2.VideoCapture(0);
if not vcap.isOpened():
print("Can't open camera!")
exit()

# get height and width of capture
width = int(vcap.get(3))
height = int(vcap.get(4))

# bool for isColor is optional, BUT defaults to True!
# - doing grayscale in the loop, so have to set to false!
isColor = False

# create VideoWriter
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
output = cv2.VideoWriter('video.mp4', fourcc, 20.0, (width, height), isColor)

# loop until
# - error reading frame from camera
# - or, user hits 'q'
while True:
# read a frame
ret, frame = vcap.read();

# ret == True if frame read correctly
if not ret:
print("Can't read frame, exiting...")
break

# process frame
# - change BGR -> GRAY (video should be grayscale)
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# display resulting fram
cv2.imshow('frame', gray_frame)

# write to the output
output.write(gray_frame)

# listen for 'q' press to exit
if cv2.waitKey(1) == ord('q'):
break

# everything done
# - release capture
# - release video writer
# - destroy all windows
vcap.release()
output.release()
cv2.destroyAllWindows()

setup

import numpy as np
import cv2

# pass argument 0 for device index (hopefully laptop cam)
vcap = cv2.VideoCapture(0);
if not vcap.isOpened():
print("Can't open camera!")
exit()

# get height and width of capture
width = int(vcap.get(3))
height = int(vcap.get(4))

# bool for isColor is optional, BUT defaults to True!
# - doing grayscale in the loop, so have to set to false!
isColor = False

# create VideoWriter
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
output = cv2.VideoWriter('video.mp4', fourcc, 20.0, (width, height), isColor)

This section of the script is almost the same as the previous post because many of the same things have to be done. I will only cover new parts of the script. So, if I don't mention something and you need more information, check the previous post .

The additions to this section include:

  • the width and height of the image from the camera are obtained, making sure to cast them as an integer:
    # get height and width of capture
    width = int(vcap.get(3))
    height = int(vcap.get(4))
  • a variable called isColor is set to False because opencv will assume the video is color unless told that it is NOT (the video is turned to grayscale in the main loop, see below):
    # bool for isColor is optional, BUT defaults to True!
    # - doing grayscale in the loop, so have to set to false!
    isColor = False
  • the video codec is selected as *'mp4v' (this works on Pop!_OS/Ubuntu with ffmpeg installed) and this is used to create the output, which saves to the file video.mp4 at 20 frames per second (obviously these can be changed):
    # create VideoWriter
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    output = cv2.VideoWriter('video.mp4', fourcc, 20.0, (width, height), isColor)

The fourcc setting above is specific to linux/Pop!_OS/Ubuntu and won't work for Windows or MAC. Start at the documentation to find a codec that will work for your machine.

main loop

# loop until
# - error reading frame from camera
# - or, user hits 'q'
while True:
# read a frame
ret, frame = vcap.read();

# ret == True if frame read correctly
if not ret:
print("Can't read frame, exiting...")
break

# process frame
# - change BGR -> GRAY (video should be grayscale)
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# display resulting fram
cv2.imshow('frame', gray_frame)

# write to the output
output.write(gray_frame)

# listen for 'q' press to exit
if cv2.waitKey(1) == ord('q'):
break

The main processing in the script happend in the while True loop. However, there is only one change to this section:

  • The current frame of the video is written to the file using output. Notice that we are giving the output gray_frame. This is why the VideoWriter had to be told the frame is NOT color above:
    # write to the output
    output.write(gray_frame)
  • Everything else in the loop is the same!

cleaning up and exit

The last lines of the script close (release) the camera, close (release) the output video writing, and close all open windows. In this case, the window showing the video feed is closed.

vcap.release()
output.release()
cv2.destroyAllWindows()

running the script

Running the script is the same as before. Again, the complete script is provided at the top of the post and can be placed in a single file, let's call it script02.py. This script has a shebang at the top ( #! /usr/bin/env python3 ) that tells bash how to run it. To do this, make sure the file is executable:

$ chmod u+x script02.py

Before running the script, make sure the virtual environment is active using ( see this post if you don't have this setup):

$ workon opencv
(opencv) $

With the virtual environment active, opencv-python and numpy are available. Finally, the script can be run using

(opencv) $ ./script02.py

assuming the script is in the local directory. To stop the video capture and writing the video file press q and the video window should close. That's it-- everything worked for me on Pop!_OS 22.04 on this date (Apr 25, 2024).