Can #AI make me look (more) presentable? The jury is out I think.

Smile

This is called style transfer, where the style/technique from a kind of painting (could be a photos too) is applied to an image, to create a new image. I took this using the built-in camera on my machine sitting at my desk and then applying the different kind of ‘styles’ on it. Each of these styles are is a separate #deeplearning model  that has learned how to apply the relevant style to a source image.

candy
Style - Candy

feathers
Style - Feathers

mosaic
Style - Mosaic

robert
Style - Robert

Specifically, this uses a Neural Network (#DeepLearning) model called VGG19 , which is a 19-layer model running on TensorFlow. Of course, you can export this to a ONNX model, that then can be used in most other run-times and libraries.

image

This is inspired from Cornell universities paper - Perceptual Losses for Real-Time Style Transfer and Super-Resolution . Below is a snapshot of the VGG code that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def net(data_path, input_image): layers = ( 
  'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1', 
  'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2', 
  'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'conv3_3', 
  'relu3_3', 'conv3_4', 'relu3_4', 'pool3', 'conv4_1', 
  'relu4_1', 'conv4_2', 'relu4_2', 'conv4_3', 'relu4_3', 
  'conv4_4', 'relu4_4', 'pool4', 'conv5_1', 
  'relu5_1', 'conv5_2', 'relu5_2', 'conv5_3', 'relu5_3', 'conv5_4', 'relu5_4'
  )
  
data = scipy.io.loadmat(data_path)
mean = data['normalization'][0][0][0]
mean_pixel = np.mean(mean, axis=(0, 1)) 
weights = data['layers'][0]

net = {} 
current = input_image 

for i, name in enumerate(layers):
  kind = name
  if kind == 'conv':
    kernels, bias = weights[i][0][0][0][0] 
    # matconvnet: weights are [width, height, in_channels, out_channels] 
    # tensorflow: weights are \[height, width, in_channels, out_channels\] 
    kernels = np.transpose(kernels, (1, 0, 2, 3)) 
    bias = bias.reshape(-1) 
    current = _conv_layer(current, kernels, bias) 
  elif kind == 'relu': 
    current = tf.nn.relu(current) 
  elif kind == 'pool': 
    current = _pool_layer(current) 
    net[name] = current

assert len(net) == len(layers) return net

def _conv_layer(input, weights, bias): conv = tf.nn.conv2d(input, tf.constant(weights), strides=(1, 1, 1, 1), padding='SAME') return tf.nn.bias_add(conv, bias)

def _pool_layer(input): return tf.nn.max_pool(input, ksize=(1, 2, 2, 1), strides=(1, 2, 2, 1), padding='SAME')

If you want to play with this, you can download the code . Personally, I like the Mosaic style the best.