3morrrrr commited on
Commit
89f4d14
·
verified ·
1 Parent(s): e2e7724

Update drawing.py

Browse files
Files changed (1) hide show
  1. drawing.py +218 -216
drawing.py CHANGED
@@ -1,216 +1,218 @@
1
- from __future__ import print_function
2
- from collections import defaultdict
3
-
4
- import matplotlib.pyplot as plt
5
- import numpy as np
6
- from scipy.signal import savgol_filter
7
- from scipy.interpolate import interp1d
8
-
9
-
10
- alphabet = [
11
- '\x00', ' ', '!', '"', '#', "'", '(', ')', ',', '-', '.',
12
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
13
- '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
14
- 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'Y',
15
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
16
- 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
17
- 'y', 'z'
18
- ]
19
- alphabet_ord = list(map(ord, alphabet))
20
- alpha_to_num = defaultdict(int, list(map(reversed, enumerate(alphabet))))
21
- num_to_alpha = dict(enumerate(alphabet_ord))
22
-
23
- MAX_STROKE_LEN = 1200
24
- MAX_CHAR_LEN = 75
25
-
26
-
27
- def align(coords):
28
- """
29
- corrects for global slant/offset in handwriting strokes
30
- """
31
- coords = np.copy(coords)
32
- X, Y = coords[:, 0].reshape(-1, 1), coords[:, 1].reshape(-1, 1)
33
- X = np.concatenate([np.ones([X.shape[0], 1]), X], axis=1)
34
- offset, slope = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(Y).squeeze()
35
- theta = np.arctan(slope)
36
- rotation_matrix = np.array(
37
- [[np.cos(theta), -np.sin(theta)],
38
- [np.sin(theta), np.cos(theta)]]
39
- )
40
- coords[:, :2] = np.dot(coords[:, :2], rotation_matrix) - offset
41
- return coords
42
-
43
-
44
- def skew(coords, degrees):
45
- """
46
- skews strokes by given degrees
47
- """
48
- coords = np.copy(coords)
49
- theta = degrees * np.pi/180
50
- A = np.array([[np.cos(-theta), 0], [np.sin(-theta), 1]])
51
- coords[:, :2] = np.dot(coords[:, :2], A)
52
- return coords
53
-
54
-
55
- def stretch(coords, x_factor, y_factor):
56
- """
57
- stretches strokes along x and y axis
58
- """
59
- coords = np.copy(coords)
60
- coords[:, :2] *= np.array([x_factor, y_factor])
61
- return coords
62
-
63
-
64
- def add_noise(coords, scale):
65
- """
66
- adds gaussian noise to strokes
67
- """
68
- coords = np.copy(coords)
69
- coords[1:, :2] += np.random.normal(loc=0.0, scale=scale, size=coords[1:, :2].shape)
70
- return coords
71
-
72
-
73
- def encode_ascii(ascii_string):
74
- """
75
- encodes ascii string to array of ints
76
- """
77
- return np.array(list(map(lambda x: alpha_to_num[x], ascii_string)) + [0])
78
-
79
-
80
- def denoise(coords):
81
- """
82
- smoothing filter to mitigate some artifacts of the data collection
83
- """
84
- coords = np.split(coords, np.where(coords[:, 2] == 1)[0] + 1, axis=0)
85
- new_coords = []
86
- for stroke in coords:
87
- if len(stroke) != 0:
88
- x_new = savgol_filter(stroke[:, 0], 7, 3, mode='nearest')
89
- y_new = savgol_filter(stroke[:, 1], 7, 3, mode='nearest')
90
- xy_coords = np.hstack([x_new.reshape(-1, 1), y_new.reshape(-1, 1)])
91
- stroke = np.concatenate([xy_coords, stroke[:, 2].reshape(-1, 1)], axis=1)
92
- new_coords.append(stroke)
93
-
94
- coords = np.vstack(new_coords)
95
- return coords
96
-
97
-
98
- def interpolate(coords, factor=2):
99
- """
100
- interpolates strokes using cubic spline
101
- """
102
- coords = np.split(coords, np.where(coords[:, 2] == 1)[0] + 1, axis=0)
103
- new_coords = []
104
- for stroke in coords:
105
-
106
- if len(stroke) == 0:
107
- continue
108
-
109
- xy_coords = stroke[:, :2]
110
-
111
- if len(stroke) > 3:
112
- f_x = interp1d(np.arange(len(stroke)), stroke[:, 0], kind='cubic')
113
- f_y = interp1d(np.arange(len(stroke)), stroke[:, 1], kind='cubic')
114
-
115
- xx = np.linspace(0, len(stroke) - 1, factor*(len(stroke)))
116
- yy = np.linspace(0, len(stroke) - 1, factor*(len(stroke)))
117
-
118
- x_new = f_x(xx)
119
- y_new = f_y(yy)
120
-
121
- xy_coords = np.hstack([x_new.reshape(-1, 1), y_new.reshape(-1, 1)])
122
-
123
- stroke_eos = np.zeros([len(xy_coords), 1])
124
- stroke_eos[-1] = 1.0
125
- stroke = np.concatenate([xy_coords, stroke_eos], axis=1)
126
- new_coords.append(stroke)
127
-
128
- coords = np.vstack(new_coords)
129
- return coords
130
-
131
-
132
- def normalize(offsets):
133
- """
134
- normalizes strokes to median unit norm
135
- """
136
- offsets = np.copy(offsets)
137
- offsets[:, :2] /= np.median(np.linalg.norm(offsets[:, :2], axis=1))
138
- return offsets
139
-
140
-
141
- def coords_to_offsets(coords):
142
- """
143
- convert from coordinates to offsets
144
- """
145
- offsets = np.concatenate([coords[1:, :2] - coords[:-1, :2], coords[1:, 2:3]], axis=1)
146
- offsets = np.concatenate([np.array([[0, 0, 1]]), offsets], axis=0)
147
- return offsets
148
-
149
-
150
- def offsets_to_coords(offsets):
151
- """
152
- convert from offsets to coordinates
153
- """
154
- return np.concatenate([np.cumsum(offsets[:, :2], axis=0), offsets[:, 2:3]], axis=1)
155
-
156
-
157
- def draw(
158
- offsets,
159
- ascii_seq=None,
160
- align_strokes=True,
161
- denoise_strokes=True,
162
- interpolation_factor=None,
163
- save_file=None
164
- ):
165
- strokes = offsets_to_coords(offsets)
166
-
167
- if denoise_strokes:
168
- strokes = denoise(strokes)
169
-
170
- if interpolation_factor is not None:
171
- strokes = interpolate(strokes, factor=interpolation_factor)
172
-
173
- if align_strokes:
174
- strokes[:, :2] = align(strokes[:, :2])
175
-
176
- fig, ax = plt.subplots(figsize=(12, 3))
177
-
178
- stroke = []
179
- for x, y, eos in strokes:
180
- stroke.append((x, y))
181
- if eos == 1:
182
- coords = zip(*stroke)
183
- ax.plot(coords[0], coords[1], 'k')
184
- stroke = []
185
- if stroke:
186
- coords = zip(*stroke)
187
- ax.plot(coords[0], coords[1], 'k')
188
- stroke = []
189
-
190
- ax.set_xlim(-50, 600)
191
- ax.set_ylim(-40, 40)
192
-
193
- ax.set_aspect('equal')
194
- plt.tick_params(
195
- axis='both',
196
- left='off',
197
- top='off',
198
- right='off',
199
- bottom='off',
200
- labelleft='off',
201
- labeltop='off',
202
- labelright='off',
203
- labelbottom='off'
204
- )
205
-
206
- if ascii_seq is not None:
207
- if not isinstance(ascii_seq, str):
208
- ascii_seq = ''.join(list(map(chr, ascii_seq)))
209
- plt.title(ascii_seq)
210
-
211
- if save_file is not None:
212
- plt.savefig(save_file)
213
- print('saved to {}'.format(save_file))
214
- else:
215
- plt.show()
216
- plt.close('all')
 
 
 
