Hello folks, in this tutorial I will create a video-inside-text effect using Python. The video will play in the background but it will be visible only through the overlaid text.
My method can be applied to multiple videos of any resolution and duration. Take a look at the final output.
Usually, people use tools like Adobe After Effects, Adobe Premiere Pro or Davinci Resolve to create this kind of effect. They are awesome software but you have to put in a lot of manual effort to get the job done.
Therefore, I am going to use Python to automate inserting a video in a text string. Once the initial setup is done, we can run the same Python script on a large number of videos in one shot.
Note – You can download the Python code and other needed files from this link.
Put image inside text
First, let me show you how to put an image inside a static text sequence. It will help you in understanding the technique.
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw, ImageFont
from moviepy.editor import VideoFileClip, CompositeVideoClip
# Load your image
image = Image.open("input_image.jpg")
image = image.convert("RGBA")
# display image
image
After loading the image I have converted it to an “RGBA” mode which means it will have Red, Green, Blue, and Alpha (transparency) channels.
Next, I will create a blank image of the same dimensions as the one above. On this image, I will put the text string and use this image as a layer that will be later overlaid on the input image.
# Choose a font and size for the text
font_path = "ChrustyRock-ORLA.ttf" # replace with the path to your font file
font_size = 100 # replace with your desired font size
font = ImageFont.truetype(font_path, font_size)
Here I have specified the path to a .ttf
font file and set a font size. Then I created a font object that will be used to draw text.
# Create a new blank image with a black background
text_image = Image.new("RGBA", image.size, (0, 0, 0, 255))
# Create drawing context
draw = ImageDraw.Draw(text_image)
# Define text and position
text = "Your Text" # replace with your text
_, _, text_width, text_height = draw.textbbox(xy = (0,0), text=text, font=font)
text_x = (text_image.width - text_width) / 2
text_y = (text_image.height - text_height) / 2
Now I can specify the text overlaid on the image and calculate how big it will be in pixels, given the specified font. We then use these dimensions to compute the position of where the text should be placed to be centered on the image.
# Add text to the new blank image
draw.text((text_x, text_y), text, font=font, fill=(255, 255, 255, 255))
# Display image
text_image
Using the drawing context, I added the text to text_image
with the calculated x and y positions in white color.
Now I will create a mask image to put the text on top of the input image. I will use a grayscale mask image with the same size as the original image. Then, the same text is drawn onto the mask in white (255).
This mask will define where the original image will show through – only where the text is.
# Create a mask using the text_image and apply it onto the original image
mask = Image.new("L", image.size, 0)
mask_draw = ImageDraw.Draw(mask)
mask_draw.text((text_x, text_y), text, font=font, fill=255)
# Composite the original image onto the text image using the created mask
result = Image.composite(image, text_image, mask)
result
If you can see carefully, the image appears through the text. We have to use the same technique and apply it to all the frames of the video and then combine the processed frames back together to create a video that will appear inside the text.
Add video inside text
I will use a stock video for this demo. You can find this video in my downloadable material. Feel free to change the font size as per your taste.
# Load the video
video_path = 'drone_footage.mp4'
video = VideoFileClip(video_path)
# Define a function that will be applied to each frame
def add_text_to_frame(frame):
font_size = 232
# convert frame (numpy array) to PIL image
pil_frame = Image.fromarray(frame)
# Load the custom font
font = ImageFont.truetype(font_path, font_size)
# Create drawing context
text_image = Image.new("RGBA", pil_frame.size, (0, 0, 0, 255))
# Create drawing context
draw = ImageDraw.Draw(text_image)
# Define text and position
text = "MAGIC" # replace with your text
_, _, text_width, text_height = draw.textbbox(xy = (0,0), text = text, font = font)
text_x = (text_image.width - text_width) / 2
text_y = (text_image.height - text_height) / 2
# Add text to the new blank image
draw.text((text_x, text_y), text, font=font, fill=(255, 255, 255, 255))
# Create a mask using the text_image and apply it onto the original image
mask = Image.new("L", pil_frame.size, 0)
mask_draw = ImageDraw.Draw(mask)
mask_draw.text((text_x, text_y), text, font=font, fill=255)
# Composite the original image onto the text image using the created mask
result = Image.composite(pil_frame, text_image, mask)
# Convert the result back to a frame
new_frame = np.array(result)[:,:,:3]
return new_frame
# Apply the function to each frame
modified_video = video.fl_image(add_text_to_frame)
# Write the result to a file
output_path = 'video_in_text.mp4'
modified_video.write_videofile(output_path, codec='libx264', audio_codec='aac')
We can make it even more interesting by moving the text as well in addition to the video playing in the background. For example, we can use the typewriter effect on our text or make the text scroll horizontally.