diff --git a/__helpers__.py b/__helpers__.py index e60cd1f..867102d 100644 --- a/__helpers__.py +++ b/__helpers__.py @@ -19,15 +19,16 @@ import urllib from tqdm import tqdm + if tf.__version__[0] == '1': tf.enable_eager_execution() # print("Eager Execution Initialized:",tf.executing_eagerly()) # Starting session to download Images from URL if fed. -s = requests.Session() -s.proxies = {"http": "http://61.233.25.166:80"} -r = s.get("http://www.google.com") +# s = requests.Session() +# s.proxies = {"http": "http://61.233.25.166:80"} +# r = s.get("http://www.google.com") # Defining the Feature Layers we need respectively @@ -60,8 +61,7 @@ def getModel(): return models.Model(model.input, modelOutput) - # Defining GRAM MATRIX - +# Defining GRAM MATRIX def gram(x): # number of channels @@ -73,9 +73,9 @@ def gram(x): # gram matrix gram = tf.matmul(a, a, transpose_a=True) - return gram / tf.cast(n, tf.float32) + # Defining CONTENT COST def contentCost(contentFeatures, generateFeatures): return tf.reduce_mean(tf.square(contentFeatures-generateFeatures)) @@ -94,13 +94,13 @@ def getFeatures(content, style, model): # Extracting out the different features from the model output contentFeatures = [contentFeature[0] for contentFeature in contentOutputs[numStyleLayers:]] - styleFeatures = [styleFeature[0] for styleFeature in styleOutputs[:numStyleLayers]] - + styleFeatures = [styleFeature[0] for styleFeature in styleOutputs[:numStyleLayers]] return contentFeatures, styleFeatures def loadImage(path_to_img): max_dim = 512 + # import pdb; pdb.set_trace() if type(path_to_img) == str: img2show = Image.open(path_to_img) else: @@ -109,17 +109,19 @@ def loadImage(path_to_img): # long = max(img2show.size) long = (img2show.size) + long = long[0] scale = max_dim/long img = img2show.resize((round(img2show.size[0]*scale), round(img2show.size[1]*scale)), Image.ANTIALIAS) - + img = image.img_to_array(img) # We need to broadcast the image array such that it has a batch dimension - img = np.expand_dims(img2show, axis=0) + img = np.expand_dims(img, axis=0) return img2show, img def urlToImage(url): + import pdb; pdb.set_trace() resp = urllib.request.urlopen(url) img = np.asarray(bytearray(resp.read()), dtype='uint8') img = cv2.imdecode(img, cv2.IMREAD_COLOR) @@ -132,15 +134,14 @@ def urlToImage(url): def inputImageAndPreprocess(path): # Loading the image and reshaping it according to VGG19 requirements. if path[:4]=='http': - # print("Loading Image from Internet...") + print("Loading Image from Internet...") img2show, img = urlToImage(path) else: - # print("Loading Image from Local...") + print("Loading Image from Local...") img2show, img = loadImage(path) # Preprocessing the img according to VGG19 requirements img = tf.keras.applications.vgg19.preprocess_input(img) - return img2show, img @@ -190,7 +191,6 @@ def totalLoss(model, lossWeights, generateImage, contentFeatures, styleFeatures) # Computing Style Cost for every layer for generateStyle, combinationStyle in zip(styleFeatures, styleGenerateFeatures): styleCostValue += styleWeightPerLayer * styleCost(combinationStyle[0], generateStyle) - # Assigning the weights contentCostValue *= contentWeight @@ -198,7 +198,6 @@ def totalLoss(model, lossWeights, generateImage, contentFeatures, styleFeatures) # Computing the Total Loss totalLossValue = contentCostValue + styleCostValue - return totalLossValue, contentCostValue, styleCostValue @@ -207,7 +206,6 @@ def computeGrads(config): allLoss = totalLoss(**config) loss = allLoss[0] - return tape.gradient(loss, config['generateImage']), allLoss @@ -252,7 +250,8 @@ def runStyleTransfer(contentPath, SAVE_EVERY = 0, contentWeight = 1e3, styleWeight = 1e-2, - output_dirName = None): + output_dirName = None, + save_stats = False): # Importing the Model model = getModel() @@ -294,23 +293,22 @@ def runStyleTransfer(contentPath, normMeans = np.array([103.939, 116.779, 123.68]) - minVals = -normMeans - maxVals = 255 - normMeans + minVals = -normMeans + maxVals = 255 - normMeans # Creating Logs to use for Plotting Later # global contentCostLog, styleCostLog, totalCostLog contentCostLog, styleCostLog, totalCostLog = [], [], [] - if output_dirName: - PATH = os.path.join(os.curdir, 'outputs', output_dirName) + PATH = os.path.join(os.curdir, output_dirName) if not os.path.isdir(PATH): os.mkdir(PATH) os.chdir(PATH) - for iter in tqdm(range(iterations), leave=False): - # Computing the Grads and Loss + for iter in tqdm(range(iterations), leave=False): + # for iter in range(iterations): grads, allLoss = computeGrads(config) # Extracting different kinds of Losses @@ -339,13 +337,13 @@ def runStyleTransfer(contentPath, new = deprocessImage(generateImage.numpy()) cv2.imwrite(f'generateImage_{iter+1}.jpg', cv2.cvtColor(new, cv2.COLOR_BGR2RGB)) - - bestImage = deprocessImage(generateImage.numpy()) - cv2.imwrite(f'FINAL_OUTPUT.jpg', cv2.cvtColor(bestImage, cv2.COLOR_BGR2RGB)) - # Saving the numpy Arrays to plot later - np.save('contentLoss.npy', contentCostLog) - np.save('styleLoss.npy', styleCostLog) - np.save('totalCostLoss.npy', totalCostLog) + cv2.imwrite(f'output.jpg', cv2.cvtColor(bestImage, cv2.COLOR_BGR2RGB)) + + if save_stats: + # Saving the numpy Arrays to plot later + np.save('contentLoss.npy', contentCostLog) + np.save('styleLoss.npy', styleCostLog) + np.save('totalCostLoss.npy', totalCostLog) return bestImage, (contentCostLog, styleCostLog, totalCostLog) diff --git a/application.py b/application.py new file mode 100644 index 0000000..70cd6e8 --- /dev/null +++ b/application.py @@ -0,0 +1,88 @@ +from flask import Flask, render_template, request, redirect +import numpy as np +import joblib +import os, time, random +from PIL import Image +import numpy as np + +from __helpers__ import * + + +app = Flask(__name__) + +# Creating a user_file folder if not present in the working dir +if 'temp_user_files' not in os.listdir(): + os.mkdir('temp_user_files') +# temp_user_file : It'll contain the images uploaded by the user temporarily + +app.config["IMAGE_UPLOADS"] = os.path.join(os.getcwd(), 'temp_user_files') +home_dir = os.getcwd() + +# To DISABLE Caching +@app.after_request +def add_header(r): + """ + Add headers to both force latest IE rendering engine or Chrome Frame, + and also to cache the rendered page for 10 minutes. + """ + r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" + r.headers["Pragma"] = "no-cache" + r.headers["Expires"] = "0" + r.headers['Cache-Control'] = 'public, max-age=0' + return r + +# Defining the Home page +@app.route('/', methods=['GET', 'POST']) +def home(): + return render_template('index.html') + + +# Defining the Prediction page +@app.route('/output', methods=['GET', 'POST']) +def output(): + + if request.method == 'POST': + if request.form['submit'] == 'Do the magic!': + + # # Reading the POST request + content_img = request.files['img1name'] + style_img = request.files['img2name'] + iterations = int(request.form['iterations']) + print('Iterations :',iterations) + + # # Saving the Image file in local env + content_path = os.path.join(app.config["IMAGE_UPLOADS"], 'content_img.jpg') + style_path = os.path.join(app.config["IMAGE_UPLOADS"], 'style_img.jpg') + content_img.save(content_path) + style_img.save(style_path) + + # # Running Style Transfer + print('[INFO] Style Transfer Intializing..') + generatedImage, losses = runStyleTransfer(content_path, + style_path, + iterations = iterations, + SAVE_EVERY = 0, + contentWeight = 1, + styleWeight = 0.8, + output_dirName = 'static', + save_stats = False) + + + # Deleting the file from the database + os.remove(content_path) + os.remove(style_path) + + # Switching back to the main dir because Current dir is changed internally + os.chdir(home_dir) + print('[INFO] Output generated.') + return render_template('output.html') + + print('[INFO] Rendering Output') + return render_template('index.html') + + + +if __name__ == '__main__': + app.run(port=5555, debug=True) + +# int(random.random()*10000) \ No newline at end of file diff --git a/main_colab_notebook.ipynb b/main_colab_notebook.ipynb deleted file mode 100644 index fb42864..0000000 --- a/main_colab_notebook.ipynb +++ /dev/null @@ -1,756 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "main - NST", - "provenance": [], - "collapsed_sections": [], - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "NYb4w64K_a7r", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Uncomment the following code to mount the google drive\n", - "from google.colab import drive\n", - "drive.mount('/content/drive')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "roKFsgZS_VmJ", - "colab_type": "code", - "colab": {} - }, - "source": [ - "%tensorflow_version 1.15.0 # Defining which Tf version to use\n", - "import tensorflow as tf\n", - "import keras.backend as K\n", - "from keras.applications.vgg19 import VGG19, preprocess_input\n", - "from tensorflow.python.keras import models\n", - "from keras.models import Model\n", - "from keras.preprocessing import image\n", - "\n", - "from PIL import Image\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import time\n", - "import cv2\n", - "import os\n", - "import urllib\n", - "import statistics\n", - "from tqdm import tqdm_notebook as tqdm" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "f76I4l_B_b5M", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Enabling Eager Execution\n", - "tf.enable_eager_execution()\n", - "print(\"Eager Execution Initialized:\",tf.executing_eagerly())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0lOW4Vh9ktyY", - "colab_type": "text" - }, - "source": [ - "# Helper Functions" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "RYmdVNcLCaCD", - "colab_type": "text" - }, - "source": [ - "### Selecting the Feature Layers needed" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "FUg3eIQDBgnG", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Defining the Feature Layers we need respectively\n", - "styleLayers = ['block1_conv2', \n", - " 'block2_conv2', \n", - " 'block3_conv3', \n", - " 'block4_conv3', \n", - " 'block5_conv3']\n", - "\n", - "contentLayer = ['block3_conv2']\n", - "\n", - "\n", - "numContentLayers = len(contentLayer) # Number of Content Layers\n", - "numStyleLayers = len(styleLayers) # Number of Style Layers" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "VyrVfwX-CeKw", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Defining Function to import model (VGG19)\n", - "def getModel():\n", - "\n", - " # Loading Model from tf\n", - " model = tf.keras.applications.vgg19.VGG19(include_top=False, weights='imagenet')\n", - " model.trainable = False # Freezing to parameters\n", - "\n", - " # Features of the Respective Layers\n", - " contentFeatures = [model.get_layer(name).output for name in contentLayer]\n", - " styleFeatures = [model.get_layer(name).output for name in styleLayers]\n", - " \n", - " modelOutput = contentFeatures + styleFeatures\n", - "\n", - " return models.Model(model.input, modelOutput)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "GLOL1qbSDkDY", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Defining GRAM MATRIX\n", - "def gram(x):\n", - "\n", - " # number of channels\n", - " channels = int(x.shape[-1])\n", - " \n", - " # reshaping to channel first\n", - " a = tf.reshape(x, [-1, channels])\n", - " n = tf.shape(a)[0]\n", - " \n", - " # gram matrix\n", - " gram = tf.matmul(a, a, transpose_a=True)\n", - " \n", - " return gram / tf.cast(n, tf.float32)\n", - "\n", - "\n", - "# Defining CONTENT COST\n", - "def contentCost(contentFeatures, generateFeatures):\n", - " return tf.reduce_mean(tf.square(contentFeatures-generateFeatures))\n", - "\n", - "\n", - "# Defining STYLE COST\n", - "def styleCost(styleFeatures, generateFeatures):\n", - " styleGram = gram(styleFeatures)\n", - " return tf.reduce_mean(tf.square(styleGram - generateFeatures))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "_OHnNdN10-PE", - "colab_type": "text" - }, - "source": [ - "### Image Manipulations" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Vry1Gt1mEcnk", - "colab_type": "code", - "colab": {} - }, - "source": [ - "def getFeatures(content, style, model):\n", - " \n", - " # Defining the respective outputs from our model\n", - " contentOutputs = model(content)\n", - " styleOutputs = model(style)\n", - " \n", - " # Extracting out the different features from the model output\n", - " contentFeatures = [contentFeature[0] for contentFeature in contentOutputs[numStyleLayers:]]\n", - " styleFeatures = [styleFeature[0] for styleFeature in styleOutputs[:numStyleLayers]]\n", - "\n", - " return contentFeatures, styleFeatures\n", - "\n", - "\n", - "def loadImage(path_to_img):\n", - " max_dim = 512\n", - " if type(path_to_img) == str:\n", - " img2show = Image.open(path_to_img)\n", - " else:\n", - " img2show = path_to_img\n", - "\n", - " # long = max(img2show.size)\n", - " long = (img2show.size)\n", - "\n", - " scale = max_dim/long\n", - " img = img2show.resize((round(img2show.size[0]*scale), round(img2show.size[1]*scale)), Image.ANTIALIAS)\n", - " \n", - " img = image.img_to_array(img)\n", - " \n", - " # We need to broadcast the image array such that it has a batch dimension \n", - " img = np.expand_dims(img2show, axis=0)\n", - " return img2show, img\n", - " \n", - "\n", - "def urlToImage(url):\n", - " resp = urllib.request.urlopen(url)\n", - " img = np.asarray(bytearray(resp.read()), dtype='uint8')\n", - " img = cv2.imdecode(img, cv2.IMREAD_COLOR)\n", - " img2show = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n", - "\n", - " img = np.expand_dims(img2show, axis=0)\n", - " return img2show, img\n", - " \n", - "\n", - "def inputImageAndPreprocess(path):\n", - " # Loading the image and reshaping it according to VGG19 requirements.\n", - " if path[:4]=='http':\n", - " # print(\"Loading Image from Internet...\")\n", - " img2show, img = urlToImage(path)\n", - " else:\n", - " # print(\"Loading Image from Local...\")\n", - " img2show, img = loadImage(path)\n", - " \n", - " # Preprocessing the img according to VGG19 requirements\n", - " img = tf.keras.applications.vgg19.preprocess_input(img)\n", - "\n", - " return img2show, img\n", - "\n", - "\n", - "# Deprocessing Image to save locally\n", - "def deprocessImage(processed_img):\n", - " x = processed_img.copy()\n", - " if len(x.shape) == 4:\n", - " x = np.squeeze(x, 0)\n", - " assert len(x.shape) == 3, (\"Input to deprocess image must be an image of \"\n", - " \"dimension [1, height, width, channel] or [height, width, channel]\")\n", - " if len(x.shape) != 3:\n", - " raise ValueError(\"Invalid input to deprocessing image\")\n", - " \n", - " # perform the inverse of the preprocessiing step\n", - " x[:, :, 0] += 103.939\n", - " x[:, :, 1] += 116.779\n", - " x[:, :, 2] += 123.68\n", - " x = x[:, :, ::-1]\n", - "\n", - " x = np.clip(x, 0, 255).astype('uint8')\n", - " return x" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "G--g9kADOCuI", - "colab_type": "text" - }, - "source": [ - "### Computing the total Loss" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "U3bx7mzlonff", - "colab_type": "code", - "colab": {} - }, - "source": [ - "def totalLoss(model, lossWeights, generateImage, contentFeatures, styleFeatures):\n", - "\n", - " # Extracting the respective weights\n", - " contentWeight, styleWeight = lossWeights\n", - "\n", - " # Extracting the generate image features from the model\n", - " modelOutputs = model(generateImage)\n", - "\n", - " # Splitting the generate Features into different categories\n", - " contentGenerateFeatures = modelOutputs[numStyleLayers:]\n", - " styleGenerateFeatures = modelOutputs[:numStyleLayers]\n", - "\n", - " # Initializing all costs with 0\n", - " contentCostValue, styleCostValue = 0, 0\n", - "\n", - " # Defining partial weights\n", - " contentWeightPerLayer = 1.0 / float(numContentLayers)\n", - " styleWeightPerLayer = 1.0 / float(numStyleLayers)\n", - "\n", - " # Computing Content Cost\n", - " for generateContent, combinationContent in zip(contentFeatures, contentGenerateFeatures):\n", - " contentCostValue += contentWeightPerLayer * contentCost(combinationContent[0], generateContent)\n", - "\n", - " # Computing Style Cost for every layer\n", - " for generateStyle, combinationStyle in zip(styleFeatures, styleGenerateFeatures):\n", - " styleCostValue += styleWeightPerLayer * styleCost(combinationStyle[0], generateStyle)\n", - " \n", - "\n", - " # Assigning the weights\n", - " contentCostValue *= contentWeight\n", - " styleCostValue *= styleWeight\n", - "\n", - " # Computing the Total Loss\n", - " totalLossValue = contentCostValue + styleCostValue\n", - "\n", - " return totalLossValue, contentCostValue, styleCostValue" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "h5m_rbo5OGnU", - "colab_type": "text" - }, - "source": [ - "### Computing the Gradient Descent" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "QkuJHoGOtQkf", - "colab_type": "code", - "colab": {} - }, - "source": [ - "def computeGrads(config):\n", - " with tf.GradientTape() as tape:\n", - " allLoss = totalLoss(**config)\n", - "\n", - " loss = allLoss[0]\n", - "\n", - " return tape.gradient(loss, config['generateImage']), allLoss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "SBBVPtneLdxK", - "colab_type": "text" - }, - "source": [ - "### Time to get it all together" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "DWMyORWOuPhN", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Defining the MAIN TRAINING FUNCTION\n", - "def runStyleTransfer(contentPath,\n", - " stylePath,\n", - " iterations = 1000,\n", - " SAVE_EVERY = 0,\n", - " contentWeight = 1e3,\n", - " styleWeight = 1e-2,\n", - " output_dirName = None):\n", - " \n", - " # Importing the Model\n", - " model = getModel()\n", - " for layer in model.layers:\n", - " layer.trainable = False\n", - "\n", - " if type(contentPath) == str:\n", - " _ , contentImage = inputImageAndPreprocess(contentPath)\n", - " else:\n", - " contentImage = contentPath\n", - " \n", - " _ , styleImage = inputImageAndPreprocess(stylePath)\n", - " \n", - " # Extracting out the respective features from the model\n", - " contentFeatures, styleFeatures = getFeatures(contentImage, styleImage, model)\n", - " styleFeatures = [gram(styleFeature) for styleFeature in styleFeatures]\n", - "\n", - " # Creating the Generate Image\n", - " generateImage = contentImage\n", - " generateImage = tf.Variable(generateImage, dtype=tf.float32)\n", - "\n", - " # Defining the Adam Optimizer\n", - " optimizer = tf.train.AdamOptimizer(learning_rate=5, epsilon=1e-3)\n", - "\n", - " # Storing the best Image and Loss\n", - " bestLoss, bestImage = float('inf'), None\n", - "\n", - " # Zipping the Weights\n", - " lossWeights = (contentWeight, styleWeight)\n", - " \n", - " # Defining the Config File\n", - " config = {\n", - " 'model': model,\n", - " 'lossWeights': lossWeights,\n", - " 'generateImage': generateImage,\n", - " 'contentFeatures': contentFeatures,\n", - " 'styleFeatures': styleFeatures\n", - " }\n", - " \n", - " \n", - " normMeans = np.array([103.939, 116.779, 123.68])\n", - " minVals = -normMeans\n", - " maxVals = 255 - normMeans \n", - "\n", - " # Creating Logs to use for Plotting Later\n", - " global contentCostLog, styleCostLog, totalCostLog \n", - " contentCostLog, styleCostLog, totalCostLog = [], [], []\n", - "\n", - "\n", - " if output_dirName:\n", - " PATH = f'/content/drive/My Drive/Colab Notebooks/Neural Style Transfer/output/vids/{output_dirName}'\n", - " if not os.path.isdir(PATH):\n", - " os.mkdir(PATH)\n", - " os.chdir(PATH)\n", - "\n", - " for iter in tqdm(range(iterations), leave=False):\n", - "\n", - " # Computing the Grads and Loss\n", - " grads, allLoss = computeGrads(config)\n", - "\n", - " # Extracting different kinds of Losses\n", - " loss, contentLoss, styleLoss = allLoss\n", - " \n", - " # Saving the respective losses in respective lists for plotting\n", - " contentCostLog.append(contentLoss)\n", - " styleCostLog.append(styleLoss)\n", - " totalCostLog.append(loss)\n", - "\n", - " # Applying gradients to Generate Image\n", - " optimizer.apply_gradients([(grads, generateImage)])\n", - "\n", - " # Clipping the values of Generate Image from (-255, 255)\n", - " clipped = tf.clip_by_value(generateImage, minVals, maxVals)\n", - " generateImage.assign(clipped)\n", - "\n", - " # Updating the Best Image and Loss\n", - " if loss < bestLoss:\n", - " bestLoss = loss\n", - " bestImage = generateImage.numpy()\n", - "\n", - " # Saving the Generate Image\n", - " if SAVE_EVERY:\n", - " if iter % SAVE_EVERY == 0:\n", - " new = cv2.cvtColor(deprocessImage(generateImage.numpy()), cv2.COLOR_RGB2BGR)\n", - " cv2.imwrite(f'generateImage_{iter+1}.jpg', new)\n", - "\n", - " \n", - " if not SAVE_EVERY:\n", - " bestImage = deprocessImage(generateImage.numpy())\n", - " else:\n", - " # Saving the numpy Arrays to plot later\n", - " np.save('contentLoss.npy', contentCostLog)\n", - " np.save('styleLoss.npy', styleCostLog)\n", - " np.save('totalCostLoss.npy', totalCostLog)\n", - "\n", - " return bestImage, bestLoss, output_dirName\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hFMQ6znrMY3y", - "colab_type": "text" - }, - "source": [ - "## Visualizing our Content And Style Images" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "BpXligxdVBFZ", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Style Templates:\n", - "wave = 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ8LOCDfTvcJ_V4fBdtL3R_oQn7D9P96PPzJFCksdWeKHHhyfUZ'\n", - "seated_nude = 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ0ip7KMW5XB_qhU3cwBDDd1fjlogHfgOxw9gnVq2CqZdLwHgY3'\n", - "shinchan = 'https://pbs.twimg.com/profile_images/452516792426975232/rOQPTVq4_400x400.png'\n", - "\n", - "# PATH = '/content/drive/My Drive/Colab Notebooks/Neural Style Transfer/vids/surf/'\n", - "\n", - "# Enter the path of the respective Images\n", - "contentImagePath = wave\n", - "styleImagePath = seated_nude\n", - "\n", - "content, _ = inputImageAndPreprocess(contentImagePath)\n", - "style, _ = inputImageAndPreprocess(styleImagePath)\n", - "\n", - "plt.figure(figsize=(10, 10))\n", - "\n", - "plt.subplot(1, 2, 1)\n", - "plt.imshow(content)\n", - "plt.title('Content Image')\n", - "\n", - "plt.subplot(1, 2, 2)\n", - "plt.imshow(style)\n", - "plt.title('Style Image')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "117gi_T-MneQ", - "colab_type": "text" - }, - "source": [ - "# **Training**" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "wPGdWaG43zMD", - "colab_type": "code", - "colab": {} - }, - "source": [ - "ITERATIONS = 1\n", - "DIR_NAME = 'seated_nude'\n", - "\n", - "\n", - "bestImage, bestLoss, output_dirName = runStyleTransfer(contentImagePath,\n", - " styleImagePath,\n", - " iterations=ITERATIONS,\n", - " SAVE_EVERY = 0,\n", - " contentWeight = 1,\n", - " styleWeight= 0.8,\n", - " output_dirName = None)\n", - "\n", - "# Output Cleared for Fairness" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "XzkI-DB6M5Wj", - "colab_type": "text" - }, - "source": [ - "#### Visualizing the Best Image" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "ywRuBn7fHpkP", - "colab": {} - }, - "source": [ - "plt.figure(figsize=(10,10))\n", - "plt.imshow(bestImage)\n", - "plt.title('Generated Image')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "4BIqrewkNBxJ", - "colab_type": "text" - }, - "source": [ - "#### Plotting the Cost Functions" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "QpxrPjPH-AJ7", - "colab_type": "code", - "colab": {} - }, - "source": [ - "plt.figure(figsize=(23, 8))\n", - "plt.plot(totalCostLog, linewidth=3, label='total loss')\n", - "plt.plot(styleCostLog, linewidth=1, label='style loss')\n", - "plt.plot(contentCostLog, linewidth=2, label='content loss')\n", - "# plt.plot(learning_curve_tv, linewidth=2, label='total variation loss')\n", - "plt.title(\"Learning curve\")\n", - "plt.ylabel(\"error\")\n", - "plt.xlabel(\"epoch\")\n", - "plt.yscale(\"log\")\n", - "plt.legend()\n", - "plt.grid()\n", - "plt.show()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "f12hKz_q9LJa", - "colab_type": "text" - }, - "source": [ - "#Video Conversion" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "TsD-NPZavu9v", - "colab_type": "code", - "cellView": "form", - "colab": {} - }, - "source": [ - "#@title Parameters:\n", - "Video_path = \"/content/drive/My Drive/Colab Notebooks/Neural Style Transfer/vids/surf.mp4\" #@param {type:\"string\"}\n", - "\n", - "style_path = \"https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ8LOCDfTvcJ_V4fBdtL3R_oQn7D9P96PPzJFCksdWeKHHhyfUZ\" #@param {type:\"string\"}\n", - "\n", - "\n", - "fps_quality = \"Just show me the thing already\" #@param [\"Super Duper\", \"Fancier than Average\", \"Ya ok Whatever\", \"Just show me the thing already\"]\n", - "\n", - "style_quality = 100 #@param {type:\"slider\", min:100, max:1000, step:100}\n", - "\n", - "if fps_quality == 'Super Duper':\n", - " skip_frame_every = 1\n", - "elif fps_quality == 'Fancier than Average':\n", - " skip_frame_every = 3\n", - "elif fps_quality == 'Ya ok Whatever':\n", - " skip_frame_every = 6\n", - "else:\n", - " skip_frame_every = 10" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "_PMZLRMvT5V8", - "colab_type": "code", - "colab": {} - }, - "source": [ - "def extract_frames_out_of_the_video(vid_path):\n", - " cam = cv2.VideoCapture(vid_path)\n", - "\n", - " currentframe = 1\n", - " frames = []\n", - "\n", - " while(True): \n", - " # reading from frame \n", - " ret, frame = cam.read() \n", - " \n", - " if ret:\n", - " frame = np.expand_dims(frame, axis=0)\n", - " frames.append(frame.astype('float32'))\n", - " print(currentframe, end='\\r') \n", - " currentframe += 1\n", - " else: \n", - " break\n", - " print('Frames generated..!')\n", - " return frames" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "5KbvxNOzx3sf", - "colab_type": "code", - "colab": {} - }, - "source": [ - "VID_PATH = '/content/drive/My Drive/Colab Notebooks/Neural Style Transfer/vids/surf.mp4'\n", - "OUTPUT_DIR = '/content/drive/My Drive/Colab Notebooks/Neural Style Transfer/output/vids/'\n", - "OUTPUT_FILE_NAME = 'trying_aivayy'\n", - "\n", - "generated_frames = []\n", - "vid_frames = extract_frames_out_of_the_video(VID_PATH)\n", - "\n", - "for frame_number in tqdm(range(0, len(vid_frames), skip_frame_every)):\n", - "\n", - " content = vid_frames[frame_number]\n", - "\n", - " bestImage, bestLoss, output_dirName = runStyleTransfer(content,\n", - " style_path,\n", - " iterations=style_quality,\n", - " contentWeight = 1,\n", - " styleWeight= 0.8)\n", - " generated_frames.append(bestImage)\n", - " height, width, channels = bestImage.shape\n", - "\n", - "\n", - "print('Developing the Video')\n", - "out = cv2.VideoWriter(OUTPUT_DIR + OUTPUT_FILE_NAME + '.avi', cv2.VideoWriter_fourcc(*'DIVX'), 15, (width,height))\n", - "for i in (range(len(generated_frames))):\n", - " out.write(generated_frames[i])\n", - "out.release()\n", - "\n", - "print('Video Converted and Saved Succesfully!')" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/main_image.py b/main_image.py deleted file mode 100644 index 6a41e41..0000000 --- a/main_image.py +++ /dev/null @@ -1,64 +0,0 @@ -import matplotlib.pyplot as plt - -from __helpers__ import * - -################################################################### -# Few templates -wave = 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ8LOCDfTvcJ_V4fBdtL3R_oQn7D9P96PPzJFCksdWeKHHhyfUZ' -seated_nude = 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ0ip7KMW5XB_qhU3cwBDDd1fjlogHfgOxw9gnVq2CqZdLwHgY3' -shinchan = 'https://pbs.twimg.com/profile_images/452516792426975232/rOQPTVq4_400x400.png' -taj_mahal = 'https://thumbs-prod.si-cdn.com/Abm-e-V_cqdIqYDo_cXApagw8zI=/800x600/filters:no_upscale():focal(1471x1061:1472x1062)/https://public-media.si-cdn.com/filer/b6/30/b630b48b-7344-4661-9264-186b70531bdc/istock-478831658.jpg' -################################################################### - -STYLE_QUALITY = 500 # Iterations -DIR_NAME = 'seated_nude' # Set this to None if outputs are not required to be saved locally. - -contentImagePath = taj_mahal -styleImagePath = wave - -generatedImage, losses = runStyleTransfer(contentImagePath, - styleImagePath, - iterations = STYLE_QUALITY, - SAVE_EVERY = 0, - contentWeight = 1, - styleWeight = 0.8, - output_dirName = DIR_NAME) - - -contentCostLog, styleCostLog, totalCostLog = losses - -print('Plotting...') - -fig = plt.figure(constrained_layout=False, figsize=(5, 5)) -gs1 = fig.add_gridspec(nrows=2, ncols=3, left=0.005, right=0.48, wspace=0.05, hspace=0.01) - -fig.add_subplot(gs1[:-1, :]) -plt.imshow(generatedImage) -plt.axis('off') -plt.title('Generated Image') - -fig.add_subplot(gs1[-1, :-1]) -plt.imshow(inputImageAndPreprocess(contentImagePath)[0]) -plt.axis('off') -plt.title('Content Image') - -fig.add_subplot(gs1[-1, -1]) -plt.imshow(inputImageAndPreprocess(styleImagePath)[0]) -plt.axis('off') -plt.title('Style Image') - - - -plt.figure(figsize=(10, 4)) -plt.plot(totalCostLog, linewidth=3, label='total loss') -plt.plot(styleCostLog, linewidth=1, label='style loss') -plt.plot(contentCostLog, linewidth=2, label='content loss') -plt.title("Learning curve") -plt.ylabel("error") -plt.xlabel("epoch") -plt.yscale("log") -plt.legend() -plt.grid() -plt.show() - -print('All done yay!') diff --git a/main_video.py b/main_video.py deleted file mode 100644 index 7322b62..0000000 --- a/main_video.py +++ /dev/null @@ -1,50 +0,0 @@ -from __helpers__ import * - - -VIDEO_PATH = '' -STYLE_IMAGE_PATH = 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ8LOCDfTvcJ_V4fBdtL3R_oQn7D9P96PPzJFCksdWeKHHhyfUZ' - -FPS_QUALITY = 'low' -''' -high > original fps > slowest -medium > -low > bad fps > fastest -''' - -STYLE_QUALITY = 100 # Any integer in range (100, 1000) -''' -The more the STYLE_QUALITY, the more better every frame is stylized. -BUT, will take more time. -''' - -# Final Output video name -OUTPUT_FILE_NAME = 'trying_aivayy' - - - - -vid_frames = extract_frames_out_of_the_video(VIDEO_PATH) -generated_frames = [] - -for frame_number in tqdm(range(0, len(vid_frames), skip_frame_every(FPS_QUALITY))): - content = vid_frames[frame_number] - generated_image, _ = runStyleTransfer(content, - STYLE_IMAGE_PATH, - iterations=STYLE_QUALITY) - generated_frames.append(generated_image) - - -height, width, channels = generated_frames[0].shape - -PATH = os.path.join(os.curdir, 'outputs') -if not os.path.isdir(PATH): - os.mkdir(PATH) -os.chdir(PATH) - -print('Developing the Video...') -out = cv2.VideoWriter(OUTPUT_FILE_NAME + '.avi', cv2.VideoWriter_fourcc(*'DIVX'), 15, (width,height)) -for i in (range(len(generated_frames))): - out.write(generated_frames[i]) -out.release() - -print('Video Converted and Saved Succesfully!') diff --git a/neural_style_transfer_torch.ipynb b/neural_style_transfer_torch.ipynb deleted file mode 100644 index 7adfdf9..0000000 --- a/neural_style_transfer_torch.ipynb +++ /dev/null @@ -1,469 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "neural style transfer - torch", - "provenance": [], - "collapsed_sections": [], - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "jpE-RBdyWhlu", - "colab_type": "code", - "outputId": "79b8337f-802a-4a90-dac2-c003a580caab", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - } - }, - "source": [ - "import torch\n", - "import torchvision.models as models\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "import torch.optim as optim\n", - "\n", - "import urllib\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import cv2\n", - "# from google.colab.patches import cv2_imshow\n", - "\n", - "if torch.cuda.is_available():\n", - " device = torch.device('cuda:0')\n", - " running = 'GPU'\n", - "else:\n", - " device = torch.device('cpu')\n", - " running = 'CPU'\n", - "print(f'Running on : {running}')" - ], - "execution_count": 4, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Running on : GPU\n" - ], - "name": "stdout" - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "kaITuLhhF9e1", - "colab_type": "code", - "colab": {} - }, - "source": [ - "'''\n", - "THIS IS WHAT I HAVE TO DO:\n", - "\n", - "# 1) Get the VGG19 model.\n", - "# 2) Define the Content, Style and Total Loss Function, and also Gram Matrix.\n", - "# 3) Define a method to extract features from 'x' layer of the Network.\n", - "4) Create the Training Loop which will minimize the Total Loss function and update the values of the image.\n", - "\n", - "'''" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "EGoNFVofWrdK", - "colab_type": "code", - "outputId": "688aaa99-cb0b-4eb6-bab6-80d4090c6a78", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 286 - } - }, - "source": [ - "def urlToImage(url):\n", - " resp = urllib.request.urlopen(url)\n", - " img = np.asarray(bytearray(resp.read()), dtype='uint8')\n", - " img = cv2.imdecode(img, cv2.IMREAD_COLOR)\n", - " img2show = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n", - "\n", - " img = np.expand_dims(img2show, axis=0)\n", - " return img2show, img\n", - "\n", - "\n", - "\n", - "url = 'https://pbs.twimg.com/profile_images/452516792426975232/rOQPTVq4_400x400.png'\n", - "\n", - "img2show, img = urlToImage(url)\n", - "\n", - "# Reshaping to remove the batch size dimension so that can be plotted\n", - "img2show = img2show.reshape(400, 400, -1)\n", - "\n", - "# Reshaping to put the channels first as the torch network wants\n", - "img = np.rollaxis(img, 3, 1)\n", - "img = torch.tensor(img).float()\n", - "img.shape\n", - "\n", - "# # A small program to find the correct values for np.rollaxis \n", - "# for i in range(4):\n", - "# for j in range(4):\n", - "# new = np.rollaxis(img, i, j)\n", - "# if new.shape == (1, 3, 400, 400):\n", - "# print(i, j)\n", - "# break\n", - "\n", - "plt.imshow(img2show)\n", - "print(img2show.shape)" - ], - "execution_count": 9, - "outputs": [ - { - "output_type": "stream", - "text": [ - "(400, 400, 3)\n" - ], - "name": "stdout" - }, - { - "output_type": "display_data", - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQEAAAD8CAYAAAB3lxGOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0\ndHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOy9Sawk2Zrn9TvHZvPZ7xw3pox8mfVe\n1atqFXqqXsAChECAkGrX6t4wqEVvKLFhQcEGxKoXSAgJCVGLFvQCCjYtelGiGSTEhuquV/1qyDEy\n5ht39tndZrNzWJiZX783IjIjY3gZkeF/hYf7dTc3O25m53+++RNaa9ZYY40PF/KHHsAaa6zxw2JN\nAmus8YFjTQJrrPGBY00Ca6zxgWNNAmus8YFjTQJrrPGB462RgBDi3xBCfC2EuCeE+MO3dZw11ljj\n9SDeRpyAEMIA7gL/GvAU+DPg72itv3jjB1tjjTVeC29LEvg94J7W+oHWOgX+GPj9t3SsNdZY4zVg\nvqX97gMHK38/Bf7mizbe3NzUt2/ffktDWWONNQD+/M//fKC13rr6/tsige+EEOLvAX8P4ObNm/zy\nl7/8oYayxhofBIQQj5/3/ttSBw6BGyt/X6/eW0Jr/Uda619orX+xtfUMOa2xxhq/JrwtEvgz4BMh\nxEdCCBv428A/fkvHWmONNV4Db0Ud0FrnQog/AP4JYAD/QGv9+ds41hprrPF6eGs2Aa31nwB/8rb2\nv8Yaa7wZrCMG11jjA8eaBNZY4wPHmgTWWOMDx5oE1ljjA8eaBNZY4wPHmgTWWOMDx5oE1ljjA8ea\nBNZY4wPHmgTWWOMDx5oE1ljjA8eaBNZY4wPHmgTWWOMDx5oE1ljjA8eaBNZY4wPHmgTWWOMDx5oE\n1ljjA8eaBN5TvI1+Eb9OvO/j/zHhB6s2vMbrQQiBUgqtNYVSoDWU/wC9nGRaa9AaXW1bv6er96o3\n6m9dPQpCCBArz1IiygEgqnEsPy/fhvKT6nUFDUJKDEMi5cX2a/zweC0SEEI8AuZAAeRa618IIfrA\n/wLcBh4Bf0trPX69Ya7xPOR5QZ7nRHGCKvJysmtNoQq01qiioCgKdJ5TVA+lFUWWo/LqoQp0tf0z\nEAIhDaRpIU0TaVkIw8A0DIQQGEJgmCbSMMrPhUQIkEKCLLcpqaIkJ8excRwHx7FYc8C7gzchCfwr\n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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "FgAo9QtRG5xy", - "colab_type": "text" - }, - "source": [ - "## Step 1 | Get Model" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "SN4n-p5B-8LG", - "colab_type": "code", - "outputId": "4f427f8f-2f4d-4cfc-80ac-a2d44fbd83ec", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 88 - } - }, - "source": [ - "# Define the model\n", - "model = models.vgg19(pretrained=True)\n", - "print('Model Loaded!')" - ], - "execution_count": 2, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Downloading: \"https://download.pytorch.org/models/vgg19-dcbb9e9d.pth\" to /root/.cache/torch/checkpoints/vgg19-dcbb9e9d.pth\n", - "100%|██████████| 548M/548M [00:03<00:00, 184MB/s]\n" - ], - "name": "stderr" - }, - { - "output_type": "stream", - "text": [ - "Model Loaded!\n" - ], - "name": "stdout" - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "a86u0RyOAe8P", - "colab_type": "text" - }, - "source": [ - "## Step 2 | Define the Loss Functions" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "d_nHQODUHKpn", - "colab_type": "code", - "colab": {} - }, - "source": [ - "# Defining the Gram Matrix\n", - "def gram(x):\n", - " pass # ---------------------------------------------------------------------------------------------- need to complete this\n", - "\n", - "\n", - "# Defining the Content Loss Function\n", - "def content_loss(contentFeatures, generatedFeatures):\n", - " 'contentFeatures, generatedFeatures --> tensors'\n", - " loss = torch.mean((contentFeatures[0] - generatedFeatures[0])**2)\n", - " return loss\n", - "\n", - "\n", - "# Defining the Style Loss Function\n", - "def style_loss(styleFeatures, generatedFeatures):\n", - " 'styleFeatures, generatedFeatures --> tensors'\n", - " \n", - " # Extracting the Gram matrix\n", - " styleGram = gram(styleFeatures)\n", - "\n", - " loss = torch.mean((styleFeatures - generatedFeatures)**2)\n", - " return loss\n", - "\n", - "\n", - "# Defining the Total Loss Function\n", - "def total_loss(loss_weights, generateImage, content_features, style_features):\n", - "\n", - " # Extracting the respective weights\n", - " content_weight, style_weight = loss_weights\n", - "\n", - " # Extracting the generate image features from the model\n", - " generate_outputs = get_generate_features(generateImage)\n", - "\n", - " # Splitting the generate Features into different categories\n", - " generate_content_features = generate_outputs[0]\n", - " generate_style_features = generate_outputs[1:]\n", - "\n", - " # Initializing all costs with 0\n", - " content_cost_value, style_cost_value = 0, 0\n", - "\n", - " # Defining partial weights\n", - " # contentWeightPerLayer = 1.0 / float(numContentLayers)\n", - " # styleWeightPerLayer = 1.0 / float(numStyleLayers)\n", - "\n", - " # Computing Content Cost\n", - " content_cost_value += content_loss(content_features, generate_content_features)\n", - "\n", - " # Computing Style Cost for every layer\n", - " # for i in range(len(style_features)):\n", - " # style_cost_value += style_loss(style_features[i], generate_style_features[i])\n", - " \n", - "\n", - " # Assigning the weights\n", - " content_cost_value *= content_weight\n", - " # style_cost_value *= style_weight\n", - "\n", - " # Computing the Total Loss\n", - " # total_loss_value = content_cost_value + style_cost_value\n", - " total_loss_value = content_cost_value\n", - "\n", - " # return total_loss_value, content_cost_value, style_cost_value\n", - " return total_loss_value, content_cost_value\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "_Zx-6dAHBnsC", - "colab_type": "text" - }, - "source": [ - "## Step 3 | Feature Extraction" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "HTuFQO3x5AOA", - "colab_type": "code", - "colab": {} - }, - "source": [ - "def get_features(input_img, type_of_feature):\n", - " '''\n", - " >> A function that return the features of the 'input_img'.\n", - " type_of_feature --> content/style\n", - " '''\n", - "\n", - " if type_of_feature == 'content':\n", - " layers = [12]\n", - " else:\n", - " layers = [2, 7, 14, 23, 32]\n", - " \n", - " outputs= []\n", - " def hook(module, input, output):\n", - " outputs.append(output)\n", - "\n", - " # Creating a dictionary containing the children of the layers\n", - " features = {}\n", - " for idx, layer_num in enumerate(layers):\n", - " features['style_' + str(idx)] = list(model.children())[0][layer_num]\n", - "\n", - " # Hooking the network to get the output of every layer in the features dict.\n", - " for i in range(len(layers)):\n", - " features['style_' + str(i)].register_forward_hook(hook)\n", - " \n", - " # Passing the image through the network\n", - " final_output_which_is_not_needed = model(input_img)\n", - " \n", - " # Returning the features\n", - " return outputs\n", - "\n", - "\n", - "\n", - "def get_generate_features(input_img):\n", - " '''\n", - " >> A function that returnes the content and style features of the 'input_img'.\n", - " '''\n", - " # Extracting the respective features\n", - " content_features = get_features(input_img, 'content')\n", - " style_features = get_features(input_img, 'style')\n", - "\n", - " return content_features, style_features" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "NSYrNlVq_FzT", - "colab_type": "code", - "outputId": "e2cca850-e38a-4322-fa59-68210bca0eb3", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - } - }, - "source": [ - "# This is the layer of which the output is needed.\n", - "LAYER_NUM = 12\n", - "\n", - "x = get_layer(model, LAYER_NUM)\n", - "x.shape" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "torch.Size([1, 256, 100, 100])" - ] - }, - "metadata": { - "tags": [] - }, - "execution_count": 28 - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "faS-bHuIFfIB", - "colab_type": "text" - }, - "source": [ - "## Step 4 | Training Loop" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "6b4ZgHlQFfK1", - "colab_type": "code", - "colab": {} - }, - "source": [ - "def run_style_transfer(content_image, style_image, content_weight, style_weight, EPOCHS=1000):\n", - "\n", - " # Loading the VGG19 model\n", - " model = models.vgg19(pretrained=True)\n", - " print('Model Loaded!')\n", - "\n", - " # Extracting the content and style features\n", - " content_features = get_features(content_image, 'content')\n", - " style_features = get_features(style_image , 'style')\n", - "\n", - " # Creating the generate Image\n", - " generate_image = content_image\n", - "\n", - " # Defining the optimizer\n", - " optimizer = optim.Adam(model.parameters(), lr=5)\n", - "\n", - " # Storing the best Image and Loss\n", - " best_loss, best_image = float('inf'), None\n", - "\n", - " # Zipping the Weights\n", - " loss_weights = (content_weight, style_weight)\n", - "\n", - " for iter in range(EPOCHS):\n", - "\n", - " model.zero_grad()\n", - "\n", - " # Computing the outputs and thus, Total Loss\n", - " totalLoss = total_loss(loss_weights, generate_image, content_features, style_features)\n", - "\n", - " print(totalLoss)\n", - " break\n", - "\n", - "\n", - " " - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "0VYpSTKiFp-H", - "colab_type": "code", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 51 - }, - "outputId": "db038fd6-f67a-497c-b9ae-231889406c69" - }, - "source": [ - "run_style_transfer(img, img, 0.7, 0.4)" - ], - "execution_count": 30, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Model Loaded!\n", - "(tensor(0., grad_fn=), tensor(0., grad_fn=))\n" - ], - "name": "stdout" - } - ] - } - ] -} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..27ba8da --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +certifi==2020.6.20 +click==7.1.2 +Flask==1.1.2 +itsdangerous==1.1.0 +Jinja2==2.11.2 +joblib==0.17.0 +MarkupSafe==1.1.1 +numpy==1.18.5 +Pillow==8.0.1 +tensorflow-gpu==2.2.0 +keras==2.4.3 +opencv-python==4.4.0.42 diff --git a/static/elements/back-block.gif b/static/elements/back-block.gif new file mode 100644 index 0000000..c68e463 Binary files /dev/null and b/static/elements/back-block.gif differ diff --git a/static/elements/banner.jpg b/static/elements/banner.jpg new file mode 100644 index 0000000..977448d Binary files /dev/null and b/static/elements/banner.jpg differ diff --git a/static/elements/banner.psd b/static/elements/banner.psd new file mode 100644 index 0000000..aa21da7 Binary files /dev/null and b/static/elements/banner.psd differ diff --git a/static/elements/loading.gif b/static/elements/loading.gif new file mode 100644 index 0000000..1e2508d Binary files /dev/null and b/static/elements/loading.gif differ diff --git a/static/elements/output_banner.jpg b/static/elements/output_banner.jpg new file mode 100644 index 0000000..f8855e5 Binary files /dev/null and b/static/elements/output_banner.jpg differ diff --git a/static/elements/spiral.gif b/static/elements/spiral.gif new file mode 100644 index 0000000..fc2c927 Binary files /dev/null and b/static/elements/spiral.gif differ diff --git a/static/index.js b/static/index.js new file mode 100644 index 0000000..070d616 --- /dev/null +++ b/static/index.js @@ -0,0 +1,29 @@ +// To show the image // + +function readURL(input, tag) { + if (input.files && input.files[0]) { + var reader = new FileReader(); + + reader.onload = function (e) { + $(tag).attr('src', e.target.result); + } + + reader.readAsDataURL(input.files[0]); // convert to base64 string + } +} + + +function onButtonClick(div, div2){ + document.getElementById(div).className="show"; + document.getElementById(div2).className="hide"; + +} + + +$("#img1name").change(function () { + readURL(this, '#img1'); +}); + +$("#img2name").change(function () { + readURL(this, '#img2'); +}); \ No newline at end of file diff --git a/static/output.jpg b/static/output.jpg new file mode 100644 index 0000000..03b3870 Binary files /dev/null and b/static/output.jpg differ diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..6560b79 --- /dev/null +++ b/static/styles.css @@ -0,0 +1,226 @@ +h1 { + color: white; + text-align: center; + font-size: 150px; + font-family: "Montserrat", sans-serif; + margin-bottom: 40px; + margin-top: 10px; +} + +h3 { + color: white; + text-align: center; + font-size: 25px; + font-family: "Montserrat", sans-serif; +} + +label { + color: white; + font-family: "Montserrat", sans-serif; +} + +body { + background-image: url('elements/back-block.gif'); + background-size: 150px; + background-color: #222222; + padding: 0; + margin: 0; +} + + +/* Image properties */ +.imtip { + position: absolute; + bottom: 0; + right: 0; +} + +.input_img { + max-width: 500px; + max-height: 500px; + border: 10px white solid; +} + +/* +.banner{ + max-width: 500px; + max-height: 500px; + border: none; +} */ + + +input[type=submit] { + background-color: transparent; + color: white; + padding: 16px 0px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + font-family: "Montserrat", sans-serif; + margin: 4px 2px; + transition-duration: 0.4s; + cursor: pointer; + border: 5px solid #FFC300; + width: 200px; +} + +input[type=submit]:hover { + background-color: #FFC300; + color: black; +} + +.center { + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; +} + +/* all css code for file uploader */ + + +.hide { + display: none; +} + +.show { + display: block; + width: 80px; +} + +#output_img { + width: 1000px; + height: auto; + border-image: url(http://placekitten.com/100/100) 25% round; + /* border: 2px solid #FFC300; */ + +} + +/* .out_img { + +} */ + +.file-upload { + display: block; + text-align: center; + font-family: "Montserrat", sans-serif; + font-size: 12px; + margin: 0 0 20px 0; + padding: 0; + width: 100%; + background-color: transparent; + transition-duration: 0.4s; + +} + +.file-upload .file-select { + display: block; + border: 2px solid #FFC300; + color: white; + cursor: pointer; + height: 40px; + width: 100%; + line-height: 40px; + text-align: center; + background: transparent; + overflow: hidden; + position: relative; +} + + +.file-upload .file-select .file-select-button { + background: transparent; + padding: 0 10px; + display: inline-block; + height: 40px; + line-height: 40px; +} + +.file-upload .file-select .file-select-name { + line-height: 40px; + display: inline-block; + padding: 0 10px; +} + +.file-upload .file-select:hover { + border-color: #FFC300; + transition: all .2s ease-in-out; + -moz-transition: all .2s ease-in-out; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; +} + +.file-upload .file-select:hover .file-select-button { + background: #FFC300; + color: black; + width: 100%; + text-align: center; + transition: all .2s ease-in-out; + -moz-transition: all .2s ease-in-out; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; +} + +.file-upload.active .file-select { + border-color: #3fa46a; + transition: all .2s ease-in-out; + -moz-transition: all .2s ease-in-out; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; +} + +.file-upload.active .file-select .file-select-button { + background: #3fa46a; + color: #FFFFFF; + transition: all .2s ease-in-out; + -moz-transition: all .2s ease-in-out; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; +} + +.file-upload .file-select input[type=file] { + z-index: 100; + cursor: pointer; + position: absolute; + height: 100%; + width: 100%; + top: 0; + left: 0; + opacity: 0; + filter: alpha(opacity=0); +} + +.file-upload .file-select.file-select-disabled { + opacity: 0.65; +} + +.file-upload .file-select.file-select-disabled:hover { + cursor: default; + display: block; + border: 2px solid #dce4ec; + color: #34495e; + cursor: pointer; + height: 40px; + line-height: 40px; + margin-top: 5px; + text-align: left; + background: #FFFFFF; + overflow: hidden; + position: relative; +} + +.file-upload .file-select.file-select-disabled:hover .file-select-button { + background: #dce4ec; + color: #666666; + padding: 0 10px; + display: inline-block; + height: 40px; + line-height: 40px; +} + +.file-upload .file-select.file-select-disabled:hover .file-select-name { + line-height: 40px; + display: inline-block; + padding: 0 10px; +} \ No newline at end of file diff --git a/temp_user_files/don't delete.txt b/temp_user_files/don't delete.txt new file mode 100644 index 0000000..08778d7 --- /dev/null +++ b/temp_user_files/don't delete.txt @@ -0,0 +1 @@ +{\rtf1} \ No newline at end of file diff --git a/temp_user_files/readme.txt b/temp_user_files/readme.txt new file mode 100644 index 0000000..7699aab --- /dev/null +++ b/temp_user_files/readme.txt @@ -0,0 +1,2 @@ +User inputs will be saved here temporarily. +DO NOT DELETE THIS FOLDER. \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..3bffc25 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,79 @@ + + + +

 

+

+ + + + + Style Transfer + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+

Select CONTENT Image

+
+

Select STYLE Image

+
+
+
+
Choose File
+ + +
+
+ +
+
+ +
+
Choose File
+ + +
+
+
+
+ +

Style Quality 

+ + + + + +





+ + +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/templates/output.html b/templates/output.html new file mode 100644 index 0000000..ee475ca --- /dev/null +++ b/templates/output.html @@ -0,0 +1,34 @@ + + + + Style Transfer + + + + + + +

Isn't this just amazing??

+ + +
+

+ +
+ + +
+



+
+ +
+
+ \ No newline at end of file diff --git a/templates/output_banner.jpg b/templates/output_banner.jpg new file mode 100644 index 0000000..f8855e5 Binary files /dev/null and b/templates/output_banner.jpg differ