Overlay Text On Raspberry Pi Video Stream & Save
Introduction
Hey guys! Are you looking for a way to overlay text on a video stream from your Raspberry Pi and save it to the file system? You've come to the right place! This article will guide you through the process, providing a comprehensive solution for embedding text into your video recordings. We'll be focusing on using a Raspberry Pi, specifically the Raspberry Pi Zero, and the Raspicam, but the principles can be applied to other similar setups as well. We'll cover everything from setting up your Raspberry Pi to the Python code needed to capture video, read sensor data, overlay it as text, and save the final product to your file system. Let's dive in!
Problem Statement: Embedding Text into Video Streams
The challenge we're addressing here is how to integrate real-time data, such as sensor readings, directly into a video recording. Imagine you have a Raspberry Pi connected to various sensors, like temperature, pressure, or even custom sensors connected via UART. You want to record a video stream from the Raspicam and, at the same time, display the sensor values as text overlaid on the video. This is super useful for a variety of applications, such as:
- Scientific experiments: Recording sensor data alongside visual observations.
- Surveillance systems: Adding timestamps or other relevant information to video footage.
- DIY projects: Creating informative videos with sensor data overlays.
- Data logging: Creating a visual data log for easy analysis. It's important to have clear and concise information available at a glance, and overlaying sensor data onto video can help with that. Having the data embedded directly into the video stream can make analysis and interpretation much simpler. Furthermore, this approach eliminates the need to synchronize separate data logs with video recordings, thus saving time and reducing the potential for errors.
This article focuses on achieving this by using Python, which is a powerful and versatile language for the Raspberry Pi. We will utilize libraries that allow us to interact with the Raspicam, read data from the UART interface (for sensor readings), and manipulate the video stream to add the text overlay. The final output will be a video file saved on the Raspberry Pi's file system, with the text information permanently embedded within the video frames.
Prerequisites: Setting Up Your Raspberry Pi
Before we start coding, let's ensure your Raspberry Pi is ready to go. Here's what you'll need:
- Raspberry Pi: A Raspberry Pi Zero (or any other Raspberry Pi model) will work.
- Raspicam: The official Raspberry Pi camera module.
- MicroSD card: For installing the operating system.
- Power supply: To power the Raspberry Pi.
- UART connection (optional): If you're using external sensors connected via UART.
Here's a step-by-step guide to setting up your Raspberry Pi:
-
Install the Operating System: Download the latest version of Raspberry Pi OS (formerly Raspbian) from the official Raspberry Pi website. Follow the instructions to flash the OS image onto your microSD card using a tool like Raspberry Pi Imager or Etcher.
-
Enable the Camera: Boot up your Raspberry Pi and open the Raspberry Pi Configuration tool (either through the GUI or using
sudo raspi-config
in the terminal). Navigate to the Interfaces tab and enable the camera interface. -
Enable UART (if needed): If you are using UART communication, you may need to enable it. You can do this in
raspi-config
under Interface Options. Be aware that enabling UART might disable the serial console, so you'll need to use SSH or a monitor to access the Pi. You might need to also disable the serial console to free up the UART for your sensors. This can be done by editing/boot/cmdline.txt
and removingconsole=serial0,115200
. -
Install Necessary Packages: We'll need a few Python libraries for this project. Open a terminal on your Raspberry Pi and install them using
pip
:sudo apt update
sudo apt install python3-pip
pip3 install picamera
pip3 install Pillow
pip3 install pyserial
(if you're using UART)
Explanation of packages:
picamera
: This library provides a Python interface for interacting with the Raspicam.Pillow
: Pillow is an image processing library that allows us to draw text onto the video frames.pyserial
: This library enables serial communication with external devices via the UART interface.
-
Connect Your Sensors (if using UART): Connect your sensors to the appropriate UART pins on the Raspberry Pi. You'll need to identify the TX (transmit) and RX (receive) pins, as well as the ground (GND) and power (VCC) pins. Refer to the documentation for your specific sensors and the Raspberry Pi's pinout diagram.
With these prerequisites out of the way, we can now focus on the core of the project: the Python code!
Python Code: Capturing Video and Overlaying Text
Now comes the fun part: writing the Python code! We'll break down the code into smaller, manageable chunks and explain each section in detail. Here's the overall structure of the script:
- Import Libraries: Import the necessary Python libraries.
- Initialize Camera and UART (if needed): Set up the Raspicam and the UART interface.
- Define Text Overlay Function: Create a function to draw text onto the video frames.
- Start Video Recording: Begin capturing video from the Raspicam.
- Read Sensor Data and Overlay Text: In a loop, read sensor data, overlay it on the current frame, and write the frame to the video file.
- Stop Recording and Cleanup: Stop the video recording and clean up resources.
Here's the Python code, with explanations:
import picamera
from PIL import Image, ImageDraw, ImageFont
import serial
import time
# 1. Import Libraries
# We import the necessary libraries: picamera for camera control,
# PIL (Pillow) for image manipulation, serial for UART communication,
# and time for pausing execution.
try:
# 2. Initialize Camera and UART (if needed)
# Set up the camera resolution and frame rate.
camera = picamera.PiCamera()
camera.resolution = (640, 480)
camera.framerate = 30
# Initialize UART (if using serial communication with sensors)
# Replace '/dev/ttyS0' with the correct serial port for your setup.
# The baud rate (9600) should match your sensor's configuration.
ser = None
try:
ser = serial.Serial('/dev/ttyS0', 9600)
except serial.SerialException:
print("Serial port not available. Continuing without serial data.")
# 3. Define Text Overlay Function
# This function takes the camera object, text to overlay, and
# position as input. It draws the text onto the video frame.
def overlay_text(camera, text, position=(10, 10), font_size=20):
# Create an image the same size as the camera preview.
img = Image.new('RGBA', camera.resolution, (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Load a font (you may need to adjust the path).
font_path = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf'
try:
font = ImageFont.truetype(font_path, font_size)
except IOError:
print(f"Font file not found: {font_path}. Using default font.")
font = ImageFont.load_default()
# Draw the text onto the image.
draw.text(position, text, font=font, fill='white')
# Add the image as an overlay to the camera preview.
overlay = camera.add_overlay(img.tobytes(), size=img.size, layer=3, alpha=128)
return overlay
# 4. Start Video Recording
# Define the output video file name.
output_file = 'video_with_overlay.h264'
camera.start_recording(output_file)
overlay = None # Initialize overlay variable
try:
# 5. Read Sensor Data and Overlay Text
# This loop continuously reads sensor data (if UART is used),
# formats the data as text, overlays it on the video frame,
# and waits for a short period.
start_time = time.time()
while time.time() - start_time < 10: # Record for 10 seconds
sensor_data = ""
if ser:
try:
# Read data from UART (replace with your sensor reading logic).
sensor_data = ser.readline().decode('utf-8').strip()
except Exception as e:
sensor_data = f"Error reading serial: {e}"
text = f"Time: {time.strftime('%H:%M:%S')} Sensor: {sensor_data}"
if overlay:
camera.remove_overlay(overlay) # Remove the old overlay
overlay = overlay_text(camera, text) # Create a new overlay
camera.wait_recording(0.1) # Wait a short time
finally:
# 6. Stop Recording and Cleanup
# This block ensures that the camera and UART resources are
# properly released, even if an error occurs.
camera.stop_recording()
if overlay:
camera.remove_overlay(overlay)
if ser:
ser.close()
print(f"Video saved to {output_file}")
except Exception as e:
print(f"An error occurred: {e}")
Code Breakdown
- Import Libraries:
- We import
picamera
to control the Raspicam. PIL
(Pillow) is used for image manipulation, specifically to draw text.serial
is used for UART communication with external sensors (if applicable).time
is used for time-related functions like pausing execution and getting the current time.
- We import
- Initialize Camera and UART:
- We create a
picamera.PiCamera()
object to represent the camera. camera.resolution = (640, 480)
sets the video resolution.camera.framerate = 30
sets the frame rate to 30 frames per second.- We attempt to initialize a serial connection using
serial.Serial('/dev/ttyS0', 9600)
. Replace/dev/ttyS0
with the correct serial port for your setup. The baud rate (9600 in this example) should match your sensor's configuration. We handle potentialserial.SerialException
errors in case the serial port is not available, allowing the script to continue without serial data if necessary.
- We create a
- Define Text Overlay Function (
overlay_text
):- This function takes the
camera
object, thetext
to overlay, theposition
of the text, and thefont_size
as input. - It creates a new
Image
object with the same dimensions as the camera preview, using an RGBA color mode (to support transparency). - It creates an
ImageDraw
object to draw on the image. - It loads a font using
ImageFont.truetype()
. You may need to adjust thefont_path
to the location of your desired font file. A try-except block is used to handleIOError
exceptions in case the font file is not found, falling back to the default font if necessary. - It draws the text onto the image using
draw.text()
, specifying the position, text, font, and color. - It adds the image as an overlay to the camera preview using
camera.add_overlay()
. This function takes the image data as bytes (img.tobytes()
), the size of the image, the layer number (3 in this case), and the alpha value (128 for semi-transparency). The overlay is added on top of the video stream. - The function returns the
overlay
object, which is needed to remove the overlay later.
- This function takes the
- Start Video Recording:
- We define the output video file name:
output_file = 'video_with_overlay.h264'
. You can change this to your desired file name and location. - We start the video recording using
camera.start_recording(output_file)
. This tells the camera to start capturing video and save it to the specified file. - We initialize an
overlay
variable toNone
to keep track of the overlay object.
- We define the output video file name:
- Read Sensor Data and Overlay Text (Main Loop):
- This is the core of the script, where we continuously read sensor data, format it as text, overlay it on the video frame, and wait for a short period.
- We use a
try...finally
block to ensure that the camera and UART resources are properly released, even if an error occurs within the loop. - We record video for a set duration (10 seconds in this example). A
start_time
variable is used to track the recording duration. - Inside the
while
loop:- We initialize
sensor_data
to an empty string. - If
ser
is notNone
(meaning UART was successfully initialized), we attempt to read data from the UART interface usingser.readline().decode('utf-8').strip()
. This reads a line of data from the serial port, decodes it as UTF-8, and removes leading/trailing whitespace. A try-except block is used to handle potential exceptions during serial communication, displaying an error message if necessary. - We construct the
text
string to be displayed on the video. This string includes the current time (usingtime.strftime('%H:%M:%S')
) and the sensor data. - We manage the video overlays:
- If an overlay already exists (
if overlay:
), we remove it usingcamera.remove_overlay(overlay)
. This is important to avoid stacking multiple overlays on top of each other. - We create a new overlay by calling the
overlay_text()
function with the camera object, the text to overlay, and the desired position. The returned overlay object is assigned to theoverlay
variable.
- If an overlay already exists (
- We pause execution for a short time using
camera.wait_recording(0.1)
(0.1 seconds). This allows the camera to process the frame and avoids overwhelming the system.
- We initialize
- Stop Recording and Cleanup:
- The
finally
block is executed regardless of whether an exception occurred in thetry
block. This is crucial for releasing resources. - We stop the video recording using
camera.stop_recording()
. This saves the recorded video to the output file. - We remove the overlay using
camera.remove_overlay(overlay)
if one exists. - We close the serial connection using
ser.close()
if it was opened. - We print a message indicating the location of the saved video file.
- The
- Error Handling:
- The outer
try...except
block catches any exceptions that might occur during the script's execution and prints an error message.
- The outer
Running the Code
- Save the code as a Python file (e.g.,
video_overlay.py
). - Open a terminal on your Raspberry Pi.
- Navigate to the directory where you saved the file.
- Run the script using
python3 video_overlay.py
.
Post-Processing: Converting the H.264 Video
The Raspberry Pi camera records video in the H.264 format, which may not be compatible with all video players. You can convert the video to a more widely supported format, such as MP4, using the MP4Box
tool.
-
Install
MP4Box
:sudo apt update sudo apt install gpac
-
Convert the video:
MP4Box -add video_with_overlay.h264 video_with_overlay.mp4
Replace
video_with_overlay.h264
with the name of your H.264 video file.
Troubleshooting
- No video output:
- Ensure the camera is properly connected and enabled in
raspi-config
. - Check the camera ribbon cable for any damage.
- Verify that the
picamera
library is installed correctly.
- Ensure the camera is properly connected and enabled in
- Text overlay not visible:
- Make sure the font path is correct.
- Adjust the text position and font size as needed.
- Check the alpha value of the overlay (a lower value makes the overlay more transparent).
- Serial communication issues:
- Double-check the serial port and baud rate settings.
- Ensure the sensor is properly connected to the UART pins.
- Verify that the sensor is sending data correctly.
- Errors during conversion:
- Make sure
MP4Box
is installed correctly. - Check the file names and paths.
- Make sure
Conclusion
Alright guys, you've made it to the end! We've covered how to overlay text on a video stream from your Raspberry Pi using the Raspicam and Python. This technique is super versatile and can be used in a wide range of applications, from scientific experiments to surveillance systems. By using the picamera
, Pillow
, and pyserial
libraries, we've created a robust solution for embedding real-time data into video recordings.
Remember, the key takeaways are:
- Setting up the Raspberry Pi: Ensure the camera and UART are enabled, and the necessary Python libraries are installed.
- The
overlay_text
function: This function is the heart of the text overlay process, creating an image with the text and adding it as an overlay to the camera preview. - The main loop: This loop reads sensor data (if applicable), formats it, and overlays it on the video frames.
- Error handling: Using
try...except
andtry...finally
blocks is crucial for ensuring that resources are properly released and errors are handled gracefully.
Now you can go ahead and adapt this code to your specific needs, such as using different sensors, displaying different data, or customizing the text appearance. Don't hesitate to experiment and explore the possibilities! Happy video recording and text overlaying!