dream2589632147 commited on
Commit
ff46f61
·
verified ·
1 Parent(s): 6381790

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -118
app.py CHANGED
@@ -1,74 +1,57 @@
1
- import spaces # <--- يجب أن يكون هذا هو السطر رقم 1 دائماً وأبداً
2
  import gradio as gr
3
- import torch
4
  import cv2
5
  import numpy as np
6
  from PIL import Image
7
- from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, LCMScheduler
8
- from controlnet_aux import CannyDetector
9
  import os
10
  import shutil
11
  import tempfile
12
  import datetime
13
- import ffmpeg
 
 
 
14
 
15
  # ==========================================
16
- # 1. إعدادات النموذج
17
  # ==========================================
18
- print("⏳ Loading Models...")
19
-
20
- # تحديد نوع البيانات (ملاحظة: مع ZeroGPU التحديد يتم لاحقاً، لكن نجهزه هنا)
21
- # ملاحظة: لا تستخدم .to('cuda') هنا خارج الدالة في ZeroGPU
22
- torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
23
 
 
 
24
  try:
25
- # تحميل ControlNet
26
- controlnet_model = ControlNetModel.from_pretrained(
27
- "lllyasviel/sd-controlnet-canny", torch_dtype=torch_dtype
28
- )
29
-
30
- # تحميل Stable Diffusion 1.5
31
- model_id = "runwayml/stable-diffusion-v1-5"
32
- pipe = StableDiffusionControlNetPipeline.from_pretrained(
33
- model_id, controlnet=controlnet_model, torch_dtype=torch_dtype
34
  )
35
-
36
- # تفعيل LCM للسرعة
37
- print("⚡ Injecting LCM-LoRA...")
38
- pipe.load_lora_weights("latent-consistency/lcm-lora-sdv1-5")
39
- pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
40
-
41
- print("✅ Models loaded into RAM (waiting for GPU allocation).")
42
-
43
  except Exception as e:
44
- print(f"❌ Error loading models: {e}")
45
- # لن نوقف البرنامج هنا، سنتركه يحاول العمل
46
- pass
47
-
48
- canny_processor = CannyDetector()
49
 
50
  # ==========================================
51
- # 2. دالة المعالجة (مع تفعيل ZeroGPU)
52
  # ==========================================
53
 
54
- @spaces.GPU(duration=120) # نمنح الدالة وقتاً كافياً (120 ثانية)
55
- def colorize_video_multistyle(video_file, prompt, style_choice, steps=5):
56
  if not video_file:
57
  return None
58
-
59
- # === نقل النموذج إلى GPU الآن فقط (داخل الدالة) ===
60
- print("🚀 Moving models to GPU...")
61
- pipe.to("cuda")
62
 
63
- # تحسينات الذاكرة
64
- pipe.enable_attention_slicing()
 
 
65
 
66
  timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
67
- output_temp_video_no_audio = os.path.join(tempfile.gettempdir(), f"temp_vis_{timestamp}.mp4")
68
- final_output_name = f"colored_lcm_{timestamp}.mp4"
69
 
70
- # --- استخراج الصوت ---
71
- audio_path = os.path.join(tempfile.gettempdir(), f"temp_audio_{timestamp}.aac")
 
 
72
  audio_exists = False
73
  try:
