Spaces:
Running
Running
import os | |
import numpy as np | |
from PIL import Image | |
import ffmpeg | |
import argparse | |
def add_noise(image: np.ndarray, noise_level: float) -> np.ndarray: | |
""" | |
Add Gaussian noise to an image with increasing intensity. | |
Args: | |
image: Input image as numpy array (0-255) | |
noise_level: Amount of noise to add (0-1) | |
""" | |
# Convert to float for calculations | |
img_float = image.astype(float) | |
# Generate noise | |
noise = np.random.normal(0, 255 * noise_level, image.shape) | |
# Add noise to image | |
noisy_image = img_float + noise | |
# Clip values to valid range | |
noisy_image = np.clip(noisy_image, 0, 255) | |
return noisy_image.astype(np.uint8) | |
def create_noise_sequence(input_image_path: str, output_folder: str, num_frames: int = 201): | |
""" | |
Create a sequence of increasingly noisy images. | |
Args: | |
input_image_path: Path to the input image | |
output_folder: Folder to save the sequence | |
num_frames: Number of frames to generate | |
""" | |
# Create output folder if it doesn't exist | |
os.makedirs(output_folder, exist_ok=True) | |
# Load the image | |
image = Image.open(input_image_path) | |
image_array = np.array(image) | |
# Calculate noise levels | |
# First 5 frames are clean, then noise increases to 0.25 | |
noise_levels = np.zeros(num_frames) | |
if num_frames > 5: | |
noise_levels[5:] = np.linspace(0, 0.50, num_frames - 5) | |
# Generate and save frames | |
for i, noise_level in enumerate(noise_levels): | |
# First 5 frames are the original image | |
if i < 5: | |
noisy_image = image_array | |
else: | |
noisy_image = add_noise(image_array, noise_level) | |
# Save frame | |
output_path = os.path.join(output_folder, f"frame_{i:03d}.png") | |
Image.fromarray(noisy_image).save(output_path) | |
# Print progress | |
if (i + 1) % 20 == 0: | |
print(f"Generated {i + 1}/{num_frames} frames") | |
def create_video(image_folder: str, output_path: str, fps: int = 24): | |
""" | |
Create a video from a sequence of images using ffmpeg command line. | |
Args: | |
image_folder: Folder containing the image sequence | |
output_path: Path for the output video | |
fps: Frames per second for the video | |
""" | |
input_pattern = os.path.join(image_folder, 'frame_%03d.png') | |
# Construct ffmpeg command | |
cmd = [ | |
'ffmpeg', | |
'-y', # Overwrite output file if it exists | |
'-framerate', str(fps), | |
'-i', input_pattern, | |
'-c:v', 'libx264', | |
'-pix_fmt', 'yuv420p', | |
'-preset', 'medium', | |
'-crf', '23', | |
output_path | |
] | |
# Run ffmpeg command | |
import subprocess | |
try: | |
subprocess.run(cmd, check=True, capture_output=True) | |
except subprocess.CalledProcessError as e: | |
print(f"Error creating video: {e.stderr.decode()}") | |
raise | |
def main(): | |
parser = argparse.ArgumentParser(description="Generate a sequence of increasingly noisy images and create a video") | |
parser.add_argument("input_image", help="Path to input image") | |
parser.add_argument("--output_folder", default="noise_sequence", help="Output folder for image sequence") | |
parser.add_argument("--output_video", default="noise_sequence.mp4", help="Output video path") | |
parser.add_argument("--fps", type=int, default=24, help="Frames per second for the video") | |
parser.add_argument("--frames", type=int, default=201, help="Number of frames to generate") | |
args = parser.parse_args() | |
print("Generating noise sequence...") | |
create_noise_sequence(args.input_image, args.output_folder, args.frames) | |
print("Creating video...") | |
create_video(args.output_folder, args.output_video, args.fps) | |
print(f"Video saved to {args.output_video}") | |
if __name__ == "__main__": | |
main() |