|
""" |
|
# Copyright 2020 Adobe |
|
# All Rights Reserved. |
|
|
|
# NOTICE: Adobe permits you to use, modify, and distribute this file in |
|
# accordance with the terms of the Adobe license agreement accompanying |
|
# it. |
|
|
|
""" |
|
|
|
import torch.nn as nn |
|
import torch.nn.init as init |
|
import os |
|
import cv2 |
|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
|
|
class Point: |
|
def __init__(self, x, y): |
|
self.x = x |
|
self.y = y |
|
|
|
class ShapeParts: |
|
def __init__(self, np_pts): |
|
self.data = np_pts |
|
|
|
def part(self, idx): |
|
return Point(self.data[idx, 0], self.data[idx, 1]) |
|
|
|
|
|
class Record(): |
|
def __init__(self, type_list): |
|
self.data, self.count = {}, {} |
|
self.type_list = type_list |
|
self.max_min_data = None |
|
for t in type_list: |
|
self.data[t] = 0.0 |
|
self.count[t] = 0.0 |
|
|
|
def add(self, new_data, c=1.0): |
|
for t in self.type_list: |
|
self.data[t] += new_data |
|
self.count[t] += c |
|
|
|
def per(self, t): |
|
return self.data[t] / (self.count[t] + 1e-32) |
|
|
|
def clean(self, t): |
|
self.data[t], self.count[t] = 0.0, 0.0 |
|
|
|
def is_better(self, t, greater): |
|
if(self.max_min_data == None): |
|
self.max_min_data = self.data[t] |
|
return True |
|
else: |
|
if(greater): |
|
if(self.data[t] > self.max_min_data): |
|
self.max_min_data = self.data[t] |
|
return True |
|
else: |
|
if (self.data[t] < self.max_min_data): |
|
self.max_min_data = self.data[t] |
|
return True |
|
return False |
|
|
|
def weight_init(m): |
|
''' |
|
Usage: |
|
model = Model() |
|
model.apply(weight_init) |
|
''' |
|
if isinstance(m, nn.Conv1d): |
|
init.normal_(m.weight.data) |
|
if m.bias is not None: |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.Conv2d): |
|
init.xavier_normal_(m.weight.data) |
|
if m.bias is not None: |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.Conv3d): |
|
init.xavier_normal_(m.weight.data) |
|
if m.bias is not None: |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.ConvTranspose1d): |
|
init.normal_(m.weight.data) |
|
if m.bias is not None: |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.ConvTranspose2d): |
|
init.xavier_normal_(m.weight.data) |
|
if m.bias is not None: |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.ConvTranspose3d): |
|
init.xavier_normal_(m.weight.data) |
|
if m.bias is not None: |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.BatchNorm1d): |
|
init.normal_(m.weight.data, mean=1, std=0.02) |
|
init.constant_(m.bias.data, 0) |
|
elif isinstance(m, nn.BatchNorm2d): |
|
init.normal_(m.weight.data, mean=1, std=0.02) |
|
init.constant_(m.bias.data, 0) |
|
elif isinstance(m, nn.BatchNorm3d): |
|
init.normal_(m.weight.data, mean=1, std=0.02) |
|
init.constant_(m.bias.data, 0) |
|
elif isinstance(m, nn.Linear): |
|
init.xavier_normal_(m.weight.data) |
|
init.normal_(m.bias.data) |
|
elif isinstance(m, nn.LSTM): |
|
for param in m.parameters(): |
|
if len(param.shape) >= 2: |
|
init.orthogonal_(param.data) |
|
else: |
|
init.normal_(param.data) |
|
elif isinstance(m, nn.LSTMCell): |
|
for param in m.parameters(): |
|
if len(param.shape) >= 2: |
|
init.orthogonal_(param.data) |
|
else: |
|
init.normal_(param.data) |
|
elif isinstance(m, nn.GRU): |
|
for param in m.parameters(): |
|
if len(param.shape) >= 2: |
|
init.orthogonal_(param.data) |
|
else: |
|
init.normal_(param.data) |
|
elif isinstance(m, nn.GRUCell): |
|
for param in m.parameters(): |
|
if len(param.shape) >= 2: |
|
init.orthogonal_(param.data) |
|
else: |
|
init.normal_(param.data) |
|
|
|
def get_n_params(model): |
|
pp=0 |
|
for p in list(model.parameters()): |
|
nn=1 |
|
for s in list(p.size()): |
|
nn = nn*s |
|
pp += nn |
|
return pp |
|
|
|
|
|
def vis_landmark_on_img(img, shape, linewidth=2): |
|
''' |
|
Visualize landmark on images. |
|
''' |
|
if (type(shape) == ShapeParts): |
|
def draw_curve(idx_list, color=(0, 255, 0), loop=False, lineWidth=linewidth): |
|
for i in idx_list: |
|
cv2.line(img, (shape.part(i).x, shape.part(i).y), (shape.part(i + 1).x, shape.part(i + 1).y), |
|
color, lineWidth) |
|
if (loop): |
|
cv2.line(img, (shape.part(idx_list[0]).x, shape.part(idx_list[0]).y), |
|
(shape.part(idx_list[-1] + 1).x, shape.part(idx_list[-1] + 1).y), color, lineWidth) |
|
|
|
draw_curve(list(range(0, 16))) |
|
draw_curve(list(range(17, 21)), color=(0, 0, 255)) |
|
draw_curve(list(range(22, 26)), color=(0, 0, 255)) |
|
draw_curve(list(range(27, 35))) |
|
draw_curve(list(range(36, 41)), loop=True) |
|
draw_curve(list(range(42, 47)), loop=True) |
|
draw_curve(list(range(48, 59)), loop=True, color=(0, 255, 255)) |
|
draw_curve(list(range(60, 67)), loop=True, color=(255, 255, 0)) |
|
|
|
else: |
|
def draw_curve(idx_list, color=(0, 255, 0), loop=False, lineWidth=linewidth): |
|
for i in idx_list: |
|
cv2.line(img, (shape[i, 0], shape[i, 1]), (shape[i + 1, 0], shape[i + 1, 1]), color, lineWidth) |
|
if (loop): |
|
cv2.line(img, (shape[idx_list[0], 0], shape[idx_list[0], 1]), |
|
(shape[idx_list[-1] + 1, 0], shape[idx_list[-1] + 1, 1]), color, lineWidth) |
|
|
|
draw_curve(list(range(0, 16))) |
|
draw_curve(list(range(17, 21)), color=(0, 0, 255)) |
|
draw_curve(list(range(22, 26)), color=(0, 0, 255)) |
|
draw_curve(list(range(27, 35))) |
|
draw_curve(list(range(36, 41)), loop=True) |
|
draw_curve(list(range(42, 47)), loop=True) |
|
draw_curve(list(range(48, 59)), loop=True, color=(0, 255, 255)) |
|
draw_curve(list(range(60, 67)), loop=True, color=(255, 255, 0)) |
|
|
|
return img |
|
|
|
|
|
def vis_landmark_on_plt(fl, x_offset=0.0, show_now=True, c='r'): |
|
def draw_curve(shape, idx_list, loop=False, x_offset=0.0, c=None): |
|
for i in idx_list: |
|
plt.plot((shape[i, 0] + x_offset, shape[i + 1, 0] + x_offset), (-shape[i, 1], -shape[i + 1, 1]), c=c, lineWidth=1) |
|
if (loop): |
|
plt.plot((shape[idx_list[0], 0] + x_offset, shape[idx_list[-1] + 1, 0] + x_offset), |
|
(-shape[idx_list[0], 1], -shape[idx_list[-1] + 1, 1]), c=c, lineWidth=1) |
|
|
|
draw_curve(fl, list(range(0, 16)), x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(17, 21)), x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(22, 26)), x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(27, 35)), x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(36, 41)), loop=True, x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(42, 47)), loop=True, x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(48, 59)), loop=True, x_offset=x_offset, c=c) |
|
draw_curve(fl, list(range(60, 67)), loop=True, x_offset=x_offset, c=c) |
|
|
|
if(show_now): |
|
plt.show() |
|
|
|
|
|
def try_mkdir(dir): |
|
try: |
|
os.mkdir(dir) |
|
except: |
|
pass |
|
|
|
import numpy |
|
def smooth(x, window_len=11, window='hanning'): |
|
"""smooth the data using a window with requested size. |
|
|
|
This method is based on the convolution of a scaled window with the signal. |
|
The signal is prepared by introducing reflected copies of the signal |
|
(with the window size) in both ends so that transient parts are minimized |
|
in the begining and end part of the output signal. |
|
|
|
input: |
|
x: the input signal |
|
window_len: the dimension of the smoothing window; should be an odd integer |
|
window: the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman' |
|
flat window will produce a moving average smoothing. |
|
|
|
output: |
|
the smoothed signal |
|
|
|
example: |
|
|
|
t=linspace(-2,2,0.1) |
|
x=sin(t)+randn(len(t))*0.1 |
|
y=smooth(x) |
|
|
|
see also: |
|
|
|
numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolve |
|
scipy.signal.lfilter |
|
|
|
the window parameter could be the window itself if an array instead of a string |
|
NOTE: length(output) != length(input), to correct this: return y[(window_len/2-1):-(window_len/2)] instead of just y. |
|
""" |
|
|
|
if x.ndim != 1: |
|
raise(ValueError, "smooth only accepts 1 dimension arrays.") |
|
|
|
if x.size < window_len: |
|
raise(ValueError, "Input vector needs to be bigger than window size.") |
|
|
|
if window_len < 3: |
|
return x |
|
|
|
if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']: |
|
raise(ValueError, "Window is on of 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'") |
|
|
|
s = numpy.r_[x[window_len - 1:0:-1], x, x[-2:-window_len - 1:-1]] |
|
|
|
if window == 'flat': |
|
w = numpy.ones(window_len, 'd') |
|
else: |
|
w = eval('numpy.' + window + '(window_len)') |
|
|
|
y = numpy.convolve(w / w.sum(), s, mode='valid') |
|
return y |
|
|
|
|
|
def get_puppet_info(DEMO_CH, ROOT_DIR): |
|
import numpy as np |
|
B = 5000 |
|
|
|
if (DEMO_CH == 'wilk_old'): |
|
bound = np.array([-B, -B, -B, 459, -B, B+918, 419, B+918, B+838, B+918, B+838, 459, B+838, -B, 419, -B]).reshape(1, -1) |
|
|
|
scale, shift = -0.005276414887140783, np.array([-475.4316, -193.53225]) |
|
elif (DEMO_CH == 'sketch'): |
|
bound = np.array([-10000, -10000, -10000, 221, -10000, 10443, 232, 10443, 10465, 10443, 10465, 221, 10465, -10000, 232, -10000]).reshape(1, -1) |
|
scale, shift = -0.006393177201290783, np.array([-226.8411, -176.5216]) |
|
elif (DEMO_CH == 'onepunch'): |
|
bound = np.array([0, 0, 0, 168, 0, 337, 282, 337, 565, 337, 565, 168, 565, 0, 282, 0]).reshape(1, -1) |
|
scale, shift = -0.007558707536598317, np.array([-301.4903, -120.05265]) |
|
elif (DEMO_CH == 'cat'): |
|
bound = np.array([0, 0, 0, 315, 0, 631, 299, 631, 599, 631, 599, 315, 599, 0, 299, 0]).reshape(1, -1) |
|
scale, shift = -0.009099476040795225, np.array([-297.17085, -259.2363]) |
|
elif (DEMO_CH == 'paint'): |
|
bound = np.array([0, 0, 0, 249, 0, 499, 212, 499, 424, 499, 424, 249, 424, 0, 212, 0]).reshape(1, -1) |
|
scale, shift = -0.007409177996872789, np.array([-161.92345878, -249.40250103]) |
|
elif (DEMO_CH == 'mulaney'): |
|
bound = np.array([0, 0, 0, 255, 0, 511, 341, 511, 682, 511, 682, 255, 682, 0, 341, 0]).reshape(1, -1) |
|
scale, shift = -0.010651548568731444, np.array([-333.54245, -189.081]) |
|
elif (DEMO_CH == 'cartoonM_old'): |
|
bound = np.array([0, 0, 0, 299, 0, 599, 399, 599, 799, 599, 799, 299, 799, 0, 399, 0]).reshape(1, -1) |
|
scale, shift = -0.0055312373170456845, np.array([-398.6125, -240.45235]) |
|
elif (DEMO_CH == 'beer'): |
|
bound = np.array([0, 0, 0, 309, 0, 618, 260, 618, 520, 618, 520, 309, 520, 0, 260, 0]).reshape(1, -1) |
|
scale, shift = -0.0054102709937112374, np.array([-254.1478, -156.6971]) |
|
elif (DEMO_CH == 'color'): |
|
bound = np.array([0, 0, 0, 140, 0, 280, 249, 280, 499, 280, 499, 140, 499, 0, 249, 0]).reshape(1, -1) |
|
scale, shift = -0.012986159189209149, np.array([-237.27065, -79.2465]) |
|
else: |
|
if (os.path.exists(os.path.join(ROOT_DIR, DEMO_CH + '.jpg'))): |
|
img = cv2.imread(os.path.join(ROOT_DIR, DEMO_CH + ".jpg")) |
|
elif (os.path.exists(os.path.join(ROOT_DIR, DEMO_CH + '.png'))): |
|
img = cv2.imread(os.path.join(ROOT_DIR, DEMO_CH + ".png")) |
|
else: |
|
print('not file founded.') |
|
exit(0) |
|
size = img.shape |
|
h = size[1] - 1 |
|
w = size[0] - 1 |
|
bound = np.array([-B, -B, |
|
-B, w//4, |
|
-B, w // 2, |
|
-B, w//4*3, |
|
-B, B + w, |
|
h // 2, B+w, |
|
B+h, B+w, |
|
B+h, w // 2, |
|
B+h, -B, |
|
h//4, -B, |
|
h // 2, -B, |
|
h//4*3, -B]).reshape(1, -1) |
|
ss = np.loadtxt(os.path.join(ROOT_DIR, DEMO_CH + '_scale_shift.txt')) |
|
scale, shift = ss[0], np.array([ss[1], ss[2]]) |
|
|
|
return bound, scale, shift |
|
|
|
|
|
def close_input_face_mouth(shape_3d, p1=0.7, p2=0.5): |
|
shape_3d = shape_3d.reshape((1, 68, 3)) |
|
index1 = list(range(60 - 1, 55 - 1, -1)) |
|
index2 = list(range(68 - 1, 65 - 1, -1)) |
|
mean_out = 0.5 * (shape_3d[:, 49:54] + shape_3d[:, index1]) |
|
mean_in = 0.5 * (shape_3d[:, 61:64] + shape_3d[:, index2]) |
|
shape_3d[:, 50:53] -= (shape_3d[:, 61:64] - mean_in) * p1 |
|
shape_3d[:, list(range(59 - 1, 56 - 1, -1))] -= (shape_3d[:, index2] - mean_in) * p1 |
|
shape_3d[:, 49] -= (shape_3d[:, 61] - mean_in[:, 0]) * p2 |
|
shape_3d[:, 53] -= (shape_3d[:, 63] - mean_in[:, -1]) * p2 |
|
shape_3d[:, 59] -= (shape_3d[:, 67] - mean_in[:, 0]) * p2 |
|
shape_3d[:, 55] -= (shape_3d[:, 65] - mean_in[:, -1]) * p2 |
|
|
|
shape_3d[:, 61:64] -= (shape_3d[:, 61:64] - mean_in) * p1 |
|
shape_3d[:, index2] -= (shape_3d[:, index2] - mean_in) * p1 |
|
shape_3d = shape_3d.reshape((68, 3)) |
|
|
|
return shape_3d |
|
|
|
def norm_input_face(shape_3d): |
|
scale = 1.6 / (shape_3d[0, 0] - shape_3d[16, 0]) |
|
shift = - 0.5 * (shape_3d[0, 0:2] + shape_3d[16, 0:2]) |
|
shape_3d[:, 0:2] = (shape_3d[:, 0:2] + shift) * scale |
|
face_std = np.loadtxt('src/dataset/utils/STD_FACE_LANDMARKS.txt').reshape(68, 3) |
|
shape_3d[:, -1] = face_std[:, -1] * 0.1 |
|
shape_3d[:, 0:2] = -shape_3d[:, 0:2] |
|
|
|
return shape_3d, scale, shift |
|
|
|
def add_naive_eye(fl): |
|
for t in range(fl.shape[0]): |
|
r = 0.95 |
|
fl[t, 37], fl[t, 41] = r * fl[t, 37] + (1 - r) * fl[t, 41], (1 - r) * fl[t, 37] + r * fl[t, 41] |
|
fl[t, 38], fl[t, 40] = r * fl[t, 38] + (1 - r) * fl[t, 40], (1 - r) * fl[t, 38] + r * fl[t, 40] |
|
fl[t, 43], fl[t, 47] = r * fl[t, 43] + (1 - r) * fl[t, 47], (1 - r) * fl[t, 43] + r * fl[t, 47] |
|
fl[t, 44], fl[t, 46] = r * fl[t, 44] + (1 - r) * fl[t, 46], (1 - r) * fl[t, 44] + r * fl[t, 46] |
|
|
|
K1, K2 = 10, 15 |
|
length = fl.shape[0] |
|
close_time_stamp = [30] |
|
t = 30 |
|
while (t < length - 1 - K2): |
|
t += 60 |
|
t += np.random.randint(30, 90) |
|
if (t < length - 1 - K2): |
|
close_time_stamp.append(t) |
|
for t in close_time_stamp: |
|
fl[t, 37], fl[t, 41] = 0.25 * fl[t, 37] + 0.75 * fl[t, 41], 0.25 * fl[t, 37] + 0.75 * fl[t, 41] |
|
fl[t, 38], fl[t, 40] = 0.25 * fl[t, 38] + 0.75 * fl[t, 40], 0.25 * fl[t, 38] + 0.75 * fl[t, 40] |
|
fl[t, 43], fl[t, 47] = 0.25 * fl[t, 43] + 0.75 * fl[t, 47], 0.25 * fl[t, 43] + 0.75 * fl[t, 47] |
|
fl[t, 44], fl[t, 46] = 0.25 * fl[t, 44] + 0.75 * fl[t, 46], 0.25 * fl[t, 44] + 0.75 * fl[t, 46] |
|
|
|
def interp_fl(t0, t1, t2, r): |
|
for index in [37, 38, 40, 41, 43, 44, 46, 47]: |
|
fl[t0, index] = r * fl[t1, index] + (1 - r) * fl[t2, index] |
|
|
|
for t0 in range(t - K1 + 1, t): |
|
interp_fl(t0, t - K1, t, r=(t - t0) / 1. / K1) |
|
for t0 in range(t + 1, t + K2): |
|
interp_fl(t0, t, t + K2, r=(t + K2 - 1 - t0) / 1. / K2) |
|
|
|
return fl |