|
import tensorflow as tf |
|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
from tensorflow.keras.preprocessing import image as tf_image |
|
from tensorflow.keras.applications import VGG19 |
|
from tensorflow.keras.models import Model |
|
from tensorflow.keras import layers |
|
from tensorflow.keras.optimizers import Adam |
|
|
|
|
|
base_model = VGG19(weights="imagenet", include_top=False) |
|
|
|
|
|
style_layers = ["block1_conv1", "block2_conv1", "block3_conv1", "block4_conv1", "block5_conv1"] |
|
content_layer = "block4_conv2" |
|
|
|
|
|
style_extractor = Model(inputs=base_model.input, outputs=[base_model.get_layer(layer).output for layer in style_layers]) |
|
content_extractor = Model(inputs=base_model.input, outputs=base_model.get_layer(content_layer).output) |
|
|
|
|
|
def gram_matrix(input_tensor): |
|
result = tf.linalg.einsum("bijc,bijd->bcd", input_tensor, input_tensor) |
|
input_shape = tf.shape(input_tensor) |
|
num_locations = tf.cast(input_shape[1]*input_shape[2], tf.float32) |
|
return result / num_locations |
|
|
|
|
|
def style_loss(style_targets, predicted_styles): |
|
loss = 0 |
|
for style_target, predicted_style in zip(style_targets, predicted_styles): |
|
loss += tf.reduce_mean(tf.square(gram_matrix(style_target) - gram_matrix(predicted_style))) |
|
return loss |
|
|
|
|
|
def content_loss(content_target, predicted_content): |
|
return tf.reduce_mean(tf.square(content_target - predicted_content)) |
|
|
|
|
|
input_image_path = "input_image.jpg" |
|
style_image_path = "style_image.jpg" |
|
|
|
input_image = tf_image.load_img(input_image_path) |
|
style_image = tf_image.load_img(style_image_path) |
|
|
|
input_image = tf_image.img_to_array(input_image) |
|
style_image = tf_image.img_to_array(style_image) |
|
|
|
|
|
input_image = tf_image.smart_resize(input_image, (256, 256)) |
|
style_image = tf_image.smart_resize(style_image, (256, 256)) |
|
|
|
input_image = tf_image.img_to_array(input_image) |
|
style_image = tf_image.img_to_array(style_image) |
|
|
|
input_image = tf.keras.applications.vgg19.preprocess_input(input_image) |
|
style_image = tf.keras.applications.vgg19.preprocess_input(style_image) |
|
|
|
input_image = np.expand_dims(input_image, axis=0) |
|
style_image = np.expand_dims(style_image, axis=0) |
|
|
|
|
|
generated_image = tf.Variable(input_image, dtype=tf.float32) |
|
|
|
|
|
optimizer = Adam(learning_rate=10.0) |
|
|
|
|
|
num_iterations = 1000 |
|
|
|
|
|
style_features = style_extractor(style_image) |
|
content_features = content_extractor(input_image) |
|
|
|
|
|
style_targets = [style_extractor(tf.constant(style_image)) for _ in style_layers] |
|
|
|
|
|
for iteration in range(num_iterations): |
|
with tf.GradientTape() as tape: |
|
|
|
generated_features = style_extractor(generated_image) |
|
|
|
|
|
current_style_loss = style_loss(style_targets, generated_features) |
|
current_content_loss = content_loss(content_features, generated_features[-1]) |
|
|
|
|
|
total_loss = current_style_loss + current_content_loss |
|
|
|
|
|
gradients = tape.gradient(total_loss, generated_image) |
|
|
|
|
|
optimizer.apply_gradients([(gradients, generated_image)]) |
|
|
|
|
|
generated_image.assign(tf.clip_by_value(generated_image, clip_value_min=0.0, clip_value_max=255.0)) |
|
|
|
|
|
if iteration % 100 == 0: |
|
print(f"Iteration {iteration}, Total loss: {total_loss}") |
|
|
|
|
|
final_image = tf_image.img_to_array(generated_image[0]) |
|
|
|
|
|
final_image = np.clip(final_image, 0, 255).astype(np.uint8) |
|
|
|
|
|
final_image_path = "enhanced_image.jpg" |
|
tf.keras.preprocessing.image.save_img(final_image_path, final_image[0]) |
|
|
|
|
|
plt.imshow(final_image[0]) |
|
plt.axis("off") |
|
plt.show() |
|
|