Raspberry Pi Camera Module 3 Timelapse
Recently I’ve been playing with a Raspberry Pi Camera module 3. One thing I’ve been toying with is putting together timelapses to observe how my different plants grow.
There’s a lot of content out there for this use-case, like this project by Jeff Geerling, but there’s a lot of variation out there in terms of camera versions, compatibility libraries, legacy modes and Raspbian versions, which makes finding a working example tricky.
While searching about I found that the default provided “libcamera” library and apps, recommended for the Pi cam 3, have many abilities built in including the ability to create timelapses, making the process quite simple. Using the libcamera-still app & ffmepg, I put together a couple of bash scripts to easily capture timelapses.
Example Output
Here’s an example of an output of this process. Note that I would have played around with the framerates, and I’ve done some additional editing & cropped the video, to help reduce some heavy flicker (from artificial lights):
Capture Script
This script takes two position arguments, interval (in seconds) and total (rough) frame count.
So, saving this as capture.sh
I could call it like ./capture.sh 2 30
and it would capture
an image every 2 seconds for a minute (30 frames).
Images are saved to a <script_path>/captures/<capture_start_timestamp>/*.jpg
location.
They are saved as 1080p at 75% jpeg quality to ensure a reasonable filesize.
The --vflip
towards the bottom of the script is specific to my usage,
since I’ve seemed to mount my camera upside down relative
to how I capture. Just remove this flag if you haven’t made the same mistake.
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DATESTAMP=$(date +'%Y-%m-%d_%H-%M')
DIR="$SCRIPT_DIR/captures/$DATESTAMP"
# Check if the number of arguments is correct
if [ $# -ne 2 ]; then
echo "Usage: $0 <interval_secs> <frame_count>"
exit 1
fi
# Get the variables from input
INTERVAL=$1
FRAME_COUNT=$2
# Calculate the total time and interval in MS
INTERVAL_MS=$((INTERVAL * 1000))
TIME_MS=$((FRAME_COUNT * INTERVAL_MS))
# Create the output directory
mkdir -p "$DIR"
# Start the timelapse
libcamera-still --timelapse "$INTERVAL_MS" \
-t "$TIME_MS" \
--vflip \
--quality 75 \
--width 1920 --height 1080 \
-o "$DIR/frame_%05d.jpg"
Stitch Script
This script takes a directory of *.jpg
images, like those created from the
capture script above, and stitches them together into a output.mp4
in the same directory.
This requires ffmpeg
to be installed.
This stitches frames together for 60 input frames per second of video output.
Adjust the -framerate 60
as desired based upon your amount of input frames and the desired
length & smoothness of output.
#!/bin/bash
# Check if the directory argument is provided
if [ $# -eq 0 ]; then
echo "Please provide a directory as an argument."
exit 1
fi
# Ensure ffmpeg is installed
if ! command -v ffmpeg &>/dev/null; then
echo "ffmpeg is not installed. Please install ffmpeg first."
exit 1
fi
# Navigate to the directory
cd "$1" || exit 1
# Run ffmpeg to convert jpeg files to mp4
# If you want to different output framerate compared to input,
# add a `-filter:v fps=fps=60` argument and adjust as desired for output fps.
ffmpeg -framerate 60 -pattern_type glob -i '*.jpg' -c:v libx264 output.mp4
echo "Conversion complete. The output file 'output.mp4' is created in the $1 directory."
Startup Service
If you want to start the timelapse capture upon startup, you can do so via a SystemD
service by adding the below to a /etc/systemd/system/timelapse.service
file, then
run systemctl enable timelapse.service
.
[Unit]
Description=Timelapse
[Service]
ExecStart=/path/to/capture.sh 5 1200
Restart=on-failure
User=dan
[Install]
WantedBy=multi-user.target