File size: 5,979 Bytes
92d2cce
 
 
 
 
 
2856e75
 
92d2cce
 
2856e75
92d2cce
 
2856e75
92d2cce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2856e75
92d2cce
2856e75
92d2cce
 
2856e75
 
 
92d2cce
 
 
 
2856e75
92d2cce
 
 
 
 
 
2856e75
 
92d2cce
2856e75
92d2cce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2856e75
 
 
92d2cce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<|begin_of_box|>import gradio as gr
import numpy as np
import cv2
import tempfile
import os
from PIL import Image
import time

# Simulated outpainting function (in a real application, this would use a proper model)
def outpaint_video_with_reference(input_video, reference_image, outpaint_ratio=0.5):
    """
    Simulate video outpainting to match reference image height.
    In a real implementation, this would use a diffusion model or similar.
    """
    try:
        # Create temporary files for processing
        with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as temp_video:
            temp_video_path = temp_video.name
        
        with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_ref:
            temp_ref_path = temp_ref.name
        
        # Save uploaded files
        with open(input_video, 'wb') as f:
            f.write(open(input_video, 'rb').read())
        
        with open(reference_image, 'wb') as f:
            f.write(open(reference_image, 'rb').read())
        
        # Get video and reference image dimensions
        cap = cv2.VideoCapture(input_video)
        ref_img = Image.open(reference_image)
        ref_height = ref_img.height
        ref_width = ref_img.width
        
        # Get original video dimensions
        original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        
        # Calculate new dimensions to match reference height
        new_height = ref_height
        scale_factor = new_height / original_height
        new_width = int(original_width * scale_factor)
        
        # Create output video writer
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        out = cv2.VideoWriter(temp_video_path, fourcc, 30.0, (new_width, new_height))
        
        frame_count = 0
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            
            # Resize frame to match new dimensions
            resized_frame = cv2.resize(frame, (new_width, new_height))
            
            # Simulate outpainting by adding a border that matches reference style
            # In a real implementation, this would use AI to generate content
            border_size = int(new_width * outpaint_ratio)
            if border_size > 0:
                # Create a border that tries to match the reference image style
                border_color = np.mean(resized_frame, axis=(0, 1))
                bordered_frame = cv2.copyMakeBorder(
                    resized_frame,
                    0, 0, border_size, border_size,
                    cv2.BORDER_CONSTANT,
                    value=border_color
                )
                out.write(bordered_frame)
            else:
                out.write(resized_frame)
            
            frame_count += 1
            if frame_count % 10 == 0:
                yield f"Processing frame {frame_count}/{total_frames}..."
        
        cap.release()
        out.release()
        
        # Return the processed video
        yield temp_video_path
        
    except Exception as e:
        yield f"Error: {str(e)}"
    finally:
        # Clean up temporary files
        try:
            if 'temp_video_path' in locals() and os.path.exists(temp_video_path):
                os.unlink(temp_video_path)
            if 'temp_ref_path' in locals() and os.path.exists(temp_ref_path):
                os.unlink(temp_ref_path)
        except:
            pass

# Create the Gradio interface
with gr.Blocks() as demo:
    gr.Markdown("# 🎬 Video Outpainting with Reference Height Matching")
    gr.Markdown("Upload a video and a reference image. The video will be outpainted to match the height of the reference image.")
    
    with gr.Row():
        with gr.Column():
            gr.Markdown("### Input Video")
            video_input = gr.Video(label="Upload Video", type="filepath")
            gr.Markdown("### Reference Image")
            reference_input = gr.Image(label="Upload Reference Image", type="filepath")
            
            outpaint_ratio = gr.Slider(
                minimum=0.1,
                maximum=1.0,
                value=0.3,
                step=0.1,
                label="Outpaint Ratio (percentage of new width)"
            )
            
            process_button = gr.Button("Process Video", variant="primary")
            
        with gr.Column():
            gr.Markdown("### Output")
            output_video = gr.Video(label="Processed Video")
            status_text = gr.Textbox(label="Status", interactive=False)
    
    # Process function
    def process_video(video, reference, ratio):
        if not video or not reference:
            return None, "Please upload both video and reference image"
        
        status_text = ""
        for status in outpaint_video_with_reference(video, reference, ratio):
            if isinstance(status, str):
                status_text = status
                yield None, status_text
            else:
                yield status, "Processing complete!"
    
    process_button.click(
        fn=process_video,
        inputs=[video_input, reference_input, outpaint_ratio],
        outputs=[output_video, status_text],
        api_visibility="public"
    )

# Launch the app 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"}]
)<|end_of_box|>