Created
December 27, 2023 02:43
-
-
Save pengowray/7e743994dab3c8327902e98a87f3e19b to your computer and use it in GitHub Desktop.
add morse audio to a video of a flashing light
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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