Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import tensorflow as tf | |
| import numpy as np | |
| from PIL import Image | |
| from tensorflow.keras.applications.vgg19 import VGG19, preprocess_input | |
| from tensorflow.keras.preprocessing.image import img_to_array | |
| from tensorflow.keras.models import Model | |
| # Load VGG19 model | |
| model = VGG19(include_top=False, weights='imagenet') | |
| model.trainable = False | |
| # Define content and style layers | |
| content_layer = 'block5_conv2' | |
| content_model = Model(inputs=model.input, | |
| outputs=model.get_layer(content_layer).output) | |
| style_layers = ['block1_conv1', 'block3_conv1', 'block5_conv1'] | |
| style_models = [Model(inputs=model.input, outputs=model.get_layer( | |
| layer).output) for layer in style_layers] | |
| weight_of_layer = 1. / len(style_models) | |
| def process_image(img): | |
| # Convert to array and preprocess | |
| img = img_to_array(img) | |
| img = preprocess_input(img) | |
| img = np.expand_dims(img, axis=0) | |
| return img | |
| def deprocess(img): | |
| # Perform the inverse of the preprocessing step | |
| img = img.copy() # Create a copy to avoid modifying the original | |
| img[:, :, 0] += 103.939 | |
| img[:, :, 1] += 116.779 | |
| img[:, :, 2] += 123.68 | |
| # Convert BGR to RGB | |
| img = img[:, :, ::-1] | |
| img = np.clip(img, 0, 255).astype('uint8') | |
| return img | |
| # Gram matrix | |
| def gram_matrix(A): | |
| channels = int(A.shape[-1]) | |
| a = tf.reshape(A, [-1, channels]) | |
| n = tf.shape(a)[0] | |
| gram = tf.matmul(a, a, transpose_a=True) | |
| return gram / tf.cast(n, tf.float32) | |
| # Content loss | |
| def content_loss(content, generated): | |
| a_C = content_model(content) | |
| a_G = content_model(generated) | |
| loss = tf.reduce_mean(tf.square(a_C - a_G)) | |
| return loss | |
| # Style loss | |
| def style_cost(style, generated): | |
| J_style = 0 | |
| for style_model in style_models: | |
| a_S = style_model(style) | |
| a_G = style_model(generated) | |
| GS = gram_matrix(a_S) | |
| GG = gram_matrix(a_G) | |
| current_cost = tf.reduce_mean(tf.square(GS - GG)) | |
| J_style += current_cost * weight_of_layer | |
| return J_style | |
| # Total Loss Function | |
| def compute_total_loss(content, style, generated, alpha=10, beta=1000): | |
| J_content = content_loss(content, generated) | |
| J_style = style_cost(style, generated) | |
| return alpha * J_content + beta * J_style | |
| def ensure_pil_image(img): | |
| if isinstance(img, np.ndarray): | |
| return Image.fromarray(img.astype('uint8')) | |
| return img | |
| def neural_style_transfer(content_img, style_img, iterations=50, alpha=10, beta=1000): | |
| try: | |
| # Ensure we have PIL images | |
| content_img_pil = ensure_pil_image(content_img) | |
| style_img_pil = ensure_pil_image(style_img) | |
| # Resize images to a manageable size | |
| content_img_pil = content_img_pil.resize((300, 300), Image.LANCZOS) | |
| style_img_pil = style_img_pil.resize((300, 300), Image.LANCZOS) | |
| # Process images | |
| content = process_image(content_img_pil) | |
| style = process_image(style_img_pil) | |
| # Initialize with content image | |
| generated = tf.Variable(content, dtype=tf.float32) | |
| # Optimizer | |
| opt = tf.keras.optimizers.Adam(learning_rate=0.7) | |
| progress_images = [] | |
| for i in range(iterations): | |
| with tf.GradientTape() as tape: | |
| total_loss = compute_total_loss( | |
| content, style, generated, alpha, beta) | |
| # Get gradients and apply | |
| grads = tape.gradient(total_loss, generated) | |
| opt.apply_gradients([(grads, generated)]) | |
| if i % 10 == 0 or i == iterations - 1: | |
| # Save progress image | |
| current_img = generated.numpy() | |
| img_squeezed = np.squeeze(current_img, axis=0) | |
| img_deprocessed = deprocess(img_squeezed) | |
| progress_images.append(Image.fromarray(img_deprocessed)) | |
| print(f"Iteration {i}, Loss: {total_loss.numpy()}") | |
| # Get final image | |
| final_img = generated.numpy() | |
| final_img = np.squeeze(final_img, axis=0) | |
| final_img = deprocess(final_img) | |
| return Image.fromarray(final_img), progress_images | |
| except Exception as e: | |
| print(f"Error in neural_style_transfer: {e}") | |
| # Return a default error image | |
| error_img = Image.new('RGB', (300, 300), color='red') | |
| return error_img, [] | |
| def style_transfer_interface(content_img, style_img, iterations=50, content_weight=10, style_weight=1000): | |
| # Check if images are provided | |
| if content_img is None or style_img is None: | |
| return None | |
| # Perform style transfer | |
| result_img, _ = neural_style_transfer( | |
| content_img, | |
| style_img, | |
| iterations=iterations, | |
| alpha=content_weight, | |
| beta=style_weight | |
| ) | |
| return result_img | |
| # Example images | |
| content_path = "content/images/content" | |
| style_path = "content/styles/style" | |
| example_content_1 = f"{content_path}1.jpg" | |
| example_content_2 = f"{content_path}2.jpg" | |
| example_content_3 = f"{content_path}3.jpg" | |
| example_style_1 = f"{style_path}1.jpg" | |
| example_style_2 = f"{style_path}2.jpg" | |
| example_style_3 = f"{style_path}3.jpg" | |
| examples = [ | |
| [example_content_1, example_style_1, 10, 5, 1000], | |
| [example_content_2, example_style_2, 20, 10, 1500], | |
| [example_content_3, example_style_3, 50, 15, 2000], | |
| ] | |
| with gr.Blocks(title="Neural Style Transfer") as app: | |
| gr.Markdown("# Neural Style Transfer App") | |
| gr.Markdown( | |
| "Upload a content image and a style image to generate a stylized result") | |
| with gr.Row(): | |
| with gr.Column(): | |
| content_input = gr.Image(label="Content Image", type="pil") | |
| style_input = gr.Image(label="Style Image", type="pil") | |
| with gr.Row(): | |
| iterations_slider = gr.Slider( | |
| minimum=10, maximum=100, value=50, step=10, | |
| label="Iterations" | |
| ) | |
| with gr.Row(): | |
| content_weight_slider = gr.Slider( | |
| minimum=1, maximum=20, value=10, step=1, | |
| label="Content Weight" | |
| ) | |
| style_weight_slider = gr.Slider( | |
| minimum=500, maximum=2000, value=1000, step=100, | |
| label="Style Weight" | |
| ) | |
| submit_btn = gr.Button("Generate Stylized Image") | |
| with gr.Column(): | |
| output_image = gr.Image(label="Stylized Result") | |
| gr.Examples( | |
| examples=examples, | |
| inputs=[content_input, style_input, iterations_slider, | |
| content_weight_slider, style_weight_slider], | |
| outputs=output_image, | |
| fn=style_transfer_interface, | |
| cache_examples=False, | |
| ) | |
| submit_btn.click( | |
| fn=style_transfer_interface, | |
| inputs=[content_input, style_input, iterations_slider, | |
| content_weight_slider, style_weight_slider], | |
| outputs=output_image | |
| ) | |
| # Launch the app | |
| if __name__ == "__main__": | |
| app.launch(share=True, debug=True) |