Video recorder example

The first example, called "VidRecord", may be used to capture live video from an all sky camera and periodically save an image or record to a video file. This relatively simple example is developed for GNU C++ on Ubuntu, Visual C++ on Microsoft Windows, and Python which will run on both MS Windows and Ubuntu. On my machine the Python example records video at 15 fps. The C++ versions running on Ubuntu and MS Windows records at 30 fps.

File names of the recorded video or images are created using current date/time in GMT when file is created.

Command line arguments:

-dis=[True|False] : Whether or not to display video frame from device on your computer screen (default is True)
-viddev=n : Select video device (default is 0, usually 0, 1, or 2)
-viddir=XXX: Set directory to store videos (default is the Videos directory in the user's home directory $HOME/Videos )
-vidint=n : Length of a video in seconds (default is 60)
-vidnum=n : Number of videos to be recorded (default is 0)
-codec=XXXX : Video codec to use when recording (default is DIVX)
-imgint=n : Interval for saving image a file in seconds (default is 60)
-imgfmt=[jpg,png,tif] : Image format to save interval image (default is jpg)
-imgdir=XXX: Set directory to store images ( defalt is Pictures direcotry in the user's home directory, $HOME/Pictures)
-imgnum=n : Number of images to be recorded (default is 0)

The user may view current video frames by adding -dis=True to the command line. Video recording is started by clicking on the display frame and pressing the 'r' key. To stop recording press 'r' again. To capture an image press the 'i' key and 'i' again to stop image capture.

Command line examples:
Record videos from video device 1 without a display, each 20 seconds long for 2 hours
VidRecord -dis=False -viddev=1 -vidint=20 vidnum=360

Capture a picure every 30 seconds from video device 2 for 1 hour
VidRecord -viddev=2 imgint=30 imglen=120

Above params may also be set in a config file called ".vidrecordrc" located in you home directory.
One parameter setting per line in the form NAME=VALUE, you may add comments by starting a line with '#'
For example...

# ----------
# Disable display of video frames on the screen
dis=False
# Capture 20 images
imgnum=20
# Capture an image each 30 second time interval
imgint=30
# Save the image in the PNG format
imgfmt=png
# ----------

Command line arguments override those loaded from the config file.

VidRecord example in C++

You may download the source code for this example. The VidRecord example software is released under terms of the Open Source Initiative BSD 2 - Clause license. Copy of the license for this software is at http://www.raben.com/sites/default/files/allsky/software/license.txt . If you have not already done so, download and install OpenCV on your local machine, see the installation notes. Unzip the VidRecordCpp.zip file somewhere in your local directory. It will create a directory called "VidRecord" containing the source files and license.

To compile on Ubuntu 12.04

unzip VidRecordCpp.zip
cd VidRecord
mkdir build
cd build
cmake ..
make
make install

To compile on MS Windows Vista or Windows 7

  • Download and install CMake from http://www.cmake.org
  • Start up CMake and set the source directory to the VidRecord directory you previously unzipped. Set the binaries directory to be just below the source in a directory called say "build", something like WHATEVER\VidRecord\build
  • Click on the "Configure" button.
  • Click on the "Build" button
  • Use Visual Studio 2010, 2011, 2012 edition if you already have it. If not, download and install MS Windows Visual Studio Express 2011 or 2012 from www.microsoft.com (Currently the free Express edition is at http://www.microsoft.com/visualstudio/eng/downloads#d-2012-express ).
  • Now run Visual Studio and then click on the "Project" button at the top and select the VidRecord\build directory and click on the project solution file.
  • Click the "Compile" button
  • Answer yes to popup to build additonal projects, ie, build-all and install
  • Note that OpenCV 2.4.2 is compatible with the VS 2010 compiler. If you are using the 2012 edition of VS, answer to "No" to dialog asking to convert project to 2012 (unless you like seeing lots of error messages)

VidRecord C++ source notes

The required includes for OpenCV are just "core" and "highgui".

#include < opencv2/core/core.hpp >
#include < opencv2/highgui/highgui.hpp >

Remainder of the includes are just standard cpp libraries for iostream, some string manipulations and time routines.

Included is simplistic class called "Config.cpp" for retrieving configuration parameters from the command line arguments or from a configuration file called (no surprise) ".vidrecordrc". It has a number overloaded function "getters" for retrieving various parameter types, int, double, bool, and string.

/**
  * Get configuration value for a parameter
  * @param name Name of the parameter
  * @param default Default value for the parameter if not set
  * @return the parameter's value as an integer
  */
int Config::getVal(string name, int defaultVal) {
	int retVal = defaultVal;

	if (vals.count(name) > 0) {
		istringstream iss(vals[name]);
		iss >> retVal;
	}

	return retVal;
}

We use get parameters previously set from command line arguments or previously loaded from a config file. For example, the configuration parameters for image writing are retrieved as follows:

    imgDir = config.getVal("imgdir", imgDir);
    imgFmt = config.getVal("imgfmt", imgFmt);
    imgInterval = config.getVal("imgint", imgInterval);
    imgNum = config.getVal("imgnum", imgNum);

We open the video device connected to our allsky camera as follows:

    // Open video device, set video frame width and height as driver often does not
    VideoCapture cap = VideoCapture(vidDevice);

    if (cap.isOpened()) {
        cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
        cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    } else {
    	cerr << "Error: Could not open video device "<< vidDevice << endl;
        return 1;   
    } 

Frames from the video device are moved to our image frame

    // Frame capture loop
    while(isEnabled) {
        cap >> frame;
        ....

We then write the frame to the video file, calculate the time interval passed and based on whether or not to create a new file:

        if (isRecordingEnabled) {
            writer.write(frame);
            vidDelta = sec - vidTime;
            cout << "vidDelta "<= "<= vidInterval) {
                isRecording = false;
                vidTotal = vidTotal + 1;
                ....
        if ((isRecordingEnabled) && (!isRecording)) {
            int width = (int)cap.get(CV_CAP_PROP_FRAME_WIDTH);
            int height = (int)cap.get(CV_CAP_PROP_FRAME_HEIGHT);
            writer = createVideoFile(vidDir, width, height, vidFps, fourcc, sec);
            vidTime = sec;
            isRecording = true;
            frameNum = 0;
        }

The "createVideoFile function creates a new VideoWriter object that starts writing passing it a file name with current time stamp.

VideoWriter createVideoFile(String vidDir, int width, int height, int fps, int fourcc, time_t sec) {

    string timeStr = currentTimeString(&sec);
    string fileName = vidDir + timeStr + ".avi";
	cout << "Video file name = " << fileName << endl;
	Size frameSize = Size(width, height);
    VideoWriter vidWriter = VideoWriter(fileName, fourcc, fps,
        frameSize);
	return vidWriter;
}

The "currentTimeString" function uses the current time in seconds and uses the gmtime function to return the current time.

string currentTimeString(time_t *sec) {
    struct tm *ptm = gmtime (sec);
    ostringstream ostr;
    ostr<tm_year + 1900)<< "-" << setw(2)<< (ptm->tm_mon+1)
            << "-" << setw(2)<tm_mday << "T"<tm_hour
            << "h" <tm_min << "m" << setw(2) << ptm->tm_sec;
    return ostr.str();
}

The writeImageFile uses the cuirrentTimeString as well to create new png, jpg, tiff, etc image files at periodic intervals. Logic as to when to write them is very similar to how its done for video. See source code referenced above for details.

VidRecord example in Python

You may download the source code for this example. Software is released under terms of the Open Source Initiative BSD 2 - Clause license. Copy of the license for this software is at http://www.raben.com/sites/default/files/allsky/software/license.txt .

Required imports are:

import argparse
import os
import time
from cv2 import *

You need to define the following properties to record video as they seem to be
missing in the OpenCV 2.4.2 python module.

CV_CAP_PROP_FRAME_WIDTH = 3
CV_CAP_PROP_FRAME_HEIGHT = 4

Also the CV_FOURCC function is not defined in the OpenCV 2.4.2 python module.

def CV_FOURCC(c1, c2, c3, c4) :
    return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24)

Here is a function to create a video file named with the time stamp of when its created

def createVideoFile(path, width, height, fps ,fourcc,tsec):
    filename = time.strftime("%Y-%m-%dT%Hh%Mm%Ss", time.gmtime(tsec))
    pathname = os.path.join(path,filename) + ".avi"
    print "Create video file "+pathname
    writer = VideoWriter(pathname, fourcc, fps,(width,height))
    return writer;

And a function to write an image file

def writeImageFile(path, tsec, frame):
    filename = time.strftime("%Y-%m-%dT%Hh%Mm%Ss", time.gmtime(tsec))
    pathname = os.path.join(path,filename) + "." + imageFmt
    print "Create image file "+pathname
    imwrite(pathname, frame)

To get started we set the default video and image directories to store videos and images. These may be overridden by command line arguments.

videoDir = os.path.join(os.getenv("HOME","."),"Videos")
imageDir = os.path.join(os.getenv("HOME","."),"Pictures")

We can use Python's nifty ArgumentParser class to set up defaults and parse the command line.

parser = argparse.ArgumentParser()
parser.add_argument("-dis","--dis", help="Display video frame (set DIS to True or False)",default=True)
parser.add_argument("-viddir","--viddir",help="Set directory to save videos", default=videoDir)
parser.add_argument("-viddev","--viddev",help="Select video device number (usually 0 or 1, defailt is 0)",type=int,default = 0) 
parser.add_argument("-vidint","--vidint",help="recording interval in sec (default=0)",type=int,default=60)
parser.add_argument("-vidnum","--vidnum",help="number of videos to record default is 1",type=int,default=0)
parser.add_argument("-codec","--codec",help="Set recording codec MJPG,PIM1,MP42,U263,I263,FLV1 default is DIVX (mpeg4)",default="DIVX")
parser.add_argument("-vidfps", "--vidfps", help="Set recording fps", type=int, default=30)
parser.add_argument("-imgfmt","--imgfmt",help="Set video image format [jpg, png, tiff]",default="jpg")
parser.add_argument("-imgint","--imgint",help="Set interval between images (sec)", type=int,default=60)
parser.add_argument("-imgdir", "--imgdir", help="Set directory to save images",default=imageDir)
parser.add_argument("-imgnum", "--imgnum", help="Number of images to take", type=int, default=0)
args = parser.parse_args()

The argument values can be accessed through the "args" variable returned by the parser, for example args.dis, args.vidfps, etc. We use these to initialize some variables.

Now calculate the fourcc value from codec specified.; by default the codec is "DIVX"

codecArr = list(args.codec)
fourcc = CV_FOURCC(ord(codecArr[0]),ord(codecArr[1]),ord(codecArr[2]),ord(codecArr[3]))

Then open the video device to which the camera is connected. Its necessary to set width and height as some device drivers default to a only a frame which is only a few pixels in width and height.

cap = VideoCapture(videoDevice)
if cap.isOpened():
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 640)
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480)
else:
    exit    

A video frame is transferred to a image matrix by simply:

cap >> frame;

Frames are transferred from the VideoCapture class to an image matrix called "frame" on each pass through the loop.

To control everything the current time in seconds since 1970 is obtained by the following call.

sec = time.time()

The createVideoFile or writeImageFile functions are called at the proper intervals by checking the difference between current time and last time the file was written. Here is some of the code inside the loop for calling the writeImageFile function.

    if isImageEnabled:
        imageDelta = sec - imageTime
        
        if (imageDelta >= imageInterval):
            writeImageFile(imageDir, sec, frame)
            imageTime = sec
            imageTotal = imageTotal + 1
            if (imageTotal >= imageNum):
                isImageEnabled = False

The code for creating the image file is similar. See source code file referenced above for more details.