├── 1530306239.4496286.jpg ├── 1530307378.0300457.jpg ├── 1530309076.6533568.jpg ├── 1530311919.6497054.jpg ├── 1530443960.324053.jpg ├── 1530447451.3361306.jpg ├── 1530451563.9425378.jpg ├── 1530465237.4014776.jpg ├── 1530466662.019381.jpg ├── 1530481484.5429235.jpg ├── 1530484380.9665449.jpg ├── 1530566920.106656.jpg ├── 1530569761.9059289.jpg ├── 1530617762.7514386.jpg ├── 1530620345.9328907.jpg ├── README.md ├── __pycache__ ├── content_model.cpython-36.pyc ├── load_images.cpython-36.pyc ├── style_model.cpython-36.pyc └── utils.cpython-36.pyc ├── content ├── 02ceb046-ea83-4a45-ab7d-70af4a431176.jpg ├── 12400538_1732364596994642_3326465760914094542_n.jpg ├── 34988223_225164844977597_7441812000381861888_n.jpg ├── 614507060.jpg ├── 687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg ├── 6a00d8341bf98153ef01630203bc13970d.jpg ├── Brent-Clark-500x500.jpg ├── Chester.jpg ├── Julien_Lamour_shoot_the_land_shoot_the_frame_1-500x500.jpg ├── Sander_Grefte_shoot_the_land_shoot_the_frame_3-500x500.jpg ├── https _blogs-images.forbes.com_annabel_files_2018_02_Louisville_Skyline-1200x801.jpg ├── ledger-joker.jpg ├── pittsburgh_water_front_panorama-500x500.jpg ├── prattay.jpg ├── space-business-2.jpg └── tumblr_n0y85jDC471raw451o1_500-8343.jpg ├── content_model.py ├── load_images.py ├── photo_stylist.py ├── result ├── 1530306239.1840756.jpg ├── 1530307377.779925.jpg ├── 1530309076.0679188.jpg ├── 1530311919.316769.jpg ├── 1530443959.7306142.jpg ├── 1530447450.6487007.jpg ├── 1530449765.778833.jpg ├── 1530451563.3917222.jpg ├── 1530465236.4173527.jpg ├── 1530466661.53521.jpg ├── 1530479192.691439.jpg ├── 1530481484.1835425.jpg ├── 1530484380.669741.jpg ├── 1530566919.4661949.jpg ├── 1530569761.2654958.jpg ├── 1530617761.3455205.jpg └── 1530620345.2455604.jpg ├── style ├── 1280px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg ├── 3584389a7c92328a8f586eddea973e3f.jpg ├── 500x500.jpg ├── 64879447-original-abstract-art-contemporary-digital-painting-portrait-of-the-man-face-with-orange-hair-like-a.jpg ├── 6970631088_f8a396cc6a.jpg ├── Color-mosaic-vector-background-set-12-1.jpg ├── Nubula-I-sml-500x500.jpg ├── best-ideas-about-mosaic-art-on-mosaic-mosaics-and-picture-of-a-mosaic.jpg ├── iStock-546424192.jpg └── landscape-photography-art-by-hidenobu-suzuki-1.jpg ├── style_model.py └── utils.py /1530306239.4496286.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530306239.4496286.jpg -------------------------------------------------------------------------------- /1530307378.0300457.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530307378.0300457.jpg -------------------------------------------------------------------------------- /1530309076.6533568.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530309076.6533568.jpg -------------------------------------------------------------------------------- /1530311919.6497054.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530311919.6497054.jpg -------------------------------------------------------------------------------- /1530443960.324053.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530443960.324053.jpg -------------------------------------------------------------------------------- /1530447451.3361306.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530447451.3361306.jpg -------------------------------------------------------------------------------- /1530451563.9425378.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530451563.9425378.jpg -------------------------------------------------------------------------------- /1530465237.4014776.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530465237.4014776.jpg -------------------------------------------------------------------------------- /1530466662.019381.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530466662.019381.jpg -------------------------------------------------------------------------------- /1530481484.5429235.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530481484.5429235.jpg -------------------------------------------------------------------------------- /1530484380.9665449.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530484380.9665449.jpg -------------------------------------------------------------------------------- /1530566920.106656.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530566920.106656.jpg -------------------------------------------------------------------------------- /1530569761.9059289.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530569761.9059289.jpg -------------------------------------------------------------------------------- /1530617762.7514386.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530617762.7514386.jpg -------------------------------------------------------------------------------- /1530620345.9328907.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/1530620345.9328907.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Photo Stylist 2 | Stylizing yours photos using neural style transfer. 3 | 4 | ## Huge thanks to The Lazy Programmer without whose Udemy course this project would have not been possible. 5 | 6 | ## Outcome 7 | Watch it here. 8 | 9 | ## Requirements 10 | 0. Python 3.x 11 | 1. Tensorflow 1.5 12 | 2. Keras 13 | 3. OpenCV 3.4 14 | 4. A good grasp over the above 5 topics along with neural networks. Refer to the internet if you have problems with those. I myself am just a begineer in those. 15 | 5. A good CPU (preferably with a GPU). 16 | 6. Patience.... A lot of it. 17 | 18 | ## How to use 19 | Using this repo is very easy. First put your content and style images in the content and syle folder respectively. Then all you have to do is run the photo_stylist.py file. 20 | 21 | python photo_stylist.py 22 | 23 | You will be asked to select the content image from the content folder and the style image from the style folder. After selecting them you are good to go. You can give the optional parameters if you wish or just press enter to give the default values. 24 | 25 | ## Limitations 26 | I don't know if this exactly qualifies as a limitation but I am stil going to put it here. Since neural style tranfer is a resource intensive task, having a good CPU with a good GPU is highly recommended. In my Asus A541UJ which has a NVidia 920M graphics card, 4 GB RAM and Intel Core i3 2GHz processor any content image bigger than 500x500 px crashed the program due to non memory allocation. I don't know about any other specifications though. -------------------------------------------------------------------------------- /__pycache__/content_model.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/__pycache__/content_model.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/load_images.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/__pycache__/load_images.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/style_model.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/__pycache__/style_model.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /content/02ceb046-ea83-4a45-ab7d-70af4a431176.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/02ceb046-ea83-4a45-ab7d-70af4a431176.jpg -------------------------------------------------------------------------------- /content/12400538_1732364596994642_3326465760914094542_n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/12400538_1732364596994642_3326465760914094542_n.jpg -------------------------------------------------------------------------------- /content/34988223_225164844977597_7441812000381861888_n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/34988223_225164844977597_7441812000381861888_n.jpg -------------------------------------------------------------------------------- /content/614507060.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/614507060.jpg -------------------------------------------------------------------------------- /content/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg -------------------------------------------------------------------------------- /content/6a00d8341bf98153ef01630203bc13970d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/6a00d8341bf98153ef01630203bc13970d.jpg -------------------------------------------------------------------------------- /content/Brent-Clark-500x500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/Brent-Clark-500x500.jpg -------------------------------------------------------------------------------- /content/Chester.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/Chester.jpg -------------------------------------------------------------------------------- /content/Julien_Lamour_shoot_the_land_shoot_the_frame_1-500x500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/Julien_Lamour_shoot_the_land_shoot_the_frame_1-500x500.jpg -------------------------------------------------------------------------------- /content/Sander_Grefte_shoot_the_land_shoot_the_frame_3-500x500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/Sander_Grefte_shoot_the_land_shoot_the_frame_3-500x500.jpg -------------------------------------------------------------------------------- /content/https _blogs-images.forbes.com_annabel_files_2018_02_Louisville_Skyline-1200x801.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/https _blogs-images.forbes.com_annabel_files_2018_02_Louisville_Skyline-1200x801.jpg -------------------------------------------------------------------------------- /content/ledger-joker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/ledger-joker.jpg -------------------------------------------------------------------------------- /content/pittsburgh_water_front_panorama-500x500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/pittsburgh_water_front_panorama-500x500.jpg -------------------------------------------------------------------------------- /content/prattay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/prattay.jpg -------------------------------------------------------------------------------- /content/space-business-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/space-business-2.jpg -------------------------------------------------------------------------------- /content/tumblr_n0y85jDC471raw451o1_500-8343.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/content/tumblr_n0y85jDC471raw451o1_500-8343.jpg -------------------------------------------------------------------------------- /content_model.py: -------------------------------------------------------------------------------- 1 | from keras.layers import MaxPooling2D, AveragePooling2D, Conv2D 2 | from keras.models import Sequential 3 | import numpy as np 4 | import keras.backend as K 5 | import cv2 6 | from utils import VGG16_AvgPool, load_and_preprocess_content, minimize_loss, unpreprocess, scale_img 7 | 8 | def VGG16_AvgPool_CutOff(shape, num_conv): 9 | if num_conv < 1 or num_conv > 13: 10 | return None 11 | model = VGG16_AvgPool(shape) 12 | n = 0 13 | new_model = Sequential() 14 | for layer in model.layers: 15 | if layer.__class__ == Conv2D: 16 | n+=1 17 | new_model.add(layer) 18 | if n >= num_conv: 19 | break 20 | del model 21 | return new_model 22 | 23 | def main(): 24 | img = load_and_preprocess_content() 25 | shape = img.shape[1:] 26 | content_model = VGG16_AvgPool_CutOff(shape, 10) 27 | target = K.variable(content_model.predict(img)) 28 | 29 | mean_squared_loss = K.mean(K.square(target-content_model.output)) 30 | gradients = K.gradients(mean_squared_loss, content_model.input) 31 | get_loss_grads = K.function(inputs=[content_model.input], outputs=[mean_squared_loss]+gradients) 32 | 33 | def get_loss_grads_wrapper(x): 34 | l, g = get_loss_grads([x.reshape(img.shape)]) 35 | return l.astype(np.float64), g.flatten().astype(np.float64) 36 | 37 | img = minimize_loss(get_loss_grads_wrapper, 10, shape) 38 | final_img = img.reshape(*shape) 39 | final_img = unpreprocess(final_img) 40 | final_img = scale_img(final_img) 41 | cv2.imshow('final_img', final_img) 42 | cv2.waitKey(0) 43 | -------------------------------------------------------------------------------- /load_images.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import os 3 | import glob 4 | import numpy as np 5 | 6 | CONTENT_DIR = "content/*.jpg" 7 | STYLE_DIR = "style/*.jpg" 8 | 9 | if os.name == 'nt': 10 | clear = 'cls' 11 | else: 12 | clear = 'clear' 13 | 14 | def load_content_image(shape=None): 15 | while True: 16 | os.system(clear) 17 | print("Select content image") 18 | print("--------------------") 19 | content_dir_files = glob.glob(CONTENT_DIR) 20 | for i, file in enumerate(glob.glob(CONTENT_DIR)): 21 | print("[%d]. %s" %(i, file)) 22 | print('\n') 23 | 24 | choice = int(input('Enter your choice number: ')) 25 | if choice < 0 or choice > len(content_dir_files)-1: 26 | input("Choice must be >= 0 and <=%d. Press enter to continue"%(len(content_dir_files)-1,)) 27 | continue 28 | 29 | content_image = cv2.imread(content_dir_files[choice]) 30 | content_image = cv2.cvtColor(content_image, cv2.COLOR_BGR2RGB) 31 | content_image = content_image.astype(np.float64) 32 | if content_image.shape[0] * content_image.shape[1] > 500*500: 33 | if shape != None: 34 | content_image = cv2.resize(content_image, (shape[1], shape[0])) 35 | else: 36 | if abs(content_image.shape[0]-content_image.shape[1]) > 50: 37 | content_image = cv2.resize(content_image, None, fx=0.5, fy=0.5) 38 | else: 39 | content_image = cv2.resize(content_image, (500, 500)) 40 | break 41 | return content_image 42 | 43 | def load_style_image(shape=None): 44 | while True: 45 | os.system(clear) 46 | print("Select style image") 47 | print("------------------") 48 | style_dir_files = glob.glob(STYLE_DIR) 49 | for i, file in enumerate(glob.glob(STYLE_DIR)): 50 | print("[%d]. %s" %(i, file)) 51 | print('\n') 52 | 53 | choice = int(input('Enter your choice number: ')) 54 | if choice < 0 or choice > len(style_dir_files)-1: 55 | input("Choice must be >= 0 and <=%d. Press enter to continue"%(len(style_dir_files)-1,)) 56 | continue 57 | 58 | style_image = cv2.imread(style_dir_files[choice]) 59 | style_image = cv2.cvtColor(style_image, cv2.COLOR_BGR2RGB) 60 | style_image = style_image.astype(np.float64) 61 | if shape != None: 62 | style_image = cv2.resize(style_image, (shape[1], shape[0])) 63 | else: 64 | style_image = cv2.resize(style_image, None, fx=0.5, fy=0.5) 65 | break 66 | return style_image 67 | -------------------------------------------------------------------------------- /photo_stylist.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from keras.models import Model 3 | from keras.layers import Conv2D 4 | import keras.backend as K 5 | from scipy.optimize import fmin_l_bfgs_b 6 | import cv2 7 | from utils import minimize_loss, load_and_preprocess_style, load_and_preprocess_content, VGG16_AvgPool, unpreprocess, scale_img 8 | from style_model import style_loss 9 | from content_model import VGG16_AvgPool_CutOff 10 | import time 11 | import sys, os 12 | 13 | if os.name == 'nt': 14 | clear = 'cls' 15 | else: 16 | clear = 'clear' 17 | 18 | content_image = load_and_preprocess_content(shape=None) 19 | shape = content_image.shape[1:] 20 | h, w = content_image.shape[1:3] 21 | style_image = load_and_preprocess_style(shape=(h, w)) 22 | 23 | os.system(clear) 24 | print('Parameters') 25 | print('----------') 26 | epochs = input('Enter number of epochs (default 20): ') 27 | if epochs.strip() == '': 28 | epochs = 20 29 | else: 30 | epochs = int(epochs) 31 | 32 | conv_n = input('Enter number of conv layers to use. Must be between 1 and 13 both inclusive (default 10): ') 33 | if conv_n.strip() == '': 34 | conv_n = 10 35 | else: 36 | conv_n = int(conv_n) 37 | 38 | weights = input('Enter weights (default [1,1,1,1,1,1,1,1,1,1,1,1,1]): ') 39 | if weights.strip() == '': 40 | weights = [1]*13 41 | else: 42 | weights = eval(weights) 43 | 44 | 45 | vgg = VGG16_AvgPool(shape) 46 | vgg.summary() 47 | conv_layers = [0,1,2,4,5,7,8,9,11,12,13,15,16,17] 48 | content_model = Model(vgg.input, vgg.layers[conv_layers[conv_n]].get_output_at(0)) 49 | content_target = K.variable(content_model.predict(content_image)) 50 | 51 | symbolic_conv_outputs = [layer.get_output_at(1) for layer in vgg.layers if layer.__class__ == Conv2D] 52 | style_model = Model(vgg.input, symbolic_conv_outputs) 53 | style_outputs = [K.variable(y) for y in style_model.predict(style_image)] 54 | 55 | loss = K.mean(K.square(content_target-content_model.output)) 56 | for w, symbolic, actual in zip(weights, symbolic_conv_outputs, style_outputs): 57 | loss += w*style_loss(symbolic[0], actual[0]) 58 | 59 | gradients = K.gradients(loss, vgg.input) 60 | get_loss_grads = K.function(inputs=[vgg.input], outputs=[loss]+gradients) 61 | 62 | def get_loss_grads_wrapper(x): 63 | l, g = get_loss_grads([x.reshape(content_image.shape)]) 64 | return l.astype(np.float64), g.flatten().astype(np.float64) 65 | 66 | final_img = minimize_loss(get_loss_grads_wrapper, epochs, shape) 67 | final_img = np.reshape(final_img, newshape=(1, shape[0], shape[1], 3)) 68 | final_img = unpreprocess(final_img[0].copy()) 69 | #final_img = scale_img(final_img) 70 | 71 | result = np.hstack((unpreprocess(content_image[0].copy()), unpreprocess(style_image[0].copy()), final_img)) 72 | cv2.imwrite('result/'+str(time.time())+'.jpg', result) 73 | 74 | cv2.imwrite(str(time.time())+'.jpg', final_img) 75 | keypress = cv2.waitKey(10000) 76 | -------------------------------------------------------------------------------- /result/1530306239.1840756.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530306239.1840756.jpg -------------------------------------------------------------------------------- /result/1530307377.779925.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530307377.779925.jpg -------------------------------------------------------------------------------- /result/1530309076.0679188.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530309076.0679188.jpg -------------------------------------------------------------------------------- /result/1530311919.316769.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530311919.316769.jpg -------------------------------------------------------------------------------- /result/1530443959.7306142.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530443959.7306142.jpg -------------------------------------------------------------------------------- /result/1530447450.6487007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530447450.6487007.jpg -------------------------------------------------------------------------------- /result/1530449765.778833.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530449765.778833.jpg -------------------------------------------------------------------------------- /result/1530451563.3917222.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530451563.3917222.jpg -------------------------------------------------------------------------------- /result/1530465236.4173527.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530465236.4173527.jpg -------------------------------------------------------------------------------- /result/1530466661.53521.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530466661.53521.jpg -------------------------------------------------------------------------------- /result/1530479192.691439.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530479192.691439.jpg -------------------------------------------------------------------------------- /result/1530481484.1835425.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530481484.1835425.jpg -------------------------------------------------------------------------------- /result/1530484380.669741.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530484380.669741.jpg -------------------------------------------------------------------------------- /result/1530566919.4661949.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530566919.4661949.jpg -------------------------------------------------------------------------------- /result/1530569761.2654958.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530569761.2654958.jpg -------------------------------------------------------------------------------- /result/1530617761.3455205.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530617761.3455205.jpg -------------------------------------------------------------------------------- /result/1530620345.2455604.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/result/1530620345.2455604.jpg -------------------------------------------------------------------------------- /style/1280px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/1280px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg -------------------------------------------------------------------------------- /style/3584389a7c92328a8f586eddea973e3f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/3584389a7c92328a8f586eddea973e3f.jpg -------------------------------------------------------------------------------- /style/500x500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/500x500.jpg -------------------------------------------------------------------------------- /style/64879447-original-abstract-art-contemporary-digital-painting-portrait-of-the-man-face-with-orange-hair-like-a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/64879447-original-abstract-art-contemporary-digital-painting-portrait-of-the-man-face-with-orange-hair-like-a.jpg -------------------------------------------------------------------------------- /style/6970631088_f8a396cc6a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/6970631088_f8a396cc6a.jpg -------------------------------------------------------------------------------- /style/Color-mosaic-vector-background-set-12-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/Color-mosaic-vector-background-set-12-1.jpg -------------------------------------------------------------------------------- /style/Nubula-I-sml-500x500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/Nubula-I-sml-500x500.jpg -------------------------------------------------------------------------------- /style/best-ideas-about-mosaic-art-on-mosaic-mosaics-and-picture-of-a-mosaic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/best-ideas-about-mosaic-art-on-mosaic-mosaics-and-picture-of-a-mosaic.jpg -------------------------------------------------------------------------------- /style/iStock-546424192.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/iStock-546424192.jpg -------------------------------------------------------------------------------- /style/landscape-photography-art-by-hidenobu-suzuki-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvilPort2/PhotoStylist/a091b41c18a4b52d21662bd78574abf7e26b238c/style/landscape-photography-art-by-hidenobu-suzuki-1.jpg -------------------------------------------------------------------------------- /style_model.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from keras.models import Model 3 | from keras.layers import Conv2D 4 | import keras.backend as K 5 | from scipy.optimize import fmin_l_bfgs_b 6 | import cv2 7 | from utils import minimize_loss, load_and_preprocess_style, VGG16_AvgPool, unpreprocess, scale_img 8 | 9 | def gram_matrix(img): 10 | X = K.batch_flatten(K.permute_dimensions(img, (2, 0, 1))) 11 | G = K.dot(X, K.transpose(X)) / img.get_shape().num_elements() 12 | return G 13 | 14 | def style_loss(y, t): 15 | return K.mean(K.square(gram_matrix(y)-gram_matrix(t))) 16 | 17 | def main(): 18 | img = load_and_preprocess_style() 19 | 20 | shape = img.shape[1:] 21 | vgg = VGG16_AvgPool(shape) 22 | symbolic_conv_outputs = [layer.get_output_at(1) for layer in vgg.layers if layer.__class__ == Conv2D] 23 | 24 | style_model = Model(vgg.input, symbolic_conv_outputs) 25 | style_outputs = [K.variable(y) for y in style_model.predict(img)] 26 | print(len(style_outputs)) 27 | 28 | loss = 0 29 | for symbolic, actual in zip(symbolic_conv_outputs, style_outputs): 30 | loss += style_loss(symbolic[0], actual[0]) 31 | 32 | gradients = K.gradients(loss, style_model.input) 33 | get_loss_grads = K.function(inputs=[style_model.input], outputs=[loss]+gradients) 34 | 35 | def get_loss_grads_wrapper(x): 36 | l, g = get_loss_grads([x.reshape(img.shape)]) 37 | return l.astype(np.float64), g.flatten().astype(np.float64) 38 | 39 | img = minimize_loss(get_loss_grads_wrapper, 10, shape) 40 | img = np.reshape(img, newshape=(1, shape[0], shape[1], 3)) 41 | img = unpreprocess(img[0].copy()) 42 | img = scale_img(img) 43 | 44 | cv2.imshow('style', img) 45 | cv2.waitKey(0) -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | from keras.applications.vgg16 import VGG16, preprocess_input 2 | from keras.layers import MaxPooling2D, AveragePooling2D, Conv2D 3 | from keras.models import Sequential 4 | from load_images import load_content_image, load_style_image 5 | import numpy as np 6 | import cv2 7 | from scipy.optimize import fmin_l_bfgs_b 8 | 9 | 10 | def VGG16_AvgPool(shape): 11 | vgg16 = VGG16(input_shape=shape, weights='imagenet', include_top=False) 12 | model = Sequential() 13 | for layer in vgg16.layers: 14 | if layer.__class__ == MaxPooling2D: 15 | model.add(AveragePooling2D()) 16 | else: 17 | model.add(layer) 18 | return model 19 | 20 | def load_and_preprocess_content(shape): 21 | content = load_content_image(shape) 22 | content = np.expand_dims(content, axis=0) 23 | content = preprocess_input(content) 24 | return content 25 | 26 | def load_and_preprocess_style(shape): 27 | style = load_style_image(shape) 28 | style = np.expand_dims(style, axis=0) 29 | style = preprocess_input(style) 30 | return style 31 | 32 | def unpreprocess(img): 33 | img[..., 0] += 103.939 34 | img[..., 1] += 116.779 35 | img[..., 2] += 126.68 36 | return img 37 | 38 | def scale_img(x): 39 | x = x - x.min() 40 | x = x / x.max() 41 | return x 42 | 43 | def minimize_loss(fn, epochs, shape): 44 | img = np.random.randn(np.prod(shape)) 45 | for i in range(epochs): 46 | img = np.reshape(img, newshape=(1, shape[0], shape[1], 3)) 47 | temp = unpreprocess(img[0].copy()) 48 | temp = scale_img(temp) 49 | cv2.imshow('img', temp) 50 | cv2.waitKey(2000) 51 | img, l, _ = fmin_l_bfgs_b(func=fn, x0=img, maxfun=20) 52 | img = np.clip(img, -127, 127) 53 | print("iteration = %d, loss = %f" %(i, l)) 54 | return img --------------------------------------------------------------------------------