inoculatemedia's picture
Update app.py from anycoder
95a2ebc verified
import gradio as gr
import numpy as np
import cv2
from typing import Tuple
import os
import tempfile
def apply_normal_map_depth(video_path: str, normal_map_path: str, depth_strength: float) -> str:
"""
Apply normal map depth effect to video
Args:
video_path: Path to input video file
normal_map_path: Path to normal map image
depth_strength: Strength of depth effect (0-1)
Returns:
Path to output video with depth effect
"""
# Load normal map
normal_map = cv2.imread(normal_map_path)
if normal_map is None:
raise gr.Error("Failed to load normal map image")
# Convert to grayscale and normalize
normal_map_gray = cv2.cvtColor(normal_map, cv2.COLOR_BGR2GRAY)
normal_map_gray = normal_map_gray.astype(np.float32) / 255.0
# Create output video path
output_path = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False).name
# Open video capture
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise gr.Error("Failed to open video file")
# Get video properties
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
# Create video writer
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
# Resize normal map to match video dimensions
normal_map_resized = cv2.resize(normal_map_gray, (width, height))
frame_count = 0
try:
while True:
ret, frame = cap.read()
if not ret:
break
# Apply depth effect based on normal map
if len(frame.shape) == 3 and frame.shape[2] == 3:
# Convert to float for processing
frame_float = frame.astype(np.float32) / 255.0
# Apply depth effect by adjusting brightness based on normal map
depth_effect = normal_map_resized * depth_strength * 0.5 # Scale down effect
frame_float = np.clip(frame_float + depth_effect[:, :, np.newaxis], 0, 1)
# Convert back to uint8
frame = (frame_float * 255).astype(np.uint8)
# Write frame to output
out.write(frame)
frame_count += 1
# Update progress
if frame_count % 10 == 0:
progress = frame_count / total_frames
print(f"Processing: {progress*100:.1f}%")
finally:
cap.release()
out.release()
return output_path
def process_video(video: gr.Video, normal_map: gr.Image, strength: float) -> gr.Video:
"""
Process video with normal map depth effect
Args:
video: Input video
normal_map: Normal map image
strength: Depth effect strength
Returns:
Processed video with depth effect
"""
try:
# Save uploaded files temporarily
video_path = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False).name
normal_map_path = tempfile.NamedTemporaryFile(suffix='.png', delete=False).name
# Save video
if isinstance(video, str):
video_path = video
else:
# For webcam input, we need to handle differently
if video.startswith('data:'):
# This is a base64 encoded video from webcam
# For demo purposes, we'll use a placeholder
return gr.Video(value="https://gradio-builds.s3.amazonaws.com/assets/video_sample.mp4")
# Save normal map
if isinstance(normal_map, np.ndarray):
cv2.imwrite(normal_map_path, cv2.cvtColor(normal_map, cv2.COLOR_RGB2BGR))
else:
# Handle file path
normal_map_path = normal_map
# Process video
output_path = apply_normal_map_depth(video_path, normal_map_path, strength)
return gr.Video(value=output_path, format="mp4")
except Exception as e:
raise gr.Error(f"Error processing video: {str(e)}")
finally:
# Clean up temporary files
if 'video_path' in locals() and os.path.exists(video_path) and video_path.startswith(tempfile.gettempdir()):
os.unlink(video_path)
if 'normal_map_path' in locals() and os.path.exists(normal_map_path) and normal_map_path.startswith(tempfile.gettempdir()):
os.unlink(normal_map_path)
# Create Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# Normal Map Depth Effect for Videos")
gr.Markdown("""
### Built with anycoder
[![Anycoder](https://huggingface.co/spaces/akhaliq/anycoder/resolve/main/logo.png)](https://huggingface.co/spaces/akhaliq/anycoder)
Apply depth effects to videos using normal maps. Upload a video and a normal map image to create 3D-like depth effects.
""")
with gr.Row():
with gr.Column():
gr.Markdown("## Input Video")
video_input = gr.Video(
label="Upload Video",
sources=["upload", "webcam"],
format="mp4",
height=300
)
gr.Markdown("## Normal Map")
normal_map_input = gr.Image(
label="Upload Normal Map",
type="numpy",
height=300,
tooltip="Upload a normal map image (grayscale or color)"
)
depth_strength = gr.Slider(
minimum=0.1,
maximum=2.0,
value=1.0,
step=0.1,
label="Depth Strength",
info="Control the intensity of the depth effect"
)
process_btn = gr.Button("Apply Depth Effect", variant="primary", size="lg")
with gr.Column():
gr.Markdown("## Output Video with Depth Effect")
video_output = gr.Video(
label="Processed Video",
format="mp4",
height=400,
autoplay=True
)
gr.Markdown("""
### How it works:
1. Upload a video file or use your webcam
2. Upload a normal map image (grayscale works best)
3. Adjust the depth strength slider
4. Click 'Apply Depth Effect' to process
5. View the result with enhanced depth
### Tips:
- Use high-contrast normal maps for best results
- Start with lower depth strength and increase gradually
- Normal maps should match the video resolution for optimal effect
""")
# Examples
gr.Markdown("## Examples")
examples = gr.Examples(
examples=[
[
"https://gradio-builds.s3.amazonaws.com/assets/video_sample.mp4",
"https://gradio-builds.s3.amazonaws.com/assets/normal_map_sample.png",
1.0
],
[
"https://gradio-builds.s3.amazonaws.com/assets/video_sample.mp4",
"https://gradio-builds.s3.amazonaws.com/assets/normal_map_sample2.png",
0.7
]
],
inputs=[video_input, normal_map_input, depth_strength],
outputs=[video_output],
fn=process_video,
cache_examples=True,
examples_per_page=2,
label="Try these examples:"
)
# Event listeners
process_btn.click(
fn=process_video,
inputs=[video_input, normal_map_input, depth_strength],
outputs=[video_output],
api_visibility="public",
api_name="apply_depth_effect"
)
# Add footer with anycoder link
gr.Markdown("""
---
### Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder) 🚀
""")
# Launch with modern theme
demo.launch(
theme=gr.themes.Soft(
primary_hue="blue",
secondary_hue="indigo",
neutral_hue="slate",
font=gr.themes.GoogleFont("Inter"),
text_size="lg",
spacing_size="lg",
radius_size="md"
).set(
button_primary_background_fill="*primary_600",
button_primary_background_fill_hover="*primary_700",
block_title_text_weight="600",
),
footer_links=[
{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"},
{"label": "Gradio Docs", "url": "https://www.gradio.app/docs"},
{"label": "GitHub", "url": "https://github.com/gradio-app/gradio"}
],
css="""
.gradio-container {
max-width: 1200px !important;
}
.gr-box {
border-radius: 12px !important;
}
""",
show_error=True,
share=True
)