import gradio as gr import numpy as np import cv2 import time from PIL import Image import io def apply_transformations(image, numbers_str): """ Apply a series of transformations to an image based on a list of numbers. Shows the progressive changes as each transformation is applied. Returns both the current image and the full gallery of transformations. """ try: # Parse the input numbers numbers = [float(n.strip()) for n in numbers_str.split(',') if n.strip()] if not numbers: return image, [(image, "Original Image")] # Convert PIL Image to numpy array for OpenCV operations img = np.array(image) # Initialize the result list with the original image results = [(image, "Original Image")] current_image = image # Apply transformations based on each number for i, value in enumerate(numbers): # Make a copy of the current numpy image if i == 0: current_img = img.copy() else: current_img = np.array(current_image) # Apply different transformations based on the value transformation_type = "" if i % 5 == 0: # Brightness adjustment # Scale value to reasonable brightness adjustment brightness = max(min(value, 100), -100) # Limit between -100 and 100 current_img = cv2.addWeighted(current_img, 1, np.zeros_like(current_img), 0, brightness) transformation_type = f"Brightness: {brightness:.1f}" elif i % 5 == 1: # Rotation # Scale value to reasonable rotation angle angle = value % 360 h, w = current_img.shape[:2] center = (w // 2, h // 2) rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0) current_img = cv2.warpAffine(current_img, rotation_matrix, (w, h)) transformation_type = f"Rotation: {angle:.1f}°" elif i % 5 == 2: # Contrast adjustment # Scale value to reasonable contrast adjustment contrast = max(min(value / 10, 3), 0.5) # Limit between 0.5 and 3 current_img = cv2.convertScaleAbs(current_img, alpha=contrast, beta=0) transformation_type = f"Contrast: {contrast:.1f}x" elif i % 5 == 3: # Blur # Scale value to reasonable blur kernel size blur_amount = max(int(abs(value) % 20), 1) if blur_amount % 2 == 0: # Ensure kernel size is odd blur_amount += 1 current_img = cv2.GaussianBlur(current_img, (blur_amount, blur_amount), 0) transformation_type = f"Blur: {blur_amount}px" elif i % 5 == 4: # Hue shift (for color images) if current_img.shape[-1] == 3: # Only for color images # Convert to HSV hsv_img = cv2.cvtColor(current_img, cv2.COLOR_RGB2HSV) # Shift hue hue_shift = int(value) % 180 hsv_img[:, :, 0] = (hsv_img[:, :, 0] + hue_shift) % 180 # Convert back to RGB current_img = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2RGB) transformation_type = f"Hue Shift: {hue_shift}°" # Convert back to PIL Image and add to results current_image = Image.fromarray(current_img) # Add to results with a label for the gallery results.append((current_image, f"Step {i+1}: {transformation_type}")) # (Progress updates removed) # Add a small delay to make the progressive changes visible time.sleep(4) # Yield intermediate results for real-time updates if i < len(numbers) - 1: yield current_image, results return current_image, results except Exception as e: error_msg = f"Error: {str(e)}" return image, [(image, "Error")] # Create Gradio Interface with gr.Blocks() as demo: gr.Markdown("# Image Transformation Demo") gr.Markdown("Upload an image and provide a comma-separated list of numbers. The demo will apply a series of transformations to the image based on these numbers.") with gr.Row(): with gr.Column(scale=1): input_image = gr.Image(label="Input Image", type="pil") numbers_input = gr.Textbox(label="Transformation Values (comma-separated numbers)", placeholder="e.g., 50, -30, 1.5, 5, 90, 20", value="30, 45, 1.5, 3, 60, -20, 90, 1.8, 7, 120") transform_btn = gr.Button("Apply Transformations") explanation = gr.Markdown(""" ## How the transformations work: The numbers you input will be used to apply these transformations in sequence: 1. First number: Brightness adjustment (-100 to 100) 2. Second number: Rotation (degrees) 3. Third number: Contrast adjustment (0.5 to 3) 4. Fourth number: Blur (kernel size) 5. Fifth number: Hue shift (color images only) And the pattern repeats for longer lists of numbers. """) with gr.Column(scale=2): with gr.Row(): current_image = gr.Image(label="Current Transformation", type="pil") with gr.Row(): gallery = gr.Gallery(label="Transformation History", show_label=True, columns=4, rows=2, height="auto") transform_btn.click( fn=apply_transformations, inputs=[input_image, numbers_input], outputs=[current_image, gallery] ) # Launch the app demo.launch()