Gradioを使用したローカル深度ビデオコンバーターを構築する
フリーのプロンプト百科事典 Wikiprompt より
Gradioを使用したローカル深度ビデオコンバーターを構築する GradioとDepth Anything V2を使用してローカルなDepthビデオ変換アプリケーションを作成するための詳細なプロンプト。クロスプラットフォームのアクセラレーションサポートと複数のカスタマイズオプションを備えています。
プロンプト内容保存
🌐
"""
Depth Video Converter - Local Depth Estimation Video Tool
Converts regular videos into grayscale depth videos using Depth Anything V2.
Supports Windows (CUDA) and macOS (Apple Silicon / CPU).
"""
import os
import sys
import tempfile
import subprocess
import shutil
import numpy as np
import cv2
import torch
import gradio as gr
from PIL import Image
from transformers import pipeline
from transformers import AutoModelForDepthEstimation, AutoProcessor
import ffmpeg
import json
import time
from pathlib import Path
# ============================================================
# Configuration & Constants
# ============================================================
MODEL_IDS = {
"v2-small": "depth-anything/Depth-Anything-V2-Small-hf",
"v2-base": "depth-anything/Depth-Anything-V2-Base-hf",
"v2-large": "depth-anything/Depth-Anything-V2-Large-hf",
}
SUPPORTED_INPUT_FORMATS = [".mp4", ".mov"]
SUPPORTED_OUTPUT_FORMATS = [".mp4"]
DEFAULT_OUTPUT_RESOLUTION = 720
DEFAULT_MODEL_SIZE = "v2-base"
DEFAULT_TEMPORAL_SMOOTHING = 0.5
DEFAULT_INVERT = False
DEFAULT_PRESERVE_AUDIO = True
# ============================================================
# Device Detection
# ============================================================
def detect_device():
"""Detect the best available device for inference."""
if torch.cuda.is_available():
return "cuda"
elif sys.platform == "darwin" and torch.backends.mps.is_available():
return "mps"
else:
return "cpu"
def get_device_name(device):
"""Return a human-readable device name."""
if device == "cuda":
return f"CUDA ({torch.cuda.get_device_name(0)})"
elif device == "mps":
return "Apple Silicon (MPS)"
else:
return "CPU"
# ============================================================
# Depth Estimation Model
# ============================================================
class DepthEstimator:
"""Wrapper for Depth Anything V2 model."""
def __init__(self, model_size="v2-base", device=None):
self.device = device or detect_device()
self.model_id = MODEL_IDS[model_size]
self.pipe = None
self.processor = None
self.model = None
self.load_model()
def load_model(self):
"""Load the depth estimation model."""
print(f"Loading Depth Anything V2 model ({self.model_id}) on {get_device_name(self.device)}...")
# Load processor and model
self.processor = AutoProcessor.from_pretrained(self.model_id)
self.model = AutoModelForDepthEstimation.from_pretrained(self.model_id)
# Move model to device
if self.device == "cuda":
self.model = self.model.to("cuda")
elif self.device == "mps":
self.model = self.model.to("mps")
self.model.eval()
print("Model loaded successfully.")
def estimate_depth(self, image):
"""
Estimate depth map for a single image.
Returns a grayscale numpy array (0-255).
"""
# Convert BGR to RGB
if len(image.shape) == 3 and image.shape[2] == 3:
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
else:
image_rgb = image
# Convert to PIL
pil_image = Image.fromarray(image_rgb)
# Process
inputs = self.processor(images=pil_image, return_tensors="pt")
# Move inputs to device
if self.device == "cuda":
inputs = {k: v.to("cuda") for k, v in inputs.items()}
elif self.device == "mps":
inputs = {k: v.to("mps") for k, v in inputs.items()}
# Inference
with torch.no_grad():
outputs = self.model(**inputs)
predicted_depth = outputs.predicted_depth
# Interpolate to original size
prediction = torch.nn.functional.interpolate(
predicted_depth.unsqueeze(1),
size=pil_image.size[::-1],
mode="bicubic",
align_corners=False,
)
# Convert to numpy and normalize
depth = prediction.squeeze().cpu().numpy()
# Normalize to 0-255
depth_min = depth.min()
depth_max = depth.max()
if depth_max - depth_min > 1e-6:
depth_normalized = (depth - depth_min) / (depth_max - depth_min)
else:
depth_normalized = np.zeros_like(depth)
depth_uint8 = (depth_normalized * 255).astype(np.uint8)
return depth_uint8
# ============================================================
# Video Processing
# ============================================================
class VideoProcessor:
"""Handles video frame extraction, processing, and reassembly."""
def __init__(self, depth_estimator, output_resolution=720,
temporal_smoothing=0.5, invert=False):
self.depth_estimator = depth_estimator
self.output_resolution = output_resolution
self.temporal_smoothing = temporal_smoothing
self.invert = invert
self.prev_depth = None
def process_frame(self, frame):
"""Process a single frame and return the depth map."""
# Estimate depth
depth = self.depth_estimator.estimate_depth(frame)
# Apply temporal smoothing
if self.prev_depth is not None and self.temporal_smoothing > 0:
alpha = self.temporal_smoothing
depth = (alpha * self.prev_depth + (1 - alpha) * depth).astype(np.uint8)
self.prev_depth = depth
# Invert if requested
if self.invert:
depth = 255 - depth
# Resize to output resolution
h, w = depth.shape
target_h = self.output_resolution
target_w = int(w * (target_h / h))
depth_resized = cv2.resize(depth, (target_w, target_h), interpolation=cv2.INTER_LINEAR)
# Convert to BGR for video writing
depth_bgr = cv2.cvtColor(depth_resized, cv2.COLOR_GRAY2BGR)
return depth_bgr
def process_video(self, input_path, output_path, preserve_audio=True):
"""Process an entire video file."""
# Open video
cap = cv2.VideoCapture(input_path)
if not cap.isOpened():
raise ValueError(f"Could not open video: {input_path}")
# Get video properties
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
# Calculate output dimensions
target_h = self.output_resolution
target_w = int(width * (target_h / height))
# Create video writer
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (target_w, target_h))
if not out.isOpened():
raise ValueError(f"Could not create output video: {output_path}")
print(f"Processing video: {total_frames} frames at {fps} FPS")
print(f"Output resolution: {target_w}x{target_h}")
# Process frames
frame_count = 0
start_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
break
# Process frame
depth_frame = self.process_frame(frame)
out.write(depth_frame)
frame_count += 1
# Progress update
if frame_count % 30 == 0 or frame_count == total_frames:
elapsed = time.time() - start_time
fps_processed = frame_count / elapsed if elapsed > 0 else 0
progress = frame_count / total_frames * 100 if total_frames > 0 else 0
print(f"Progress: {progress:.1f}% ({frame_count}/{total_frames}) - {fps_processed:.1f} FPS")
# Cleanup
cap.release()
out.release()
# Handle audio preservation
if preserve_audio:
self.preserve_audio(input_path, output_path)
print(f"Video processing complete: {output_path}")
return output_path
def preserve_audio(self, input_path, output_path):
"""Copy audio from input to output using ffmpeg."""
temp_output = output_path + ".temp.mp4"
try:
# Use ffmpeg to copy audio
cmd = [
"ffmpeg", "-y",
"-i", output_path,
"-i", input_path,
"-map", "0:v:0",
"-map", "1:a:0?",
"-c:v", "copy",
"-c:a", "aac",
"-shortest",
temp_output
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0 and os.path.exists(temp_output):
os.replace(temp_output, output_path)
print("Audio preserved successfully.")
else:
print("Warning: Could not preserve audio. Using video without audio.")
if os.path.exists(temp_output):
os.remove(temp_output)
except Exception as e:
print(f"Warning: Audio preservation failed: {e}")
if os.path.exists(temp_output):
os.remove(temp_output)
# ============================================================
# Main Processing Function
# ============================================================
def process_video_file(input_file, model_size, output_resolution,
temporal_smoothing, invert, preserve_audio):
"""
Main processing function called by Gradio.
"""
try:
# Validate input
if input_file is None:
return None, "Error: No input file provided."
input_path = input_file.name if hasattr(input_file, 'name') else str(input_file)
# Check file extension
ext = os.path.splitext(input_path)[1].lower()
if ext not in SUPPORTED_INPUT_FORMATS:
return None, f"Error: Unsupported format {ext}. Please use MP4 or MOV."
# Create output path
output_dir = tempfile.mkdtemp(prefix="depth_video_")
output_filename = f"depth_{os.path.splitext(os.path.basename(input_path))[0]}.mp4"
output_path = os.path.join(output_dir, output_filename)
# Initialize depth estimator
depth_estimator = DepthEstimator(model_size=model_size)
# Initialize video processor
processor = VideoProcessor(
depth_estimator=depth_estimator,
output_resolution=output_resolution,
temporal_smoothing=temporal_smoothing,
invert=invert
)
# Process video
result_path = processor.process_video(
input_path,
output_path,
preserve_audio=preserve_audio
)
return result_path, f"Success! Depth video created: {os.path.basename(result_path)}"
except Exception as e:
import traceback
traceback.print_exc()
return None, f"Error: {str(e)}"
# ============================================================
# Gradio Interface
# ============================================================
def create_interface():
"""Create the Gradio web interface."""
device = detect_device()
device_name = get_device_name(device)
with gr.Blocks(title="Depth Video Converter") as demo:
gr.Markdown("""
# 🎥 Depth Video Converter
Convert regular videos into grayscale depth videos using **Depth Anything V2**.
Upload an MP4 or MOV file, configure the settings, and generate a depth video.
""")
with gr.Row():
with gr.Column(scale=1):
# Input
input_video = gr.Video(
label="Input Video (MP4/MOV)",
sources=["upload"],
format="mp4"
)
# Settings
model_size = gr.Dropdown(
choices=list(MODEL_IDS.keys()),
value=DEFAULT_MODEL_SIZE,
label="Model Size",
info="Larger models are more accurate but slower"
)
output_resolution = gr.Slider(
minimum=240,
maximum=1080,
value=DEFAULT_OUTPUT_RESOLUTION,
step=60,
label="Output Resolution (height in pixels)"
)
temporal_smoothing = gr.Slider(
minimum=0.0,
maximum=1.0,
value=DEFAULT_TEMPORAL_SMOOTHING,
step=0.1,
label="Temporal Smoothing",
info="Higher values reduce flicker but may cause lag"
)
invert = gr.Checkbox(
value=DEFAULT_INVERT,
label="Invert Depth (white = far, black = near)"
)
preserve_audio = gr.Checkbox(
value=DEFAULT_PRESERVE_AUDIO,
label="Preserve Original Audio"
)
process_btn = gr.Button("🎬 Generate Depth Video", variant="primary")
with gr.Column(scale=1):
# Output
output_video = gr.Video(
label="Depth Video Output",
interactive=False
)
status = gr.Textbox(
label="Status",
interactive=False
)
# Device info
gr.Markdown(f"**Device:** {device_name}")
# Event handlers
process_btn.click(
fn=process_video_file,
inputs=[
input_video,
model_size,
output_resolution,
temporal_smoothing,
invert,
preserve_audio
],
outputs=[output_video, status]
)
return demo
# ============================================================
# Main Entry Point
# ============================================================
if __name__ == "__main__":
print("=" * 60)
print("Depth Video Converter")
print("=" * 60)
# Check ffmpeg availability
if shutil.which("ffmpeg") is None:
print("Warning: ffmpeg not found in PATH. Audio preservation will be disabled.")
# Detect device
device = detect_device()
print(f"Using device: {get_device_name(device)}")
# Create and launch interface
demo = create_interface()
demo.launch(
server_name="127.0.0.1",
server_port=7860,
share=False,
inbrowser=True
)
```
```text
# requirements.txt
# Core dependencies
torch>=2.0.0
torchvision>=0.15.0
transformers>=4.36.0
gradio>=4.0.0
opencv-python>=4.8.0
numpy>=1.24.0
Pillow>=10.0.0
# Video processing
ffmpeg-python>=0.2.0
# Optional: CUDA support on Windows
# Uncomment the following line if you have NVIDIA GPU:
# torch-cuda>=2.0.0
# Optional: Apple Silicon support on macOS
# Uncomment the following line if you have Apple Silicon:
# torch-mps>=2.0.0
```
```markdown
# Depth Video Converter
Convert regular videos into grayscale depth videos using **Depth Anything V2**.
This tool runs locally on your machine and provides a simple web interface.
## Features
- 🎥 **Video Input**: Supports MP4 and MOV formats
- 🤖 **Depth Estimation**: Uses Depth Anything V2 (Small, Base, Large models)
- 🚀 **Hardware Acceleration**:
- NVIDIA CUDA on Windows
- Apple Silicon (MPS) on macOS
- CPU fallback
- 🎛️ **Customizable Settings**:
- Model size selection
- Output resolution
- Black/white inversion
- Temporal smoothing to reduce flicker
- Audio preservation
- 📦 **Export**: Compatible MP4 output
## Installation
### Prerequisites
- Python 3.9 or higher
- [ffmpeg](https://ffmpeg.org/download.html) (for audio preservation)
### Windows
```bash
# 1. Create virtual environment
python -m venv venv
venv\Scripts\activate
# 2. Install PyTorch with CUDA support (if you have NVIDIA GPU)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118
# 3. Install other dependencies
pip install -r requirements.txt
# 4. Run the application
python depth_video_converter.py
```
### macOS (Apple Silicon)
```bash
# 1. Create virtual environment
python3 -m venv venv
source venv/bin/activate
# 2. Install PyTorch with MPS support
pip install torch torchvision
# 3. Install other dependencies
pip install -r requirements.txt
# 4. Run the application
python depth_video_converter.py
```
### macOS (Intel) / Linux
```bash
# 1. Create virtual environment
python3 -m venv venv
source venv/bin/activate
# 2. Install PyTorch (CPU version)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
# 3. Install other dependencies
pip install -r requirements.txt
# 4. Run the application
python depth_video_converter.py
```
## Usage
1. Run the application
2. Open your browser to `http://127.0.0.1:7860`
3. Upload an MP4 or MOV video
4. Configure settings:
- **Model Size**: Small (fast), Base (balanced), Large (accurate)
- **Output Resolution**: Height in pixels (240-1080)
- **Temporal Smoothing**: 0-1, higher reduces flicker
- **Invert Depth**: Swap black/white
- **Preserve Audio**: Keep original audio track
5. Click "Generate Depth Video"
6. Download the result
## How It Works
1. **Frame Extraction**: Video is read frame by frame using OpenCV
2. **Depth Estimation**: Each frame is processed by Depth Anything V2
3. **Post-processing**:
- Temporal smoothing reduces flicker between frames
- Resolution adjustment to match output settings
- Optional inversion
4. **Video Assembly**: Depth frames are written to a new MP4
5. **Audio Preservation**: Original audio is copied using ffmpeg
## Model Information
| Model | Size | Speed | Accuracy |
|-------|------|-------|----------|
| v2-small | ~25MB | Fast | Good |
| v2-base | ~90MB | Medium | Better |
| v2-large | ~300MB | Slow | Best |
## Troubleshooting
### CUDA not detected on Windows
- Ensure NVIDIA drivers are installed
- Install PyTorch with CUDA: `pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118`
### MPS not detected on macOS
- Ensure you have Apple Silicon (M1/M2/M3)
- Update macOS to latest version
- Install latest PyTorch
### ffmpeg not found
- Download from [ffmpeg.org](https://ffmpeg.org/download.html)
- Add to system PATH
- Audio preservation will be disabled if ffmpeg is not available
### Out of memory
- Use smaller model (v2-small)
- Reduce output resolution
- Process shorter videos
## License
This project uses:
- [Depth Anything V2](https://github.com/DepthAnything/Depth-Anything-V2) (Apache 2.0)
- [Gradio](https://gradio.app/) (Apache 2.0)
- [PyTorch](https://pytorch.org/) (BSD-style)
## Disclaimer
This tool is for educational and creative purposes. Depth estimation results may vary depending on video content and quality.
ログインして完全なプロンプトを表示
次で続行:
ログインすると、次に同意したことになります: 利用規約 と プライバシーポリシー
使い方
このプロンプトは coding 向けに設計されています。上の内容をコピーして、お好みの AI ツールに貼り付けてください。
最良の結果を得るには、プレースホルダー(角括弧や大文字で示された部分)を具体的な要件に置き換えてください。
ノート
0 件のコメント