Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| import tempfile | |
| import os | |
| from PIL import Image, ImageEnhance, ImageFilter | |
| import random | |
| import math | |
| class AdvancedVideoTransformer: | |
| def __init__(self): | |
| self.transformations = [] | |
| def extract_frames(self, video_path): | |
| """Extract frames with metadata""" | |
| frames = [] | |
| cap = cv2.VideoCapture(video_path) | |
| if not cap.isOpened(): | |
| return [], 30 | |
| fps = int(cap.get(cv2.CAP_PROP_FPS)) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| for i in range(total_frames): | |
| ret, frame = cap.read() | |
| if not ret: | |
| break | |
| frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) | |
| cap.release() | |
| return frames, fps | |
| def save_video(self, frames, fps, output_path): | |
| """Save processed frames as video""" | |
| if not frames: | |
| return None | |
| h, w = frames[0].shape[:2] | |
| fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
| out = cv2.VideoWriter(output_path, fourcc, fps, (w, h)) | |
| for frame in frames: | |
| out.write(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)) | |
| out.release() | |
| return output_path | |
| # TRANSFORMATION METHODS | |
| def apply_geometric_transform(self, frame, transform_type="random"): | |
| """Apply geometric transformations to avoid duplicate detection""" | |
| h, w = frame.shape[:2] | |
| if transform_type == "random" or transform_type == "perspective": | |
| # Random perspective transform | |
| pts1 = np.float32([[0, 0], [w, 0], [0, h], [w, h]]) | |
| margin = min(w, h) * 0.1 | |
| pts2 = np.float32([ | |
| [random.uniform(0, margin), random.uniform(0, margin)], | |
| [w - random.uniform(0, margin), random.uniform(0, margin)], | |
| [random.uniform(0, margin), h - random.uniform(0, margin)], | |
| [w - random.uniform(0, margin), h - random.uniform(0, margin)] | |
| ]) | |
| matrix = cv2.getPerspectiveTransform(pts1, pts2) | |
| transformed = cv2.warpPerspective(frame, matrix, (w, h)) | |
| return transformed | |
| elif transform_type == "rotation": | |
| # Small rotation | |
| angle = random.uniform(-5, 5) | |
| center = (w // 2, h // 2) | |
| matrix = cv2.getRotationMatrix2D(center, angle, 1.0) | |
| rotated = cv2.warpAffine(frame, matrix, (w, h)) | |
| return rotated | |
| elif transform_type == "scale": | |
| # Slight scale variation | |
| scale = random.uniform(0.95, 1.05) | |
| new_w, new_h = int(w * scale), int(h * scale) | |
| scaled = cv2.resize(frame, (new_w, new_h)) | |
| # Pad or crop to original size | |
| if scale > 1: | |
| start_x = (new_w - w) // 2 | |
| start_y = (new_h - h) // 2 | |
| result = scaled[start_y:start_y+h, start_x:start_x+w] | |
| else: | |
| pad_x = (w - new_w) // 2 | |
| pad_y = (h - new_h) // 2 | |
| result = np.zeros((h, w, 3), dtype=np.uint8) | |
| result[pad_y:pad_y+new_h, pad_x:pad_x+new_w] = scaled | |
| return result | |
| return frame | |
| def apply_color_transformation(self, frame): | |
| """Comprehensive color transformation""" | |
| # Convert to PIL for easier processing | |
| pil_img = Image.fromarray(frame) | |
| # Random brightness adjustment | |
| brightness_factor = random.uniform(0.9, 1.1) | |
| enhancer = ImageEnhance.Brightness(pil_img) | |
| pil_img = enhancer.enhance(brightness_factor) | |
| # Random contrast adjustment | |
| contrast_factor = random.uniform(0.9, 1.1) | |
| enhancer = ImageEnhance.Contrast(pil_img) | |
| pil_img = enhancer.enhance(contrast_factor) | |
| # Random color saturation | |
| color_factor = random.uniform(0.8, 1.2) | |
| enhancer = ImageEnhance.Color(pil_img) | |
| pil_img = enhancer.enhance(color_factor) | |
| # Apply color grading | |
| img_array = np.array(pil_img, dtype=np.float32) | |
| # Random RGB channel adjustments | |
| r_mult = random.uniform(0.95, 1.05) | |
| g_mult = random.uniform(0.95, 1.05) | |
| b_mult = random.uniform(0.95, 1.05) | |
| img_array[:,:,0] *= r_mult | |
| img_array[:,:,1] *= g_mult | |
| img_array[:,:,2] *= b_mult | |
| # Clip values | |
| img_array = np.clip(img_array, 0, 255).astype(np.uint8) | |
| return img_array | |
| def apply_temporal_modification(self, frames): | |
| """Modify timing to avoid duplicate detection""" | |
| if len(frames) < 10: | |
| return frames | |
| modified_frames = [] | |
| # Add slight variations in frame timing | |
| for i, frame in enumerate(frames): | |
| # Occasionally duplicate or skip frames | |
| action = random.choices( | |
| ['keep', 'duplicate', 'skip'], | |
| weights=[0.8, 0.1, 0.1], | |
| k=1 | |
| )[0] | |
| if action == 'keep': | |
| modified_frames.append(frame) | |
| elif action == 'duplicate' and i > 0 and i < len(frames) - 1: | |
| # Add a slightly modified version of this frame | |
| modified_frame = frame.copy() | |
| # Add small noise | |
| noise = np.random.normal(0, 5, frame.shape) | |
| modified_frame = np.clip(modified_frame.astype(np.float32) + noise, 0, 255).astype(np.uint8) | |
| modified_frames.append(frame) | |
| modified_frames.append(modified_frame) | |
| # If 'skip', don't add the frame (effectively speeding up that part) | |
| return modified_frames if modified_frames else frames | |
| def apply_visual_effects(self, frame): | |
| """Add subtle visual effects to change appearance""" | |
| h, w = frame.shape[:2] | |
| # Add very subtle noise (imperceptible but changes pixel values) | |
| noise = np.random.normal(0, 2, frame.shape) | |
| frame_with_noise = np.clip(frame.astype(np.float32) + noise, 0, 255).astype(np.uint8) | |
| # Add subtle vignette effect | |
| center = (w // 2, h // 2) | |
| Y, X = np.ogrid[:h, :w] | |
| dist_from_center = np.sqrt((X - center[0])**2 + (Y - center[1])**2) | |
| max_dist = np.sqrt(center[0]**2 + center[1]**2) | |
| vignette = 1 - (dist_from_center / max_dist) * 0.1 # Very subtle | |
| vignette = np.stack([vignette] * 3, axis=2) | |
| frame_vignette = (frame_with_noise * vignette).astype(np.uint8) | |
| # Apply very slight blur to reduce sharpness differences | |
| frame_blurred = cv2.GaussianBlur(frame_vignette, (3, 3), 0) | |
| return frame_blurred | |
| def apply_content_rearrangement(self, frames): | |
| """Rearrange content structure to avoid duplicate detection""" | |
| if len(frames) < 20: | |
| return frames | |
| # Split into segments | |
| segment_size = max(10, len(frames) // 5) | |
| segments = [] | |
| for i in range(0, len(frames), segment_size): | |
| segment = frames[i:i+segment_size] | |
| if len(segment) > 0: | |
| segments.append(segment) | |
| if len(segments) < 2: | |
| return frames | |
| # Randomly reorder segments (but keep first and last for coherence) | |
| if len(segments) > 2: | |
| middle_segments = segments[1:-1] | |
| random.shuffle(middle_segments) | |
| segments = [segments[0]] + middle_segments + [segments[-1]] | |
| # Reconstruct video | |
| rearranged_frames = [] | |
| for segment in segments: | |
| rearranged_frames.extend(segment) | |
| return rearranged_frames | |
| def apply_comprehensive_transformation(self, video_path, intensity="medium"): | |
| """Apply all transformations for maximum uniqueness while preserving quality""" | |
| if not video_path: | |
| return None, "Please upload a video first" | |
| try: | |
| # Extract frames | |
| frames, fps = self.extract_frames(video_path) | |
| if not frames: | |
| return None, "Failed to extract frames" | |
| original_count = len(frames) | |
| print(f"Processing {original_count} frames...") | |
| # Apply geometric transformations | |
| print("Applying geometric transformations...") | |
| geo_frames = [] | |
| for i, frame in enumerate(frames): | |
| if intensity == "high": | |
| transform_type = random.choice(["perspective", "rotation", "scale"]) | |
| else: | |
| transform_type = "rotation" if i % 3 == 0 else "scale" | |
| transformed = self.apply_geometric_transform(frame, transform_type) | |
| geo_frames.append(transformed) | |
| # Apply color transformations | |
| print("Applying color transformations...") | |
| color_frames = [] | |
| for frame in geo_frames: | |
| transformed = self.apply_color_transformation(frame) | |
| color_frames.append(transformed) | |
| # Apply temporal modifications (for medium/high intensity) | |
| if intensity in ["medium", "high"]: | |
| print("Applying temporal modifications...") | |
| temporal_frames = self.apply_temporal_modification(color_frames) | |
| else: | |
| temporal_frames = color_frames | |
| # Apply content rearrangement (for high intensity) | |
| if intensity == "high": | |
| print("Applying content rearrangement...") | |
| rearranged_frames = self.apply_content_rearrangement(temporal_frames) | |
| else: | |
| rearranged_frames = temporal_frames | |
| # Apply visual effects | |
| print("Applying visual effects...") | |
| final_frames = [] | |
| for frame in rearranged_frames: | |
| transformed = self.apply_visual_effects(frame) | |
| final_frames.append(transformed) | |
| # Save video | |
| print("Saving final video...") | |
| output_path = tempfile.mktemp(suffix='.mp4') | |
| self.save_video(final_frames, fps, output_path) | |
| final_count = len(final_frames) | |
| status_msg = f"""β Video successfully transformed! | |
| π Transformation Summary: | |
| - Original frames: {original_count} | |
| - Final frames: {final_count} | |
| - Intensity level: {intensity} | |
| - Applied transformations: Geometric, Color, Temporal, Visual Effects | |
| π― Result: Video is now significantly different from original while maintaining quality. | |
| Perfect for avoiding duplicate content detection!""" | |
| return output_path, status_msg | |
| except Exception as e: | |
| return None, f"β Error: {str(e)}" | |
| # Create instance | |
| transformer = AdvancedVideoTransformer() | |
| # Create interface | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown(""" | |
| # π¬ Advanced Video Transformer | |
| ### Transform videos to avoid duplicate content detection while maintaining quality | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π€ Upload Your Video") | |
| video_input = gr.Video(label="Original Video") | |
| gr.Markdown("### βοΈ Transformation Settings") | |
| intensity = gr.Radio( | |
| choices=["low", "medium", "high"], | |
| value="medium", | |
| label="Transformation Intensity", | |
| info="Higher intensity = more changes, better for avoiding detection" | |
| ) | |
| transform_btn = gr.Button("π Transform Video", variant="primary", size="lg") | |
| gr.Markdown(""" | |
| ### π― What This Does: | |
| - **Geometric Changes**: Rotation, scaling, perspective warping | |
| - **Color Adjustments**: Brightness, contrast, saturation variations | |
| - **Temporal Modifications**: Frame timing changes, occasional duplicates/skips | |
| - **Visual Effects**: Subtle noise, vignette, slight blur | |
| - **Content Rearrangement**: Segment reordering (high intensity only) | |
| All while preserving overall video quality! | |
| """) | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π₯ Transformed Video") | |
| video_output = gr.Video(label="Transformed Video") | |
| status_output = gr.Textbox(label="Transformation Status", lines=10) | |
| # Examples section | |
| gr.Markdown(""" | |
| --- | |
| ### π‘ Recommended Settings: | |
| - **Low Intensity**: Minor changes, good for slight variations | |
| - **Medium Intensity**: Balanced approach, recommended for most use cases | |
| - **High Intensity**: Maximum changes, best for strict duplicate detection avoidance | |
| ### π Quality Preservation Features: | |
| - Maintains original resolution | |
| - Preserves audio quality (if any) | |
| - Smooth transitions between frames | |
| - Minimal visible artifacts | |
| """) | |
| # Event handler | |
| transform_btn.click( | |
| fn=transformer.apply_comprehensive_transformation, | |
| inputs=[video_input, intensity], | |
| outputs=[video_output, status_output] | |
| ) | |
| # Launch | |
| demo.queue().launch() |