1
+ from __future__ import print_function
2
+ from collections import defaultdict
3
+
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ from scipy.signal import savgol_filter
7
+ from scipy.interpolate import interp1d
8
+
9
+
10
+ alphabet = [
11
+ alphabet = [
12
+ '\x00', ' ', '!', '"', '#', "'", '(', ')', ',', '-', '.', '_',
13
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
14
+ '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
15
+ 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'Y',
16
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
17
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
18
+ 'y', 'z'
19
+ ]
20
+ ]
21
+ alphabet_ord = list(map(ord, alphabet))
22
+ alpha_to_num = defaultdict(int, list(map(reversed, enumerate(alphabet))))
23
+ num_to_alpha = dict(enumerate(alphabet_ord))
24
+
25
+ MAX_STROKE_LEN = 1200
26
+ MAX_CHAR_LEN = 75
27
+
28
+
29
+ def align(coords):
30
+ """
31
+ corrects for global slant/offset in handwriting strokes
32
+ """
33
+ coords = np.copy(coords)
34
+ X, Y = coords[:, 0].reshape(-1, 1), coords[:, 1].reshape(-1, 1)
35
+ X = np.concatenate([np.ones([X.shape[0], 1]), X], axis=1)
36
+ offset, slope = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(Y).squeeze()
37
+ theta = np.arctan(slope)
38
+ rotation_matrix = np.array(
39
+ [[np.cos(theta), -np.sin(theta)],
40
+ [np.sin(theta), np.cos(theta)]]
41
+ )
42
+ coords[:, :2] = np.dot(coords[:, :2], rotation_matrix) - offset
43
+ return coords
44
+
45
+
46
+ def skew(coords, degrees):
47
+ """
48
+ skews strokes by given degrees
49
+ """
50
+ coords = np.copy(coords)
51
+ theta = degrees * np.pi/180
52
+ A = np.array([[np.cos(-theta), 0], [np.sin(-theta), 1]])
53
+ coords[:, :2] = np.dot(coords[:, :2], A)
54
+ return coords
55
+
56
+
57
+ def stretch(coords, x_factor, y_factor):
58
+ """
59
+ stretches strokes along x and y axis
60
+ """
61
+ coords = np.copy(coords)
62
+ coords[:, :2] *= np.array([x_factor, y_factor])
63
+ return coords
64
+
65
+
66
+ def add_noise(coords, scale):
67
+ """
68
+ adds gaussian noise to strokes
69
+ """
70
+ coords = np.copy(coords)
71
+ coords[1:, :2] += np.random.normal(loc=0.0, scale=scale, size=coords[1:, :2].shape)
72
+ return coords
73
+
74
+
75
+ def encode_ascii(ascii_string):
76
+ """
77
+ encodes ascii string to array of ints
78
+ """
79
+ return np.array(list(map(lambda x: alpha_to_num[x], ascii_string)) + [0])
80
+
81
+
82
+ def denoise(coords):
83
+ """
84
+ smoothing filter to mitigate some artifacts of the data collection
85
+ """
86
+ coords = np.split(coords, np.where(coords[:, 2] == 1)[0] + 1, axis=0)
87
+ new_coords = []
88
+ for stroke in coords:
89
+ if len(stroke) != 0:
90
+ x_new = savgol_filter(stroke[:, 0], 7, 3, mode='nearest')
91
+ y_new = savgol_filter(stroke[:, 1], 7, 3, mode='nearest')
92
+ xy_coords = np.hstack([x_new.reshape(-1, 1), y_new.reshape(-1, 1)])
93
+ stroke = np.concatenate([xy_coords, stroke[:, 2].reshape(-1, 1)], axis=1)
94
+ new_coords.append(stroke)
95
+
96
+ coords = np.vstack(new_coords)
97
+ return coords
98
+
99
+
100
+ def interpolate(coords, factor=2):
101
+ """
102
+ interpolates strokes using cubic spline
103
+ """
104
+ coords = np.split(coords, np.where(coords[:, 2] == 1)[0] + 1, axis=0)
105
+ new_coords = []
106
+ for stroke in coords:
107
+
108
+ if len(stroke) == 0:
109
+ continue
110
+
111
+ xy_coords = stroke[:, :2]
112
+
113
+ if len(stroke) > 3:
114
+ f_x = interp1d(np.arange(len(stroke)), stroke[:, 0], kind='cubic')
115
+ f_y = interp1d(np.arange(len(stroke)), stroke[:, 1], kind='cubic')
116
+
117
+ xx = np.linspace(0, len(stroke) - 1, factor*(len(stroke)))
118
+ yy = np.linspace(0, len(stroke) - 1, factor*(len(stroke)))
119
+
120
+ x_new = f_x(xx)
121
+ y_new = f_y(yy)
122
+
123
+ xy_coords = np.hstack([x_new.reshape(-1, 1), y_new.reshape(-1, 1)])
124
+
125
+ stroke_eos = np.zeros([len(xy_coords), 1])
126
+ stroke_eos[-1] = 1.0
127
+ stroke = np.concatenate([xy_coords, stroke_eos], axis=1)
128
+ new_coords.append(stroke)
129
+
130
+ coords = np.vstack(new_coords)
131
+ return coords
132
+
133
+
134
+ def normalize(offsets):
135
+ """
136
+ normalizes strokes to median unit norm
137
+ """
138
+ offsets = np.copy(offsets)
139
+ offsets[:, :2] /= np.median(np.linalg.norm(offsets[:, :2], axis=1))
140
+ return offsets
141
+
142
+
143
+ def coords_to_offsets(coords):
144
+ """
145
+ convert from coordinates to offsets
146
+ """
147
+ offsets = np.concatenate([coords[1:, :2] - coords[:-1, :2], coords[1:, 2:3]], axis=1)
148
+ offsets = np.concatenate([np.array([[0, 0, 1]]), offsets], axis=0)
149
+ return offsets
150
+
151
+
152
+ def offsets_to_coords(offsets):
153
+ """
154
+ convert from offsets to coordinates
155
+ """
156
+ return np.concatenate([np.cumsum(offsets[:, :2], axis=0), offsets[:, 2:3]], axis=1)
157
+
158
+
159
+ def draw(
160
+ offsets,
161
+ ascii_seq=None,
162
+ align_strokes=True,
163
+ denoise_strokes=True,
164
+ interpolation_factor=None,
165
+ save_file=None
166
+ ):
167
+ strokes = offsets_to_coords(offsets)
168
+
169
+ if denoise_strokes:
170
+ strokes = denoise(strokes)
171
+
172
+ if interpolation_factor is not None:
173
+ strokes = interpolate(strokes, factor=interpolation_factor)
174
+
175
+ if align_strokes:
176
+ strokes[:, :2] = align(strokes[:, :2])
177
+
178
+ fig, ax = plt.subplots(figsize=(12, 3))
179
+
180
+ stroke = []
181
+ for x, y, eos in strokes:
182
+ stroke.append((x, y))
183
+ if eos == 1:
184
+ coords = zip(*stroke)
185
+ ax.plot(coords[0], coords[1], 'k')
186
+ stroke = []
187
+ if stroke:
188
+ coords = zip(*stroke)
189
+ ax.plot(coords[0], coords[1], 'k')
190
+ stroke = []
191
+
192
+ ax.set_xlim(-50, 600)
193
+ ax.set_ylim(-40, 40)
194
+
195
+ ax.set_aspect('equal')
196
+ plt.tick_params(
197
+ axis='both',
198
+ left='off',
199
+ top='off',
200
+ right='off',
201
+ bottom='off',
202
+ labelleft='off',
203
+ labeltop='off',
204
+ labelright='off',
205
+ labelbottom='off'
206
+ )
207
+
208
+ if ascii_seq is not None:
209
+ if not isinstance(ascii_seq, str):
210
+ ascii_seq = ''.join(list(map(chr, ascii_seq)))
211
+ plt.title(ascii_seq)
212
+
213
+ if save_file is not None:
214
+ plt.savefig(save_file)
215
+ print('saved to {}'.format(save_file))
216
+ else:
217
+ plt.show()
218
+ plt.close('all')