Skip to content

Raspberry Pi 4B Camera Module: Build a time-lapse | ShillehTek

September 08, 2024

Video Tutorial (Optional)

Watch first if you want to see the full Raspberry Pi time-lapse workflow (capture, preview, and exporting) in real time.

Project Overview

Raspberry Pi 4B + Raspberry Pi Camera Module: In this project, you set up a Raspberry Pi Camera Module on a Raspberry Pi 4B, capture frames automatically with Python (Picamera2 + OpenCV), and stitch them into a time-lapse video with ffmpeg.

For today’s example, the capture is a simple time-lapse of a city skyline, just to show the end-to-end process.

Raspberry Pi camera time-lapse capture example showing repeated frames forming a skyline time-lapse
  • Time: 30 to 60 minutes setup, plus capture time (example shown is long running)
  • Skill level: Beginner to Intermediate
  • What you will build: A Python-based time-lapse capture pipeline that exports an MP4 from captured JPEG frames

Parts List

From ShillehTek

External

  • Raspberry Pi Model 4B - the computer running Python, Picamera2, and ffmpeg
  • Raspberry Pi power supply - stable power for long captures
  • MicroSD card - Raspberry Pi OS storage
  • Raspberry Pi Camera Module V2–8 - the camera used for capturing frames
  • Raspberry Pi camera holder (optional) - helps mount the camera
  • Tripod and/or tape (optional) - keep the camera stationary and angled correctly

Note: This guide uses picamera2 (the modern Raspberry Pi camera stack), plus OpenCV for overlays and image writing, and ffmpeg to create the final MP4.

Step-by-Step Guide

Step 1 - Install the required packages

Goal: Install the system packages needed for Picamera2, OpenCV, Flask (optional preview), and ffmpeg.

What to do: Open a terminal on your Raspberry Pi and run:

Code:

sudo apt update
sudo apt install python3-opencv python3-flask python3-picamera2 ffmpeg

Expected result: The required packages install successfully, and you can import picamera2 and cv2 from Python.

Step 2 - Create the time-lapse capture script

Goal: Capture frames on an interval, overlay the current time, and save frames into a timestamped folder.

What to do: Create a Python file (for example, timelapse.py) with the following code. Make sure the camera is stationary during capture to ensure a smooth time-lapse.

Code:

import cv2
from datetime import datetime
import time
import os
from picamera2 import Picamera2

# Initialize the camera
camera = Picamera2()
camera.configure(camera.create_preview_configuration(main={"format": 'XRGB8888', "size": (1920, 1080)}))
camera.start()

# Timelapse settings
capture_interval = 10  # seconds between each frame
duration = 60 * 60 * 25  # duration of the timelapse capture in seconds (25 hours for this example)

# Create a new output directory with a timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_dir = f"timelapse_frames_{timestamp}"
os.makedirs(output_dir, exist_ok=True)

start_time = time.time()

while time.time() - start_time < duration:
    frame = camera.capture_array()

    # Get the current time in hour:minute format
    current_time = datetime.now().strftime("%H:%M")

    # Define the position and font for the time overlay
    position = (frame.shape[1] - 200, 50)  # Adjust the position (x, y)
    font = cv2.FONT_HERSHEY_SIMPLEX
    font_scale = 1
    color = (0, 0, 0)  # Black color
    thickness = 3

    # Overlay the time on the frame
    cv2.putText(frame, current_time, position, font, font_scale, color, thickness, cv2.LINE_AA)

    # Save frame to disk
    filename = f"{output_dir}/frame_{int(time.time())}.jpg"
    cv2.imwrite(filename, frame)

    # Wait for the next capture
    time.sleep(capture_interval)

camera.stop()

Expected result: After running the script, you get a folder named like timelapse_frames_YYYYMMDD_HHMMSS filled with .jpg frames.

Step 3 - (Optional) Preview and adjust the camera angle using a Flask stream

Goal: Preview the camera feed in a browser so you can confirm framing before committing to a long capture.

What to do: Create another Python file (for example, preview.py) with the following code and run it.

Code:

from flask import Flask, Response
from picamera2 import Picamera2
import cv2
from datetime import datetime

app = Flask(__name__)
camera = Picamera2()
camera.configure(camera.create_preview_configuration(main={"format": 'XRGB8888', "size": (1920, 1080)}))
camera.start()

def generate_frames():
    while True:
        frame = camera.capture_array()

        # Get the current time in hour:minute format
        current_time = datetime.now().strftime("%H:%M")

        # Define the position and font for the time overlay
        position = (frame.shape[1] - 200, 50)  # Adjust the position (x, y)
        font = cv2.FONT_HERSHEY_SIMPLEX
        font_scale = 1
        color = (255, 255, 255)  # White color
        thickness = 2

        # Overlay the time on the frame
        cv2.putText(frame, current_time, position, font, font_scale, color, thickness, cv2.LINE_AA)

        # Encode the frame as a JPEG image
        ret, buffer = cv2.imencode('.jpg', frame)
        frame = buffer.tobytes()

        # Yield the frame to the response stream
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

@app.route('/video_feed')
def video_feed():
    return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

What to do: If your Raspberry Pi is connected to your local WiFi, open this URL (replace with your Pi’s IP):

http://<Your Raspberry Pi IP>:5000/video_feed

What to do: To find your Raspberry Pi IP address, run:

ifconfig

Expected result: You see a live stream in Chrome, and you can adjust the camera angle before running the long time-lapse capture.

Raspberry Pi live camera preview shown in a web browser using Flask video_feed endpoint

What to do: Mount the camera securely. In this example, the camera was taped to the Raspberry Pi and angled with a tripod. There are more professional mounting options, but stability is what matters most.

Raspberry Pi 4B with camera module taped in place for a stable time-lapse setup
Raspberry Pi camera module positioned and angled for recording a long time-lapse

Step 4 - Stitch the frames into an MP4 with ffmpeg

Goal: Turn the captured JPEG frame sequence into a single time-lapse MP4.

What to do: After the capture finishes, you will have a directory filled with .jpg frames. Open a terminal, cd into that directory, and run:

Code:

ffmpeg -framerate 30 -pattern_type glob -i 'frame_*.jpg' -c:v libx264 -pix_fmt yuv420p timelapse.mp4

Expected result: A timelapse.mp4 file is created. Depending on the number of frames, this can take a while to run.

Step 5 - (Optional) Transfer the MP4 to your local computer with SCP

Goal: Copy the finished timelapse.mp4 from the Raspberry Pi to your computer over the network.

What to do: Make sure SSH is enabled on your Raspberry Pi. One way is to run:

sudo raspi-config

What to do: Then, from a terminal on your local computer, use scp to copy the file (update the username, host/IP, and path to match your setup):

scp mshilleh@raspberrypi:~/Desktop/timelapse_frames_20240903_040101/timelapse.mp4 ~/Desktop/

Expected result: The MP4 appears on your local computer (for example, on your Desktop) and is ready for editing or sharing.

Conclusion

You built a Raspberry Pi time-lapse workflow using a Raspberry Pi 4B and Raspberry Pi Camera Module, capturing frames with Python (Picamera2 + OpenCV) and exporting a finished MP4 using ffmpeg. With the optional Flask preview, you can lock in framing before you start a long capture.

Want the exact parts used in this build? Grab them from ShillehTek.com. If you want help customizing this project or building something for your product, check out our consulting: UpWork. You can also follow along on YouTube - Shilleh. or support the channel at Buy Me A Coffee to help us continue creating tutorials.