Spaces:
Running
on
Zero
Running
on
Zero
| import spaces | |
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| import os | |
| import shutil | |
| import tempfile | |
| import datetime | |
| import ffmpeg | |
| from modelscope.pipelines import pipeline | |
| from modelscope.utils.constant import Tasks | |
| # استيراد مكتبة السلايدر الجديدة | |
| from gradio_imageslider import ImageSlider | |
| # ========================================== | |
| # 1. إعداد نموذج DDColor | |
| # ========================================== | |
| print("⏳ Loading DDColor Professional Model...") | |
| try: | |
| ddcolor_pipeline = pipeline( | |
| Tasks.image_colorization, | |
| model='damo/cv_ddcolor_image-colorization', | |
| device='gpu' | |
| ) | |
| print("✅ DDColor Model loaded successfully.") | |
| except Exception as e: | |
| print(f"❌ Error loading DDColor model: {e}") | |
| ddcolor_pipeline = None | |
| # ========================================== | |
| # 2. دالة المعالجة | |
| # ========================================== | |
| def colorize_video_professional(video_file): | |
| if not video_file: | |
| return None, None | |
| if ddcolor_pipeline is None: | |
| raise gr.Error("فشل تحميل النموذج.") | |
| print("🚀 Starting processing...") | |
| timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") | |
| temp_frames_dir = os.path.join(tempfile.gettempdir(), f"frames_{timestamp}") | |
| os.makedirs(temp_frames_dir, exist_ok=True) | |
| final_output_name = f"colored_ddcolor_{timestamp}.mp4" | |
| audio_path = os.path.join(tempfile.gettempdir(), f"audio_{timestamp}.aac") | |
| # مسارات صور المقارنة | |
| comp_original_path = os.path.join(tempfile.gettempdir(), f"comp_orig_{timestamp}.png") | |
| comp_colored_path = os.path.join(tempfile.gettempdir(), f"comp_color_{timestamp}.png") | |
| comparison_result = None | |
| # --- استخراج الصوت --- | |
| audio_exists = False | |
| try: | |
| ffmpeg.input(video_file).output(audio_path, acodec='copy').run(overwrite_output=True, quiet=True) | |
| audio_exists = True | |
| except ffmpeg.Error: | |
| pass | |
| # --- المعالجة --- | |
| cap = cv2.VideoCapture(video_file) | |
| fps = cap.get(cv2.CAP_PROP_FPS) or 25 | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| # نختار إطاراً في المنتصف ليكون صورة المقارنة | |
| comparison_frame_index = max(0, total_frames // 2) | |
| frame_count = 0 | |
| while True: | |
| ret, frame = cap.read() | |
| if not ret: | |
| break | |
| # حفظ الإطار الأصلي للمقارنة إذا وصلنا للمنتصف | |
| if frame_count == comparison_frame_index: | |
| cv2.imwrite(comp_original_path, frame) | |
| # التلوين | |
| result = ddcolor_pipeline(frame) | |
| colorized_frame_bgr = result['output_img'] | |
| # حفظ الإطار الملون للمقارنة | |
| if frame_count == comparison_frame_index: | |
| cv2.imwrite(comp_colored_path, colorized_frame_bgr) | |
| comparison_result = (comp_original_path, comp_colored_path) | |
| # حفظ الإطار للفيديو | |
| frame_filename = os.path.join(temp_frames_dir, f"frame_{frame_count:05d}.png") | |
| cv2.imwrite(frame_filename, colorized_frame_bgr) | |
| frame_count += 1 | |
| cap.release() | |
| # --- تجميع الفيديو --- | |
| input_frames = ffmpeg.input(os.path.join(temp_frames_dir, 'frame_%05d.png'), framerate=fps) | |
| if audio_exists: | |
| stream = ffmpeg.output(input_frames, ffmpeg.input(audio_path), final_output_name, vcodec='libx264', pix_fmt='yuv420p', acodec='aac', shortest=None) | |
| else: | |
| stream = ffmpeg.output(input_frames, final_output_name, vcodec='libx264', pix_fmt='yuv420p') | |
| try: | |
| stream.run(overwrite_output=True, quiet=True) | |
| except ffmpeg.Error: | |
| # محاولة بديلة | |
| 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) | |
| shutil.rmtree(temp_frames_dir, ignore_errors=True) | |
| # نرجع الفيديو + صور المقارنة (Tuple) | |
| return final_output_name, comparison_result | |
| # ========================================== | |
| # 3. الواجهة الجديدة | |
| # ========================================== | |
| custom_css = """ | |
| #col-container {max-width: 800px; margin-left: auto; margin-right: auto;} | |
| """ | |
| with gr.Blocks(css=custom_css, title="Pro Video Colorizer") as demo: | |
| with gr.Column(elem_id="col-container"): | |
| gr.Markdown("# 🎞️ Professional Video Colorizer (DDColor)") | |
| gr.Markdown("قم برفع فيديو أبيض وأسود وسيقوم الذكاء الاصطناعي بتلوينه.") | |
| with gr.Row(): | |
| video_input = gr.Video(label="فيديو أبيض وأسود (Input)") | |
| submit_btn = gr.Button("✨ تلوين ومعاينة (Colorize)", variant="primary", size="lg") | |
| # عنصر المقارنة الجديد | |
| gr.Markdown("### 🔍 معاينة قبل وبعد (Before / After)") | |
| slider_output = ImageSlider(label="مقارنة النتيجة", type="filepath", position=0.5) | |
| gr.Markdown("### 🎥 الفيديو النهائي الملون") | |
| video_output = gr.Video(label="النتيجة النهائية") | |
| submit_btn.click( | |
| fn=colorize_video_professional, | |
| inputs=[video_input], | |
| outputs=[video_output, slider_output] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(server_name="0.0.0.0", server_port=7860) |