74
  (
@@ -81,111 +64,84 @@ def colorize_video_multistyle(video_file, prompt, style_choice, steps=5):
81
  except ffmpeg.Error:
82
  print("⚠️ Warning: No audio found or extraction failed.")
83
 
84
- # --- قراءة الفيديو ---
85
  cap = cv2.VideoCapture(video_file)
86
- if not cap.isOpened():
87
- return None
88
-
89
  fps = cap.get(cv2.CAP_PROP_FPS)
90
- width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
91
- height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
92
-
93
- # تجهيز البرومبت
94
- style_prompts = {
95
- "Auto Color": "photorealistic, 8k, masterpiece, cinematic lighting",
96
- "Vivid": "vibrant colors, high saturation, pop art style, colorful",
97
- "Vintage": "sepia, 1950s film look, grain, nostalgia",
98
- "Cyberpunk": "neon lights, cyberpunk, blue and pink hues, futuristic"
99
- }
100
 
101
- full_prompt = f"{prompt}, {style_prompts.get(style_choice, '')}, colorized video"
102
- negative_prompt = "black and white, monochrome, greyscale, low quality, blurry, distorted, nsfw, watermark"
103
-
104
- colored_frames = []
105
-
106
- print("🎬 Starting Frame Processing on ZeroGPU...")
107
 
108
  while True:
109
  ret, frame = cap.read()
110
  if not ret:
111
  break
112
 
113
- # تحويل من BGR إلى RGB
114
- pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
115
- canny_image = canny_processor(pil_image)
 
 
 
 
116
 
117
- # التوليد
118
- with torch.inference_mode():
119
- image_out = pipe(
120
- prompt=full_prompt,
121
- negative_prompt=negative_prompt,
122
- image=canny_image,
123
- num_inference_steps=steps,
124
- guidance_scale=1.5,
125
- controlnet_conditioning_scale=1.0
126
- ).images[0]
127
 
128
- colored_frames.append(np.array(image_out))
 
 
129
 
130
  cap.release()
 
131
 
132
- # --- تجميع الفيديو ---
133
- fourcc = cv2.VideoWriter_fourcc(*'mp4v')
134
- out = cv2.VideoWriter(output_temp_video_no_audio, fourcc, fps, (width, height))
135
 
136
- for frame in colored_frames:
137
- out.write(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
138
-
139
- out.release()
140
-
141
- # --- دمج الصوت ---
142
  if audio_exists:
143
- try:
144
- (
145
- ffmpeg
146
- .input(output_temp_video_no_audio)
147
- .output(ffmpeg.input(audio_path).audio, final_output_name, vcodec='copy', acodec='copy')
148
- .run(overwrite_output=True, quiet=True)
149
- )
150
- except ffmpeg.Error:
151
- shutil.copy(output_temp_video_no_audio, final_output_name)
152
  else:
153
- shutil.copy(output_temp_video_no_audio, final_output_name)
154
-
 
 
 
 
 
 
 
 
 
155
  if os.path.exists(audio_path): os.remove(audio_path)
156
 
157
  return final_output_name
158
 
159
  # ==========================================
160
- # 3. واجهة Gradio
161
  # ==========================================
162
  custom_css = """
163
  #col-container {max-width: 700px; margin-left: auto; margin-right: auto;}
164
  """
165
 
166
- with gr.Blocks(css=custom_css, title="Turbo Video Colorizer") as demo:
167
  with gr.Column(elem_id="col-container"):
168
- gr.Markdown("# Turbo Video Colorizer (LCM + ZeroGPU)")
169
- gr.Markdown("تلوين الفيديو بسرعة عالية باستخدام ZeroGPU و LCM-LoRA.")
170
 
171
  with gr.Row():
172
- video_input = gr.Video(label="رفع الفيديو")
173
-
174
- with gr.Row():
175
- prompt_input = gr.Textbox(label="وصف المشهد", placeholder="مثال: A sunny day in the park")
176
- style_dropdown = gr.Dropdown(
177
- ["Auto Color", "Vivid", "Vintage", "Cyberpunk"],
178
- label="النمط", value="Auto Color"
179
- )
180
-
181
- steps_slider = gr.Slider(minimum=4, maximum=10, step=1, value=5, label="الخطوات (5 recommended)")
182
 
183
- submit_btn = gr.Button("🎨 تلوين الفيديو", variant="primary")
184
- video_output = gr.Video(label="النتيجة")
185
 
186
  submit_btn.click(
187
- fn=colorize_video_multistyle,
188
- inputs=[video_input, prompt_input, style_dropdown, steps_slider],
189
  outputs=video_output
190
  )
191
 
 
1
+ import spaces # <--- يجب أن يبقى في السطر الأول
2
  import gradio as gr
 
3
  import cv2
4
  import numpy as np
5
  from PIL import Image
 
 
6
  import os
7
  import shutil
8
  import tempfile
9
  import datetime
10
+ import ffmpeg
11
+ # استيراد مكتبات ModelScope الخاصة بـ DDColor
12
+ from modelscope.pipelines import pipeline
13
+ from modelscope.utils.constant import Tasks
14
 
15
  # ==========================================
16
+ # 1. إعداد نموذج DDColor الاحترافي
17
  # ==========================================
18
+ print("⏳ Loading DDColor Professional Model...")
 
 
 
 
19
 
20
+ # تحميل خط الأنابيب (Pipeline) الخاص بالتلوين
21
+ # نحدد device='gpu' ليعمل مع ZeroGPU عند استدعائه
22
  try:
23
+ ddcolor_pipeline = pipeline(
24
+ Tasks.image_colorization,
25
+ model='damo/cv_ddcolor_image-colorization',
26
+ device='gpu'
 
 
 
 
 
27
  )
28
+ print("✅ DDColor Model loaded successfully.")
 
 
 
 
 
 
 
29
  except Exception as e:
30
+ print(f"❌ Error loading DDColor model: {e}")
31
+ ddcolor_pipeline = None
 
 
 
32
 
33
  # ==========================================
34
+ # 2. دالة المعالجة (الاحترافية)
35
  # ==========================================
36
 
37
+ @spaces.GPU(duration=180) # نمنح وقتاً كافياً للفيديوهات
38
+ def colorize_video_professional(video_file):
39
  if not video_file:
40
  return None
 
 
 
 
41
 
42
+ if ddcolor_pipeline is None:
43
+ raise gr.Error("فشل تحميل النموذج. يرجى مراجعة السجلات.")
44
+
45
+ print("🚀 Starting professional colorization on ZeroGPU...")
46
 
47
  timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
48
+ temp_frames_dir = os.path.join(tempfile.gettempdir(), f"frames_dd_{timestamp}")
49
+ os.makedirs(temp_frames_dir, exist_ok=True)
50
 
51
+ final_output_name = f"colored_ddcolor_{timestamp}.mp4"
52
+ audio_path = os.path.join(tempfile.gettempdir(), f"audio_dd_{timestamp}.aac")
53
+
54
+ # --- 1. استخراج الصوت (إن وجد) ---
55
  audio_exists = False
56
  try:
57
  (
 
64
  except ffmpeg.Error:
65
  print("⚠️ Warning: No audio found or extraction failed.")
66
 
67
+ # --- 2. قراءة الفيديو ومعالجة الإطارات ---
68
  cap = cv2.VideoCapture(video_file)
 
 
 
69
  fps = cap.get(cv2.CAP_PROP_FPS)
70
+ if fps == 0: fps = 25
 
 
 
 
 
 
 
 
 
71
 
72
+ frame_count = 0
73
+ print("🎬 Processing frames...")
 
 
 
 
74
 
75
  while True:
76
  ret, frame = cap.read()
77
  if not ret:
78
  break
79
 
80
+ # DDColor يقبل الصورة بصيغة BGR أو RGB (مصفوفة Numpy)
81
+ # نقوم بتمرير الإطار مباشرة للنموذج
82
+
83
+ # المعالجة باستخدام DDColor
84
+ # الناتج يكون قاموساً يحتوي على الصورة الملونة تحت مفتاح 'output_img'
85
+ result = ddcolor_pipeline(frame)
86
+ colorized_frame_bgr = result['output_img']
87
 
88
+ # حفظ الإطار كصورة PNG (لتجنب مشاكل ترميز الفيديو في OpenCV)
89
+ frame_filename = os.path.join(temp_frames_dir, f"frame_{frame_count:05d}.png")
90
+ cv2.imwrite(frame_filename, colorized_frame_bgr)
 
 
 
 
 
 
 
91
 
92
+ frame_count += 1
93
+ if frame_count % 10 == 0:
94
+ print(f"Processed {frame_count} frames...")
95
 
96
  cap.release()
97
+ print(f"✅ Finished processing {frame_count} frames. Stitching video...")
98
 
99
+ # --- 3. تجميع الفيديو باستخدام FFmpeg ---
100
+ # استخدام نمط %05d لقراءة الإطارات بالترتيب الصحيح
101
+ input_frames = ffmpeg.input(os.path.join(temp_frames_dir, 'frame_%05d.png'), framerate=fps)
102
 
 
 
 
 
 
 
103
  if audio_exists:
104
+ input_audio = ffmpeg.input(audio_path)
105
+ # استخدام ترميز x264 لضمان التوافقية
106
+ stream = ffmpeg.output(input_frames, input_audio, final_output_name, vcodec='libx264', pix_fmt='yuv420p', acodec='aac', shortest=None)
 
 
 
 
 
 
107
  else:
108
+ stream = ffmpeg.output(input_frames, final_output_name, vcodec='libx264', pix_fmt='yuv420p')
109
+
110
+ try:
111
+ stream.run(overwrite_output=True, quiet=True)
112
+ except ffmpeg.Error as e:
113
+ print("FFmpeg Error:", e.stderr.decode('utf8'))
114
+ # محاولة أخيرة بدون صوت في حال فشل الدمج
115
+ ffmpeg.input(os.path.join(temp_frames_dir, 'frame_%05d.png'), framerate=fps).output(final_output_name, vcodec='libx264', pix_fmt='yuv420p').run(overwrite_output=True)
116
+
117
+ # تنظيف
118
+ shutil.rmtree(temp_frames_dir, ignore_errors=True)
119
  if os.path.exists(audio_path): os.remove(audio_path)
120
 
121
  return final_output_name
122
 
123
  # ==========================================
124
+ # 3. واجهة التطبيق (بسيطة واحترافية)
125
  # ==========================================
126
  custom_css = """
127
  #col-container {max-width: 700px; margin-left: auto; margin-right: auto;}
128
  """
129
 
130
+ with gr.Blocks(css=custom_css, title="Professional Video Colorizer (DDColor)") as demo:
131
  with gr.Column(elem_id="col-container"):
132
+ gr.Markdown("# 🎞️ Professional Video Colorizer")
133
+ gr.Markdown("تلوين احترافي وواقعي للفيديو باستخدام نموذج DDColor. يحافظ على التفاصيل الأصلية بدون تغيير.")
134
 
135
  with gr.Row():
136
+ video_input = gr.Video(label="فيديو أبيض وأسود (Input)")
137
+ video_output = gr.Video(label="الفيديو الملون (Output)")
 
 
 
 
 
 
 
 
138
 
139
+ # لا توجد خيارات إضافية، فقط زر التلوين
140
+ submit_btn = gr.Button("✨ بدء التلوين الاحترافي", variant="primary", size="lg")
141
 
142
  submit_btn.click(
143
+ fn=colorize_video_professional,
144
+ inputs=[video_input],
145
  outputs=video_output
146
  )
147