Skip to content

Instantly share code, notes, and snippets.

@pengowray
Created December 27, 2023 02:43
Show Gist options
  • Save pengowray/7e743994dab3c8327902e98a87f3e19b to your computer and use it in GitHub Desktop.
Save pengowray/7e743994dab3c8327902e98a87f3e19b to your computer and use it in GitHub Desktop.
add morse audio to a video of a flashing light
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.io.wavfile import write
from moviepy.editor import VideoFileClip, AudioFileClip
import os
## add morse audio to a video of a flashing light
video_path = 'data/yaoxz7sqop8c1.mp4'
video_capture = cv2.VideoCapture(video_path)
output_video_path = 'data/yaoxz7sqop8c1_output.mp4'
#output_video_path = 'data/video_with_modulated_audio.mp4'
temp_audio_path = 'data/temp_audio.wav'
def apply_gamma_correction(image, gamma=0.5):
""" Apply gamma correction to an image. """
inv_gamma = 1.0 / gamma
table = np.array([((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]).astype("uint8")
return cv2.LUT(image, table)
# Function to generate modulated tone in smaller segments
def generate_modulated_tone(frequency, duration, sampling_rate, brightness_values):
segment_duration = 1 # Duration of each segment in seconds
num_segments = int(np.ceil(duration / segment_duration))
modulated_tone = np.array([])
for segment in range(num_segments):
# Time array for the current segment
start_time = segment * segment_duration
end_time = min((segment + 1) * segment_duration, duration)
segment_time = np.linspace(start_time, end_time, int((end_time - start_time) * sampling_rate), endpoint=False)
# Generate tone for the current segment
tone_segment = np.sin(2 * np.pi * frequency * segment_time)
# Resample brightness values for the current segment
segment_brightness = np.interp(segment_time, np.linspace(0, duration, num=len(brightness_values), endpoint=False), brightness_values)
# Modulate the tone segment based on brightness
modulated_segment = tone_segment * segment_brightness
# Append to the full modulated tone
modulated_tone = np.concatenate((modulated_tone, modulated_segment))
return modulated_tone
video = VideoFileClip(video_path)
video_capture = cv2.VideoCapture(video_path)
# Check if the video was opened successfully
if not video_capture.isOpened():
raise Exception("Error opening video file")
# Get the frame rate of the video
frame_rate = video_capture.get(cv2.CAP_PROP_FPS)
# Duration of the video in seconds
video_duration = video.duration
# Frequency of the tone (in Hz)
tone_frequency = 500
# Sampling rate for the audio signal
sampling_rate = 44100
# Generate time array
t = np.linspace(0, video_duration, int(video_duration * sampling_rate), endpoint=False)
# Generate a 500 Hz tone
tone = np.sin(2 * np.pi * tone_frequency * t)
# Initialize a list to store original brightness values
brightness_values = []
# Process the video frame by frame to calculate brightness
while True:
ret, frame = video_capture.read()
if not ret:
break
# Apply gamma correction
gamma_corrected_frame = apply_gamma_correction(frame, gamma=0.5)
frame = gamma_corrected_frame
# Convert the frame to grayscale
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Calculate the average brightness
average_brightness = np.mean(gray_frame)
brightness_values.append(average_brightness)
# Release the video capture object
video_capture.release()
# Set the figure width to accommodate one pixel per bar
num_frames = len(brightness_values)
fig_width = num_frames / plt.rcParams['figure.dpi']
# Normalize brightness values to a range of 0 to 1
min_brightness = min(brightness_values)
max_brightness = max(brightness_values)
normalized_brightness = (np.array(brightness_values) - min_brightness) / (max_brightness - min_brightness)
# Now, let's try generating the modulated tone again
modulated_tone = generate_modulated_tone(tone_frequency, video_duration, sampling_rate, normalized_brightness)
# Convert the audio signal to 16-bit format
modulated_tone = np.int16(modulated_tone / np.max(np.abs(modulated_tone)) * 32767)
# Save the audio signal
write(temp_audio_path, sampling_rate, modulated_tone)
# Combine the audio with the video
audio_clip = AudioFileClip(temp_audio_path)
video_with_audio = video.set_audio(audio_clip)
# Save the video with the modulated audio
video_with_audio.write_videofile(output_video_path, codec="libx264", audio_codec="aac")
# Clean up the temporary audio file
#os.remove(temp_audio_path)
# Return the path of the new video file
output_video_path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment