├── 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
--------------------------------------------------------------------------------