Cloud-enabled Time-Lapse Video – Part II

In Cloud-enabled Time-Lapse Video Part I, I walked through setting up a Raspberry Pi with a camera and motion sensor to take time-lapse images at configurable intervals and upload them to Flickr.

But, once the images are on your Flickr site, what are you supposed to do? You need an easy way to get them back and turned into a time-lapse for whatever period of time you’re interested in. To do this, I’ve created a sample Python script that lets you grab a stack of images for an entire day and create an mp4 from that stack. In this post I’ll walk through that sample code.

In the previous post, I had you install the Python module called flickr_api, so you should be all set on that front. Otherwise, the only modules you need to run the code below are argparse (to parse command line arguments) and os to allow Python to make a system call to an executable (ffmpeg in this case, to make our mp4). These modules ship with Python, so there’s nothing else to install. Here is a sample script (broken down into a few chunks for sake of explanation) to grab a day’s worth of images:

#!/usr/bin/python
 
import argparse
import os
import flickr_api
 
parser = argparse.ArgumentParser(description='Integers representing month, day, year')
parser.add_argument('-d', '--date', metavar=('Year', 'Month', 'Day'), type=int, 
   nargs=3, help='Integers representing the year, month, and day')
parser.add_argument('-f', '--outfile', metavar=('filename'), type=str, 
   help='File name for your output mp4 file.')
 
args = parser.parse_args()
if not args.date:
    print 'You must specify a date in the form "-d yyyy mm hh"'
    quit()
 
in_year = args.date[0]
in_month = args.date[1]
in_day = args.date[2]
if not args.outfile:
    outfile = str(in_year) + str(in_month) + str(in_day) + '.mp4'
else:
    outfile = os.path.splitext(args.outfile)[0] + '.mp4'

The code above imports some necessary modules and sets up the machinery to parse command line arguments. If you don’t pass it the name of the file to write the video to, it will simply name it with the format yyyymmdd.mp4.

API_KEY='<your_api_key>'
API_SECRET='<your_api_secret>'
USER_ID = '<your user id>'
PHOTO_SET_ID = u'72157653976833825' 
 
flickr_api.set_keys(api_key = API_KEY, api_secret = API_SECRET)
a = flickr_api.auth.AuthHandler.load('<path to your local authentication token file>')
flickr_api.set_auth_handler(a)
user = flickr_api.Person.findByUserName("<your_screename>")

This snippet sets up everything you need to authenticate with your Flickr keys and authentication token. (Here’s a handy refresher if you’ve forgotten about this stuff.) The USER_ID string can be a little tricky since it’s not necessarily the same as your screen name. You can use idgettr to find out what your user id is using your screenname.

photosets = user.getPhotosets()
for p in photosets:
    if p.id == PHOTO_SET_ID:
        break
 
photos = p.getPhotos()
 
def parse_title(title):
    year = int(title[:4])
    month = int(title[4:6])
    day = int(title[6:8])
 
    return (year, month, day)
 
 
dirname = str(in_year) + str(in_month).zfill(2) + str(in_day)
idx = 1
while photos.info.page <= photos.info.pages:
    if not os.path.exists(dirname):
        os.mkdir('./' + dirname)
 
    for photo in photos:
        (year, month, day) = parse_title(photo.title)
        if year == in_year and month == in_month and day == in_day:
            photo.save(os.path.join('./', dirname, str(idx).zfill(3) + '.jpg'),   
                       size_label='Original')
            idx += 1
    if photos.info.page == photos.info.pages:
        break
    else:
        photos = p.getPhotos(page=(photos.info.page + 1))
 
os.system('ffmpeg -f image2 -framerate 10 -i ' + 
   os.path.join(dirname, '%03d.jpg') + 
   ' -vf "crop=2592:1458,scale=1920:1080" -vcodec libx264 -pix_fmt yuv420p ' + 
   outfile)

This last snippet above loops through a user’s photo sets until it finds the one that matches the PHOTO_SET_ID variable. (If you wanted this code to be super versatile, you could also pass in the photo set id as an argument.) It loops through all the photos in a set and parses their titles (remember, we named the photos according to the scheme yyyymmddhhmm.jpg), grabbing only the photos for the day specified in the command line arguments. (This approach is actually pretty inefficient since it checks all photos in a set. In practice, we know that the photos were likely uploaded in chronological order, so once we encounter photos newer than the date we care about, we should probably stop.) It then creates a local directory for the day requested and saves all photos in that directory, numbering them sequentially (starting at 001.jpg). The final line makes a system call to a video utility called ffmpeg to create an mp4 video at 10 FPS from a stack of sequentially numbered images in the directory we just created.

And there you have it! This script is really just intended to be a quick and dirty example of how you can grab a set of images from Flickr and process them into a time lapse. There are lots of changes you could make to make it more useful, like specifying a time range other than 1 day. So, have at it.

Leave a Reply

Your email address will not be published.

Back to Top