File size: 5,159 Bytes
b762e56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86e64e9
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import argparse
import multiprocessing as mp
import os
import numpy as np
from dataclasses import dataclass
from tqdm import tqdm

def numericalize(cmd, n=64):
    """NOTE: shall only be called after normalization"""
    cmd = ((cmd) / 30 * n).round().clip(min=0, max=n-1).astype(int)
    return cmd

def denumericalize(cmd, n=64):
    cmd = cmd / n * 30
    return cmd

def cal_aux_bezier_pts(font_seq, opts):
    """
    calculate aux pts along bezier curves
    """
    pts_aux_all = []

    for j in range(opts.char_num):
        char_seq = font_seq[j] # shape: opts.max_len ,12
        pts_aux_char = []
        for k in range(opts.max_seq_len):
            stroke_seq = char_seq[k]
            stroke_cmd = np.argmax(stroke_seq[:4], -1)
            stroke_seq[4:] = denumericalize(numericalize(stroke_seq[4:]))
            p0, p1, p2, p3 = stroke_seq[4:6], stroke_seq[6:8], stroke_seq[8:10], stroke_seq[10:12]
            pts_aux_stroke = []
            if stroke_cmd == 0:
                for t in range(6):
                    pts_aux_stroke.append(0)
            elif stroke_cmd == 1: # move
                for t in [0.25, 0.5, 0.75]:
                    coord_t = p0 + t*(p3-p0)
                    pts_aux_stroke.append(coord_t[0])
                    pts_aux_stroke.append(coord_t[1])
            elif stroke_cmd == 2: # line
                for t in [0.25, 0.5, 0.75]:
                    coord_t = p0 + t*(p3-p0)
                    pts_aux_stroke.append(coord_t[0])
                    pts_aux_stroke.append(coord_t[1])
            elif stroke_cmd == 3: # curve
                for t in [0.25, 0.5, 0.75]:
                    coord_t = (1-t)*(1-t)*(1-t)*p0 + 3*t*(1-t)*(1-t)*p1 + 3*t*t*(1-t)*p2 + t*t*t*p3
                    pts_aux_stroke.append(coord_t[0])
                    pts_aux_stroke.append(coord_t[1])

            pts_aux_stroke = np.array(pts_aux_stroke)
            pts_aux_char.append(pts_aux_stroke)

        pts_aux_char = np.array(pts_aux_char)
        pts_aux_all.append(pts_aux_char)

    pts_aux_all = np.array(pts_aux_all)

    return pts_aux_all


def relax_rep(opts):
    """
    relaxing the sequence representation, details are shown in paper
    """
    data_path = os.path.join(opts.output_path, opts.language, opts.split)
    font_dirs = os.listdir(data_path)
    font_dirs.sort()
    num_fonts = len(font_dirs)
    print(f"Number {opts.split} fonts before processing", num_fonts)
    num_processes = mp.cpu_count() - 1
    # num_processes = 1
    fonts_per_process = num_fonts // num_processes + 1

    def process(process_id):

        for i in tqdm(range(process_id * fonts_per_process, (process_id + 1) * fonts_per_process)):
            if i >= num_fonts:
                break

            font_dir = os.path.join(data_path, font_dirs[i])
            font_seq = np.load(os.path.join(font_dir, 'sequence.npy')).reshape(opts.char_num, opts.max_seq_len, -1)
            font_len = np.load(os.path.join(font_dir, 'seq_len.npy')).reshape(-1)
            cmd = font_seq[:, :, :4]
            args = font_seq[:, :, 4:]

            ret = []
            for j in range(opts.char_num):

                char_cmds = cmd[j]
                char_args = args[j]
                char_len = font_len[j]
                new_args = []
                for k in range(char_len):
                    cur_cls = np.argmax(char_cmds[k], -1)
                    cur_arg = char_args[k]
                    if k - 1 > -1:
                        pre_arg = char_args[k - 1]
                    if cur_cls == 1: # when k == 0, cur_cls == 1
                        cur_arg = np.concatenate((np.array([cur_arg[-2], cur_arg[-1]]), cur_arg), -1)
                    else:
                        cur_arg = np.concatenate((np.array([pre_arg[-2], pre_arg[-1]]), cur_arg), -1)
                    new_args.append(cur_arg)

                while(len(new_args)) < opts.max_seq_len:
                    new_args.append(np.array([0, 0, 0, 0, 0, 0, 0, 0]))

                new_args = np.array(new_args)
                new_seq = np.concatenate((char_cmds, new_args),-1)
                ret.append(new_seq)
            ret = np.array(ret)
            # write relaxed version of sequence.npy
            np.save(os.path.join(font_dir, 'sequence_relaxed.npy'), ret.reshape(opts.char_num, -1))

            pts_aux = cal_aux_bezier_pts(ret, opts)
            np.save(os.path.join(font_dir, 'pts_aux.npy'), pts_aux)

    processes = [mp.Process(target=process, args=[pid]) for pid in range(num_processes)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    
def main():
    parser = argparse.ArgumentParser(description="relax representation")
    parser.add_argument("--language", type=str, default='eng', choices=['eng', 'chn', 'tha'])
    parser.add_argument("--data_path", type=str, default='./Font_Dataset', help="Path to Dataset")
    parser.add_argument("--output_path", type=str, default='../data/vecfont_dataset_/', help="Path to write the database to")
    parser.add_argument("--split", type=str, default='train')
    opts = parser.parse_args()
    relax_rep(opts)

if __name__ == "__main__":
    main()