jyothyprakash90 commited on
Commit
ca315bd
·
verified ·
1 Parent(s): a99d591

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -21
app.py CHANGED
@@ -3,41 +3,106 @@ import numpy as np
3
  import gradio as gr
4
  import os
5
  import subprocess
 
6
  from pathlib import Path
7
 
8
- # ... [Keep apply_anime_filter and get_brush_mask from previous response] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  def generate_video(img_path, anime_variant, brush_texture, duration):
11
  try:
12
- # 1. Load and prepare image
13
  img = cv2.imread(img_path)
14
- if img is None: return "Error: Could not read image."
 
15
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
16
  h, w = 1080, 1920
17
- img = cv2.resize(img, (w, h))
18
  target_img = apply_anime_filter(img, anime_variant)
19
 
20
- # 2. Setup Video Writer
21
- video_name = Path(img_path).stem
22
- temp_raw = f"raw_{video_name}.mp4"
23
- final_mp4 = f"final_{video_name}.mp4"
24
 
25
- # Using 'mp4v' for maximum compatibility
26
- video = cv2.VideoWriter(temp_raw, cv2.VideoWriter_fourcc(*'mp4v'), 30, (w, h))
 
27
 
28
- # 3. Processing Loop (simplified for speed)
29
- for i in range(int(duration * 30)):
30
- # ... [Reveal logic here] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  video.write(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
32
  video.release()
33
 
34
- # 4. Final Encode (The part that usually causes the 'Error')
35
- try:
36
- subprocess.run(['ffmpeg', '-y', '-i', temp_raw, '-vcodec', 'libx264', '-pix_fmt', 'yuv420p', final_mp4], check=True)
37
- return final_mp4
38
- except:
39
- # Fallback if FFmpeg is missing: return the raw file
40
- return temp_raw
41
 
42
  except Exception as e:
43
- return f"Developer Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import gradio as gr
4
  import os
5
  import subprocess
6
+ import time
7
  from pathlib import Path
8
 
9
+ def apply_anime_filter(img, variant):
10
+ try:
11
+ # Base smoothing using bilateral filter
12
+ bilateral = cv2.bilateralFilter(img, 9, 75, 75)
13
+ if variant == "Vivid Modern":
14
+ return cv2.convertScaleAbs(bilateral, alpha=1.3, beta=10)
15
+ elif variant == "90s Retro":
16
+ retro = cv2.convertScaleAbs(bilateral, alpha=0.9, beta=5)
17
+ glow = cv2.GaussianBlur(retro, (15, 15), 0)
18
+ return cv2.addWeighted(retro, 0.7, glow, 0.3, 0)
19
+ elif variant == "Soft Ghibli":
20
+ # Requires opencv-contrib-python for detailEnhance
21
+ detail = cv2.detailEnhance(bilateral, sigma_s=10, sigma_r=0.15)
22
+ return cv2.convertScaleAbs(detail, alpha=1.1, beta=15)
23
+ return bilateral
24
+ except Exception as e:
25
+ print(f"Filter Error: {e}")
26
+ return img
27
+
28
+ def get_brush_mask(length, brush_type):
29
+ if brush_type == "Sharp Row": return np.zeros(length, dtype=np.int32)
30
+ elif brush_type == "Flat Brush": return np.random.randint(-5, 6, length)
31
+ elif brush_type == "Rough Bristle": return np.random.randint(-25, 26, length)
32
+ elif brush_type == "Fan Brush":
33
+ x = np.linspace(0, 4 * np.pi, length)
34
+ return (np.sin(x) * 20).astype(np.int32)
35
+ return np.zeros(length, dtype=np.int32)
36
 
37
  def generate_video(img_path, anime_variant, brush_texture, duration):
38
  try:
 
39
  img = cv2.imread(img_path)
40
+ if img is None: return None
41
+
42
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
43
  h, w = 1080, 1920
44
+ img = cv2.resize(img, (w, h), interpolation=cv2.INTER_LANCZOS4)
45
  target_img = apply_anime_filter(img, anime_variant)
46
 
47
+ fps = 30
48
+ total_frames = int(duration * fps)
49
+ video_name = f"{Path(img_path).stem}_{int(time.time())}"
 
50
 
51
+ # Use absolute paths for Hugging Face containers
52
+ temp_raw = f"/tmp/raw_{video_name}.mp4"
53
+ final_output = f"/tmp/{video_name}_anime.mp4"
54
 
55
+ video = cv2.VideoWriter(temp_raw, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
56
+ brush_offsets = get_brush_mask(w, brush_texture)
57
+
58
+ for i in range(total_frames):
59
+ progress = i / total_frames
60
+ zoom = 1 + (0.04 * progress)
61
+ M = cv2.getRotationMatrix2D((w/2, h/2), 0, zoom)
62
+ animated_target = cv2.warpAffine(target_img, M, (w, h))
63
+
64
+ frame = np.ones((h, w, 3), dtype=np.uint8) * 255
65
+ base_h = int(progress * h)
66
+
67
+ for x in range(w):
68
+ reveal_h = max(0, min(h, base_h + brush_offsets[x]))
69
+ if reveal_h > 0:
70
+ frame[0:reveal_h, x] = animated_target[0:reveal_h, x]
71
+
72
  video.write(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
73
  video.release()
74
 
75
+ # Final FFmpeg Encode (Critical step for HF Spaces)
76
+ subprocess.run(['ffmpeg', '-y', '-i', temp_raw, '-vcodec', 'libx264', '-crf', '18', '-pix_fmt', 'yuv420p', final_output], check=True)
77
+
78
+ if os.path.exists(temp_raw): os.remove(temp_raw)
79
+ return final_output
 
 
80
 
81
  except Exception as e:
82
+ print(f"Detailed Error: {e}")
83
+ return None
84
+
85
+ def batch_process(files, anime_variant, brush, duration):
86
+ if not files: return [], None
87
+ results = []
88
+ for f in files:
89
+ res = generate_video(f.name, anime_variant, brush, duration)
90
+ if res: results.append(res)
91
+ return results, (results[0] if results else None)
92
+
93
+ with gr.Blocks() as demo:
94
+ gr.Markdown("# 🎌 Vertical Anime SpeedPaint Master")
95
+ with gr.Row():
96
+ with gr.Column():
97
+ file_input = gr.File(file_count="multiple", label="Upload Multiple Images")
98
+ variant_opt = gr.Dropdown(["Vivid Modern", "90s Retro", "Soft Ghibli"], value="Vivid Modern", label="Anime Variant")
99
+ brush_opt = gr.Dropdown(["Sharp Row", "Flat Brush", "Rough Bristle", "Fan Brush"], value="Rough Bristle", label="Brush Texture")
100
+ dur_slider = gr.Slider(2, 10, value=5, step=1, label="Duration (Seconds)")
101
+ run_btn = gr.Button("🚀 Generate Batch")
102
+ with gr.Column():
103
+ video_preview = gr.Video(label="Preview")
104
+ file_download = gr.File(label="Download Files")
105
+
106
+ run_btn.click(fn=batch_process, inputs=[file_input, variant_opt, brush_opt, dur_slider], outputs=[file_download, video_preview])
107
+
108
+ demo.launch()