Posted by Armin on Thursday, August 11, 2016
Timelapse video of a house demolition with a time-stamp overlay
Sadly, our neighbors sold their house and it was recently demolished to make way for two new buildings. On the plus side, this gave me an opportunity to try out my Raspberry Pi camera and make a time lapse movie of the process. Specifically, I wanted to try a quick-and-easy way to add a time-stamp in the corner of the video to give an indication of the current time of the day.
Below is the resulting video, hosted on YouTube. Note the date and time stamp on the lower right. Python code for how the text overlay was created can be found further down.
How the video was created
Set up the Raspberry Pi
During the demolition process, I had the RasPi take one picture every minute. To do so, I set up a Cron job to run a customized call to the raspistill program. This script created a time-stamped file name for each image and saved it a folder I created in the home directory (/home/pi/timelapse). The file name follows the convention "YYYY-MM-DD_hhmm.jpg"
#!/bin/bash DATE=$(date +"%Y-%m-%d_%H%M") raspistill -hf -vf -o /home/pi/timelapse/$DATE.jpg
*/1 6-19 * * * /home/pi/bin/make_raspistill.sh
Use Python Imaging Library to place a time stamp on each image
The Python Imaging Library (PIL) makes it very easy to overlay text on images. (I'm using the PILLOW fork of PIL.) I wrote a quick script that first resizes and crops each image, and then places the date and time stamp in the corner. The script needs all images to be placed into a folder, and then it needs to be run from within that folder. The script also needs a subdirectory called "resized" in which it will place the processed images with the timestamp overlay. The vertical crop borders (180 px), as well as text size and placement, were found by trial and error.
# script to draw image date/time over the image itself from PIL import Image from PIL import ImageFont from PIL import ImageDraw import os font = ImageFont.truetype("/System/Library/Fonts/HelveticaNeue.dfont", 72) fontsmall = ImageFont.truetype("/System/Library/Fonts/HelveticaNeue.dfont", 32) fontcolor = (238,161,6) counter = 0 # Go through each file in current directory for i in os.listdir(os.getcwd()): if i.endswith(".jpg"): counter += 1 # For debugging: limit how many images are processed: # if counter>10: # break print("Image {0}: {1}".format(counter, i)) # Files are named like YYYY-MM-DD_hhmm.jpg # * Date is the first chunk before the underscore # * Time is always the first 4 characters after the "_" splitup = i.split("_") date = splitup[0] t = splitup[1][0:4] # Add colon to time tformatted = t[0:2] + ":" + t[2:4] # Open the image and resize it to HD format # 720p (1280×720 px) # 1080p (1920x1080 px) widthtarget = 1920 heighttarget = 1080 img = Image.open(i) downSampleRatio = float(widthtarget) / float(img.width) imgDownSampled = img.resize( (widthtarget,round(img.height*downSampleRatio) ), resample=Image.LANCZOS) imgDownSampled = imgDownSampled.crop((0,180,widthtarget, heighttarget+180)) # get a drawing context draw = ImageDraw.Draw(imgDownSampled) draw.text((imgDownSampled.width-220,imgDownSampled.height-150), date, fontcolor, font=fontsmall) draw.text((imgDownSampled.width-220,imgDownSampled.height-120), tformatted, fontcolor, font=font) filename = "resized/" + i[0:-4] + "-resized.jpg" imgDownSampled.save(filename)
Use FFMPEG to make the movie from the image sequence
My workflow for converting image sequences into a movie is as follows:
- Rename images so file names are numbered sequentially
- Run ffmpeg on the sequentially named images
ffmpeg won't accept the time-stamped image names as input. Luckily, there's an easy way to rename the files to end with a zero-padded numbered sequence. It uses a modified "rename" program that can be found here: http://www.volkerschatz.com/unix/uware/rename.html. (I called it "renum" on my system to keep it separate from the standard Linux/Mac "rename" shell command.) Here's an example:
Change "2016-08-09_0631-resized.jpg" into "image_0001.jpg", "2016-08-09_0632-resized.jpg" into "image_0002.jpg", etc. The "sprintf("image_%04d",${i})" part in the command below means that we'll get a file name that's zero-padded to four digits.
renum -n 's/(\d+)-(\d+)-(\d+)_(\d+)-resized/sprintf("image_%04d",${i})/e' *.jpg
The "-n" option above means you can test whether it works. The output will show whether the renaming works, i.e. whether your regular expression was correct. Change it to "-v" once you see it works.
Once we have our sequentially numbered images, we can call ffmpeg:
ffmpeg -framerate 30 -i image_%04d.jpg -c:v libx264 -r 30 -pix_fmt yuv420p output_filename.mp4
Comments
Kevin replied on Permalink
This is an awesome script!
This is an awesome script! thank you. I hope you don't mind if I have stolen it and modified it to fit my needs. I took out the resizing, and added an if statement to skip it if the file exists already. I am constantly rsyncing with my raspberry pi to test the timelapse, and this speeds up the process by not having to timestamp every file again after a few new ones are added. I've been in love with my raspi ever since I bought the camera module. Thanks for sharing!
Armin replied on Permalink
Perfect...
Jay replied on Permalink
More detail request
Hi,
Can you please share more detail on image renaming process, like which package to import in python file as I can see that rename command shared above by author is from Perl not from python.
Thank you in advance
Armin replied on Permalink
Rename script
I ran the rename script in bash after the Python script put timestamps on the individual images. So "rename" is not called from Python. It's from here: http://www.volkerschatz.com/unix/uware/rename.html
It should actually be fairly straightforward to incorporate the sequential naming (which was only needed because ffmpeg wanted it) into the python script itself, so you can skip the rename bash script step afterwards. You could just create a file name with a zero-padded number when saving each jpg file in the loop; e.g.
Wrybread replied on Permalink
Wanted to say thank you for
Wanted to say thank you for this code. I used it to add timestamps to this timelapse:
https://vimeo.com/316945847
And FYI I added the scripts I build to my github:
https://github.com/wrybread/Python-Security-Camera-Timelapser
Armin replied on Permalink
Cool!
Oli replied on Permalink
Modification
Thank you for this script. I modified it so that instead of using the date/time from the filename, it will extract datetime from the images' EXIF metadata instead - https://github.com/raspberryrippl3/timestamp-images-using-exif-data/blob...