HighCWu commited on
Commit
e9d4572
1 Parent(s): df2258f
This view is limited to 50 files because it contains too many changes.   See raw diff
InstanceNorm.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from keras.engine import Layer, InputSpec
2
+ from keras import initializers, regularizers, constraints
3
+ from keras import backend as K
4
+ from keras.utils.generic_utils import get_custom_objects
5
+
6
+ import tensorflow as tf
7
+
8
+
9
+ class InstanceNormalization(Layer):
10
+ """Instance normalization layer (Lei Ba et al, 2016, Ulyanov et al., 2016).
11
+ Normalize the activations of the previous layer at each step,
12
+ i.e. applies a transformation that maintains the mean activation
13
+ close to 0 and the activation standard deviation close to 1.
14
+ # Arguments
15
+ axis: Integer, the axis that should be normalized
16
+ (typically the features axis).
17
+ For instance, after a `Conv2D` layer with
18
+ `data_format="channels_first"`,
19
+ set `axis=1` in `InstanceNormalization`.
20
+ Setting `axis=None` will normalize all values in each instance of the batch.
21
+ Axis 0 is the batch dimension. `axis` cannot be set to 0 to avoid errors.
22
+ epsilon: Small float added to variance to avoid dividing by zero.
23
+ center: If True, add offset of `beta` to normalized tensor.
24
+ If False, `beta` is ignored.
25
+ scale: If True, multiply by `gamma`.
26
+ If False, `gamma` is not used.
27
+ When the next layer is linear (also e.g. `nn.relu`),
28
+ this can be disabled since the scaling
29
+ will be done by the next layer.
30
+ beta_initializer: Initializer for the beta weight.
31
+ gamma_initializer: Initializer for the gamma weight.
32
+ beta_regularizer: Optional regularizer for the beta weight.
33
+ gamma_regularizer: Optional regularizer for the gamma weight.
34
+ beta_constraint: Optional constraint for the beta weight.
35
+ gamma_constraint: Optional constraint for the gamma weight.
36
+ # Input shape
37
+ Arbitrary. Use the keyword argument `input_shape`
38
+ (tuple of integers, does not include the samples axis)
39
+ when using this layer as the first layer in a model.
40
+ # Output shape
41
+ Same shape as input.
42
+ # References
43
+ - [Layer Normalization](https://arxiv.org/abs/1607.06450)
44
+ - [Instance Normalization: The Missing Ingredient for Fast Stylization](https://arxiv.org/abs/1607.08022)
45
+ """
46
+ def __init__(self,
47
+ axis=None,
48
+ epsilon=1e-3,
49
+ center=True,
50
+ scale=True,
51
+ beta_initializer='zeros',
52
+ gamma_initializer='ones',
53
+ beta_regularizer=None,
54
+ gamma_regularizer=None,
55
+ beta_constraint=None,
56
+ gamma_constraint=None,
57
+ **kwargs):
58
+ super(InstanceNormalization, self).__init__(**kwargs)
59
+ self.supports_masking = True
60
+ self.axis = axis
61
+ self.epsilon = epsilon
62
+ self.center = center
63
+ self.scale = scale
64
+ self.beta_initializer = initializers.get(beta_initializer)
65
+ self.gamma_initializer = initializers.get(gamma_initializer)
66
+ self.beta_regularizer = regularizers.get(beta_regularizer)
67
+ self.gamma_regularizer = regularizers.get(gamma_regularizer)
68
+ self.beta_constraint = constraints.get(beta_constraint)
69
+ self.gamma_constraint = constraints.get(gamma_constraint)
70
+
71
+ def build(self, input_shape):
72
+ ndim = len(input_shape)
73
+ if self.axis == 0:
74
+ raise ValueError('Axis cannot be zero')
75
+
76
+ if (self.axis is not None) and (ndim == 2):
77
+ raise ValueError('Cannot specify axis for rank 1 tensor')
78
+
79
+ self.input_spec = InputSpec(ndim=ndim)
80
+
81
+ if self.axis is None:
82
+ shape = (1,)
83
+ else:
84
+ shape = (input_shape[self.axis],)
85
+
86
+ if self.scale:
87
+ self.gamma = self.add_weight(shape=shape,
88
+ name='gamma',
89
+ initializer=self.gamma_initializer,
90
+ regularizer=self.gamma_regularizer,
91
+ constraint=self.gamma_constraint)
92
+ else:
93
+ self.gamma = None
94
+ if self.center:
95
+ self.beta = self.add_weight(shape=shape,
96
+ name='beta',
97
+ initializer=self.beta_initializer,
98
+ regularizer=self.beta_regularizer,
99
+ constraint=self.beta_constraint)
100
+ else:
101
+ self.beta = None
102
+ self.built = True
103
+
104
+ def call(self, inputs, training=None):
105
+ input_shape = K.int_shape(inputs)
106
+ reduction_axes = list(range(0, len(input_shape)))
107
+
108
+ if (self.axis is not None):
109
+ del reduction_axes[self.axis]
110
+
111
+ del reduction_axes[0]
112
+
113
+ mean, var = tf.nn.moments(inputs, reduction_axes, keep_dims=True)
114
+ stddev = tf.sqrt(var) + self.epsilon
115
+ normed = (inputs - mean) / stddev
116
+
117
+ broadcast_shape = [1] * len(input_shape)
118
+ if self.axis is not None:
119
+ broadcast_shape[self.axis] = input_shape[self.axis]
120
+
121
+ if self.scale:
122
+ broadcast_gamma = K.reshape(self.gamma, broadcast_shape)
123
+ normed = normed * broadcast_gamma
124
+ if self.center:
125
+ broadcast_beta = K.reshape(self.beta, broadcast_shape)
126
+ normed = normed + broadcast_beta
127
+ return normed
128
+
129
+ def get_config(self):
130
+ config = {
131
+ 'axis': self.axis,
132
+ 'epsilon': self.epsilon,
133
+ 'center': self.center,
134
+ 'scale': self.scale,
135
+ 'beta_initializer': initializers.serialize(self.beta_initializer),
136
+ 'gamma_initializer': initializers.serialize(self.gamma_initializer),
137
+ 'beta_regularizer': regularizers.serialize(self.beta_regularizer),
138
+ 'gamma_regularizer': regularizers.serialize(self.gamma_regularizer),
139
+ 'beta_constraint': constraints.serialize(self.beta_constraint),
140
+ 'gamma_constraint': constraints.serialize(self.gamma_constraint)
141
+ }
142
+ base_config = super(InstanceNormalization, self).get_config()
143
+ return dict(list(base_config.items()) + list(config.items()))
144
+
145
+
146
+ get_custom_objects().update({'InstanceNormalization': InstanceNormalization})
ai.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow
2
+
3
+ tensorflow.compat.v1.disable_v2_behavior()
4
+ tf = tensorflow.compat.v1
5
+
6
+ import keras
7
+ import numpy as np
8
+ from config import *
9
+ from keras.models import load_model
10
+ from smoother import *
11
+ import keras.backend as K
12
+ from models import *
13
+
14
+
15
+ def ToGray(x):
16
+ R = x[:, :, :, 0:1]
17
+ G = x[:, :, :, 1:2]
18
+ B = x[:, :, :, 2:3]
19
+ return 0.30 * R + 0.59 * G + 0.11 * B
20
+
21
+
22
+ def RGB2YUV(x):
23
+ R = x[:, :, :, 0:1]
24
+ G = x[:, :, :, 1:2]
25
+ B = x[:, :, :, 2:3]
26
+ Y = 0.299 * R + 0.587 * G + 0.114 * B
27
+ U = 0.492 * (B - Y) + 128
28
+ V = 0.877 * (R - Y) + 128
29
+ return tf.concat([Y, U, V], axis=3)
30
+
31
+
32
+ def YUV2RGB(x):
33
+ Y = x[:, :, :, 0:1]
34
+ U = x[:, :, :, 1:2]
35
+ V = x[:, :, :, 2:3]
36
+ R = Y + 1.140 * (V - 128)
37
+ G = Y - 0.394 * (U - 128) - 0.581 * (V - 128)
38
+ B = Y + 2.032 * (U - 128)
39
+ return tf.concat([R, G, B], axis=3)
40
+
41
+
42
+ def VGG2RGB(x):
43
+ return (x + [103.939, 116.779, 123.68])[:, :, :, ::-1]
44
+
45
+
46
+ def blur(x):
47
+ return Smoother({'data': tf.pad(x, [[0, 0], [9, 9], [9, 9], [0, 0]], 'SYMMETRIC')}, 7, 2).get_output()[:, 9: -9, 9: -9, :]
48
+
49
+
50
+ def norm_feature(x, core):
51
+ cs0 = tf.shape(core)[1]
52
+ cs1 = tf.shape(core)[2]
53
+ small = tf.image.resize_area(x, (cs0, cs1))
54
+ avged = tf.nn.avg_pool(tf.pad(small, [[0, 0], [2, 2], [2, 2], [0, 0]], 'REFLECT'), [1, 5, 5, 1], [1, 1, 1, 1], 'VALID')
55
+ return tf.image.resize_bicubic(avged, tf.shape(x)[1:3])
56
+
57
+
58
+ def upsample(x):
59
+ return K.resize_images(x, 2, 2, 'channels_last')
60
+
61
+
62
+ def downsample(x):
63
+ return tf.nn.avg_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
64
+
65
+
66
+ def nts(x):
67
+ return (x + [103.939, 116.779, 123.68])[:, :, :, ::-1] / 255.0
68
+
69
+
70
+ session = keras.backend.get_session()
71
+
72
+ ip1 = tf.placeholder(dtype=tf.float32, shape=(None, None, None, 1))
73
+ ip3 = tf.placeholder(dtype=tf.float32, shape=(None, None, None, 3))
74
+ ip4 = tf.placeholder(dtype=tf.float32, shape=(None, None, None, 4))
75
+
76
+ print('1')
77
+
78
+ vector = make_diff_net()
79
+ vector_op = 255.0 - tf.nn.sigmoid(vector(ip3 / 255.0)) * 255.0
80
+
81
+ print('4')
82
+
83
+ reader = load_model('./nets/reader.net')
84
+ features = reader(ip3 / 255.0)
85
+
86
+ print('5')
87
+
88
+ head = load_model('./nets/head.net')
89
+ feed = [1 - ip1 / 255.0, (ip4[:, :, :, 0:3] / 127.5 - 1) * ip4[:, :, :, 3:4] / 255.0]
90
+ for _ in range(len(features)):
91
+ feed.append(keras.backend.mean(features[_], axis=[1, 2]))
92
+ nil0, nil1, head_temp = head(feed)
93
+
94
+ print('6')
95
+
96
+ neck = load_model('./nets/neck.net')
97
+ nil2, nil3, neck_temp = neck(feed)
98
+ feed[0] = tf.clip_by_value(1 - tf.image.resize_bilinear(ToGray(VGG2RGB(head_temp) / 255.0), tf.shape(ip1)[1:3]), 0.0, 1.0)
99
+ nil4, nil5, head_temp = neck(feed)
100
+ head_op = VGG2RGB(head_temp)
101
+ neck_op = VGG2RGB(neck_temp)
102
+
103
+ print('7')
104
+
105
+ inception = load_model('./nets/inception.net')
106
+ features_render = inception((ip3 + (downsample(ip1) - blur(downsample(ip1))) * 2.0) / 255.0)
107
+ precessed_feed = [(ip4[:, :, :, 0:3] / 127.5 - 1) * ip4[:, :, :, 3:4] / 255.0] + [
108
+ norm_feature(item, features_render[-1]) for item in features_render]
109
+
110
+ print('8')
111
+
112
+ render_head = load_model('./nets/render_head.net')
113
+ render_neck = load_model('./nets/render_neck.net')
114
+ nil6, nil7, render_A = render_head([1 - ip1 / 255.0] + precessed_feed)
115
+ nil8, nil9, render_B = render_neck(
116
+ [1 - tf.image.resize_bilinear(ToGray(nts(render_A)), tf.shape(ip1)[1:3])] + precessed_feed)
117
+ render_op = nts(render_B) * 255.0
118
+
119
+ print('9')
120
+
121
+ tail = load_model('./nets/tail.net')
122
+ pads = 7
123
+ tail_op = tail(tf.pad(ip3 / 255.0, [[0, 0], [pads, pads], [pads, pads], [0, 0]], 'REFLECT'))[:, pads * 2:-pads * 2, pads * 2:-pads * 2, :][:, 1:-1, 1:-1, :] * 255.0
124
+
125
+ print('10')
126
+
127
+
128
+ vgg7 = load_model('./nets/vgg7.net')
129
+ pads = 7
130
+ vgg7_op = vgg7(tf.pad(ip1 / 255.0, [[0, 0], [pads, pads], [pads, pads], [0, 0]], 'REFLECT'))[:, pads:-pads, pads:-pads, :] * 255.0
131
+
132
+ print('11')
133
+
134
+
135
+ mat = make_unet512()
136
+ mat_op = mat(ip3 / 255.0) * 255.0
137
+
138
+ print('11')
139
+
140
+ norm = load_model('./nets/norm.net')
141
+ norm_op = norm(ip1 / 255.0) * 255.0
142
+
143
+ print('12')
144
+
145
+ session.run(tf.global_variables_initializer())
146
+
147
+ print('begin load')
148
+
149
+
150
+ tail.load_weights('./nets/tail.net')
151
+ vgg7.load_weights('./nets/vgg7.net')
152
+ head.load_weights('./nets/head.net')
153
+ neck.load_weights('./nets/neck.net')
154
+ reader.load_weights('./nets/reader.net')
155
+ vector.load_weights('./nets/vector.net')
156
+ render_head.load_weights('./nets/render_head.net')
157
+ render_neck.load_weights('./nets/render_neck.net')
158
+ inception.load_weights('./nets/inception.net')
159
+ mat.load_weights('./nets/mat.net')
160
+ norm.load_weights('./nets/norm.net')
161
+
162
+
163
+ def go_head(sketch, global_hint, local_hint):
164
+ return session.run(head_op, feed_dict={
165
+ ip1: sketch[None, :, :, None], ip3: global_hint[None, :, :, :], ip4: local_hint[None, :, :, :]
166
+ })[0].clip(0, 255).astype(np.uint8)
167
+
168
+
169
+ def go_render(sketch, segmentation, points):
170
+ return session.run(render_op, feed_dict={
171
+ ip1: sketch[None, :, :, None], ip3: segmentation[None, :, :, :], ip4: points[None, :, :, :]
172
+ })[0].clip(0, 255).astype(np.uint8)
173
+
174
+
175
+ def go_tail(x):
176
+ return session.run(tail_op, feed_dict={
177
+ ip3: x[None, :, :, :]
178
+ })[0].clip(0, 255).astype(np.uint8)
179
+
180
+
181
+ def go_vgg7(x):
182
+ return session.run(vgg7_op, feed_dict={
183
+ ip1: x[None, :, :, None]
184
+ })[0, :, :, 0].clip(0, 255).astype(np.uint8)
185
+
186
+
187
+ def go_vector(x):
188
+ return session.run(vector_op, feed_dict={
189
+ ip3: x[None, :, :, :]
190
+ })[0].clip(0, 255).astype(np.uint8)
191
+
192
+
193
+ def go_mat(x):
194
+ return session.run(mat_op, feed_dict={
195
+ ip3: x[None, :, :, :]
196
+ })[0, :, :, 0].clip(0, 255).astype(np.uint8)
197
+
198
+
199
+ def go_norm(x):
200
+ return session.run(norm_op, feed_dict={
201
+ ip1: x[None, :, :, None]
202
+ })[0].clip(0, 255).astype(np.uint8)
203
+
app.py ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import base64
3
+ import datetime
4
+ import sys
5
+ import pickle
6
+ import gzip
7
+ import json
8
+ import time
9
+ import gradio as gr
10
+
11
+ from ai import *
12
+ from tricks import *
13
+ from decompositioner import *
14
+ from rendering import *
15
+
16
+
17
+ import os
18
+ import glob
19
+ import shutil
20
+
21
+ splash = glob.glob('ui/web-mobile/splash*')[0]
22
+ os.remove(splash)
23
+ shutil.copy('res/splash.png', splash)
24
+ with open('ui/web-mobile/index.html', 'r', encoding='utf-8') as f:
25
+ page = f.read()
26
+ with open('ui/web-mobile/index.html', 'w', encoding='utf-8') as f:
27
+ f.write(page.replace('Cocos Creator | ', ''))
28
+
29
+
30
+ def cv2_encode(image: np.ndarray, name):
31
+ if image is None:
32
+ return 'null'
33
+ if '.jpg' in name:
34
+ _, data = cv2.imencode('.jpeg', image)
35
+ return 'data:image/jpeg;base64,' + base64.b64encode(data).decode('utf8')
36
+ else:
37
+ _, data = cv2.imencode('.png', image)
38
+ return 'data:image/png;base64,' + base64.b64encode(data).decode('utf8')
39
+
40
+
41
+ def get_request_image(request, name):
42
+ img = request.get(name)
43
+ img = re.sub('^data:image/.+;base64,', '', img)
44
+ img = base64.b64decode(img)
45
+ img = np.fromstring(img, dtype=np.uint8)
46
+ img = cv2.imdecode(img, -1)
47
+ return img
48
+
49
+
50
+ def npcache(history, room_id, name, data):
51
+ rooms = list(filter(lambda _room: _room["id"] == room_id, history))
52
+ if len(rooms) == 0:
53
+ room = { "id": room_id }
54
+ history.append(room)
55
+ else:
56
+ room = rooms[0]
57
+ room[name] = data
58
+
59
+
60
+ def npread(history, room_id, name):
61
+ rooms = list(filter(lambda _room: _room["id"] == room_id, history))
62
+ if len(rooms) == 0:
63
+ return None
64
+ else:
65
+ room = rooms[0]
66
+ return room.get(name, None)
67
+
68
+
69
+ def upload_sketch(json_str, history):
70
+ request = json.loads(json_str)
71
+ timenow = time.time()
72
+ ID = datetime.datetime.now().strftime('H%HM%MS%S')
73
+ room = datetime.datetime.now().strftime('%b%dH%HM%MS%S') + 'R' + str(np.random.randint(100, 999))
74
+ sketch = from_png_to_jpg(get_request_image(request, 'sketch'))
75
+ npcache(history, room, 'sketch.original.jpg', sketch)
76
+ sketch = go_tail(cli_norm(min_resize(sketch, 512)))
77
+ print('original_sketch saved')
78
+ s256 = go_vector(go_cal(mk_resize(sketch, 8)))[:, :, 0]
79
+ print('s256')
80
+ s512 = go_vector(go_cal(d_resize(sketch, s256.shape, 2.0)))[:, :, 0]
81
+ print('s512')
82
+ s1024 = go_vector(go_cal(d_resize(sketch, s256.shape, 4.0)))[:, :, 0]
83
+ print('s1024')
84
+ npcache(history, room, 'sketch.s1024.png', s1024)
85
+ npcache(history, room, 'sketch.s512.png', s512)
86
+ npcache(history, room, 'sketch.s256.png', s256)
87
+ print('edge processed')
88
+ fill = double_fill(s1024, s512, s256)
89
+ npcache(history, room, 'sketch.fill', fill)
90
+ print('filled')
91
+ npcache(history, room, 'sketch.colorization.png', np.min(sketch, axis=2))
92
+ print('sketch processed')
93
+ print(time.time() - timenow)
94
+ if len(history) > 5:
95
+ history = history[-5:]
96
+ return room + '_' + ID, history
97
+
98
+
99
+ def request_result(json_str, history):
100
+ request = json.loads(json_str)
101
+ timenow = time.time()
102
+ room = request.get("room")
103
+ if len(list(filter(lambda _room: _room["id"] == room, history))) == 0:
104
+ return None, history
105
+ skipper = str(request.get("skipper"))
106
+ light_r = float(request.get("r"))
107
+ light_g = float(request.get("g"))
108
+ light_b = float(request.get("b"))
109
+ light_h = float(request.get("h"))
110
+ light_max = max([light_r, light_g, light_b, light_h])
111
+ inv4 = int(request.get("inv4"))
112
+ print('inv4=' + str(inv4))
113
+ light_r = (light_r + 1e-5) / (light_max + 1e-5)
114
+ light_g = (light_g + 1e-5) / (light_max + 1e-5)
115
+ light_b = (light_b + 1e-5) / (light_max + 1e-5)
116
+ light_h *= 600.0
117
+ light_d = request.get("d")
118
+ need_render = int(request.get("need_render"))
119
+ print([light_r, light_g, light_b, light_d])
120
+ ID = datetime.datetime.now().strftime('H%HM%MS%S')
121
+ points = request.get("points")
122
+ points = json.loads(points)
123
+ npcache(history, room, 'points.' + ID + '.txt', points)
124
+ if len(points) > 500:
125
+ return None, history
126
+ for _ in range(len(points)):
127
+ points[_][1] = 1 - points[_][1]
128
+ fill = npread(history, room, 'sketch.fill')
129
+ s1024 = npread(history, room, 'sketch.s1024.png')
130
+ sketch = npread(history, room, 'sketch.colorization.png')
131
+ print(skipper)
132
+ if npread(history, room, 'albedo.' + skipper + '.png') is not None:
133
+ albedo = npread(history, room, 'albedo.' + skipper + '.png')
134
+ npcache(history, room, 'albedo.' + ID + '.png', albedo)
135
+ print('albedo readed')
136
+ else:
137
+ faceID = int(request.get("faceID")) - 65535
138
+ print(faceID)
139
+ if faceID > -1:
140
+ print('fake ref')
141
+ face = from_png_to_jpg(cv2.imread("refs/" + str(faceID + 1) + ".png", cv2.IMREAD_UNCHANGED))
142
+ else:
143
+ print('get ref')
144
+ face = from_png_to_jpg(get_request_image(request, 'face'))
145
+ npcache(history, room, 'face.' + ID + '.jpg', face)
146
+ face = s_enhance(face)
147
+ print('request result room = ' + str(room) + ', ID = ' + str(ID))
148
+ print('processing painting in ' + room)
149
+ if inv4 > 0:
150
+ sketch_1024 = k_resize(sketch, 64)
151
+ else:
152
+ sketch_1024 = k_resize(sketch, 48)
153
+ hints_1024 = ini_hint(sketch_1024)
154
+ hints_1024 = opreate_normal_hint(hints_1024, points, length=2, skip_sp=True)
155
+ baby = go_head(
156
+ sketch=sketch_1024,
157
+ global_hint=k_resize(face, 14),
158
+ local_hint=hints_1024
159
+ )
160
+ npcache(history, room, 'baby.' + ID + '.jpg', baby)
161
+ print('baby born')
162
+ composition = d_resize(re_deatlize(deatlize(balance_fill(baby, fill, opreate_normal_hint(ini_hint(s1024), points, length=2, skip_sp=True), s1024)), s1024), sketch.shape)
163
+ npcache(history, room, 'composition.' + ID + '.jpg', composition)
164
+ gird = process_overlay(composition, sketch)
165
+ npcache(history, room, 'gird.' + ID + '.jpg', gird)
166
+ print('composition saved')
167
+ if inv4 > 0:
168
+ albedo = go_render(sketch_1024, d_resize(composition, sketch_1024.shape, 0.5), hints_1024)
169
+ albedo = go_tail(albedo)
170
+ albedo = d_resize(re_deatlize(d_resize(albedo, s1024.shape), s1024), sketch.shape)
171
+ albedo = cv2.cvtColor(albedo, cv2.COLOR_RGB2YUV)
172
+ albedo[:, :, 0] = go_vgg7(albedo[:, :, 0])
173
+ albedo = cv2.cvtColor(albedo, cv2.COLOR_YUV2RGB)
174
+ else:
175
+ albedo = re_deatlize(d_resize(baby, s1024.shape), s1024)
176
+ albedo = d_resize(albedo, sketch.shape, 0.25)
177
+ albedo = go_tail(albedo)
178
+ albedo = go_tail(albedo)
179
+ albedo = d_resize(albedo, sketch.shape)
180
+ boundary = sketch.astype(np.float32)
181
+ boundary = cv2.GaussianBlur(boundary, (0, 0), 1.618) - boundary
182
+ boundary = boundary.clip(0, 255)
183
+ albedo = cv2.cvtColor(albedo, cv2.COLOR_RGB2HSV).astype(np.float32)
184
+ albedo[:, :, 1] += albedo[:, :, 1] * boundary / 48.0
185
+ albedo[:, :, 2] -= boundary
186
+ albedo = cv2.cvtColor(albedo.clip(0, 255).astype(np.uint8), cv2.COLOR_HSV2RGB)
187
+ npcache(history, room, 'albedo.' + ID + '.png', albedo)
188
+ print('albedo saved')
189
+ if need_render == 0:
190
+ npcache(history, room, 'result.' + ID + '.jpg', albedo)
191
+ # cv2.imwrite('results/' + room + '.' + ID + '.jpg', albedo)
192
+ print(time.time() - timenow)
193
+ return room + '_' + ID, history
194
+ HSV, YUV, DEL = process_albedo(albedo, composition, sketch)
195
+ npcache(history, room, 'HSV.' + ID + '.jpg', HSV)
196
+ npcache(history, room, 'YUV.' + ID + '.jpg', YUV)
197
+ npcache(history, room, 'DEL.' + ID + '.jpg', DEL)
198
+ print('HSV YUV DEL')
199
+ albedo_s1024 = d_resize(albedo, s1024.shape)
200
+ matting = go_mat(albedo_s1024)
201
+ matting = np.tile(matting[:, :, None], [1, 1, 3])
202
+ matting = shade_fill(matting, fill, opreate_normal_hint(ini_hint(s1024), points, length=2, skip_sp=False), s1024)
203
+ matting = matting[:, :, 0]
204
+ depth = np.zeros_like(matting, dtype=np.uint8) + 255
205
+ depth[matting < 127] = 127
206
+ depth[s1024 < 250] = 0
207
+ npcache(history, room, 'depth.' + ID + '.jpg', depth)
208
+ print('depth saved')
209
+ normal = go_norm(depth).astype(np.float32)
210
+ normal = ((normal + 1e-4) / (np.max(normal, axis=2, keepdims=True) + 1e-4) * 255.0).clip(0, 255).astype(np.uint8)
211
+ normal[matting < 127] = 255
212
+ normal = re_deatlize(normal, s1024)
213
+ normal = d_resize(normal, sketch.shape)
214
+ npcache(history, room, 'normal.' + ID + '.jpg', normal)
215
+ print('norm saved')
216
+ mask = np.zeros_like(matting, dtype=np.uint8) + 255
217
+ mask[matting < 127] = 0
218
+ mask = d_resize(mask, sketch.shape)
219
+ mask[mask < 127] = 0
220
+ mask[mask > 0] = 255
221
+ if int(light_d) == 0:
222
+ result = small_render(normal, mask, albedo, s1024, r=light_r, g=light_g, b=light_b, h=light_h, left=True, top=True)
223
+ elif int(light_d) == 1:
224
+ result = small_render(normal, mask, albedo, s1024, r=light_r, g=light_g, b=light_b, h=light_h, left=False, top=True)
225
+ elif int(light_d) == 2:
226
+ result = small_render(normal, mask, albedo, s1024, r=light_r, g=light_g, b=light_b, h=light_h, left=True, top=False)
227
+ else:
228
+ result = small_render(normal, mask, albedo, s1024, r=light_r, g=light_g, b=light_b, h=light_h, left=False, top=False)
229
+ if need_render == 2:
230
+ npcache(history, room, 'result.' + ID + '.jpg', result)
231
+ # cv2.imwrite('results/' + room + '.' + ID + '.jpg', result)
232
+ print(time.time() - timenow)
233
+ return room + '_' + ID, history
234
+ print('result saved')
235
+ preview = np.concatenate([np.tile(sketch[:, :, None], [1, 1, 3]), albedo, result], axis=1)
236
+ npcache(history, room, 'preview.' + ID + '.jpg', preview)
237
+ print('preview saved')
238
+ npcache(history, room, 'result.' + ID + '.jpg', result)
239
+ # cv2.imwrite('results/' + room + '.' + ID + '.jpg', preview)
240
+ print(time.time() - timenow)
241
+ return room + '_' + ID, history
242
+
243
+
244
+ def download_result(name, history):
245
+ room_id, name = name.split('/')
246
+ rooms = list(filter(lambda _room: _room["id"] == room_id, history))
247
+ if len(rooms) == 0:
248
+ return None
249
+ else:
250
+ room = rooms[0]
251
+
252
+ real_name = None
253
+ for k in room.keys():
254
+ if name in k:
255
+ real_name = k
256
+ break
257
+ if real_name is None:
258
+ return None
259
+ name = real_name
260
+
261
+ result = room.get(name, None)
262
+
263
+ if 'points' in name:
264
+ return json.dumps(result)
265
+
266
+ return cv2_encode(result, name)
267
+
268
+
269
+ with gr.Blocks() as demo:
270
+ history = gr.State(value=[])
271
+ with gr.Row():
272
+ with gr.Column():
273
+ btn_show = gr.Button("Open Style2Paints V4.2")
274
+ btn_show.click(None, _js="(_) => open('file/ui/web-mobile/index.html')")
275
+
276
+ with gr.Row():
277
+ with gr.Box():
278
+ with gr.Row():
279
+ upload_sketch_json = gr.Textbox(label="upload_sketch(json string)")
280
+ with gr.Row():
281
+ upload_sketch_btn = gr.Button(label="Submit sketch json")
282
+ with gr.Row():
283
+ upload_sketch_result = gr.Textbox(label="Result", interactive=False)
284
+ upload_sketch_btn.click(upload_sketch, [upload_sketch_json, history], [upload_sketch_result, history], api_name="upload_sketch")
285
+
286
+ with gr.Box():
287
+ with gr.Row():
288
+ request_result_json = gr.Textbox(label="request_result(json string)")
289
+ with gr.Row():
290
+ request_result_btn = gr.Button(label="Submit json of request for result")
291
+ with gr.Row():
292
+ request_result_result = gr.Textbox(label="Result", interactive=False)
293
+ upload_sketch_btn.click(request_result, [request_result_json, history], [request_result_result, history], api_name="request_result")
294
+
295
+ with gr.Box():
296
+ with gr.Row():
297
+ download_result_json = gr.Textbox(label="download_result(json string)")
298
+ with gr.Row():
299
+ download_result_btn = gr.Button(label="Submit json of download for result")
300
+ with gr.Row():
301
+ download_result_result = gr.Textbox(label="Result", interactive=False)
302
+ upload_sketch_btn.click(download_result, [download_result_json, history], [download_result_result], api_name="download_result")
303
+
304
+ demo.launch()
config.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ multiple_process = True
2
+
decompositioner.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from scipy.spatial import ConvexHull
4
+ from sklearn.cluster import MiniBatchKMeans
5
+ from tricks import *
6
+ import cv2
7
+
8
+
9
+ ksd = 8
10
+ mbc = MiniBatchKMeans(ksd)
11
+
12
+
13
+ def get_theme(img):
14
+ images = np.reshape(cv2.resize(img, (256, 256)), (256 * 256, 3))
15
+ hull = ConvexHull(images)
16
+ return hull.points[hull.vertices]
17
+
18
+
19
+ def simplify_points(points, img):
20
+ labels = mbc.fit(points)
21
+ new_points = []
22
+ all_center = np.mean(labels.cluster_centers_, axis=0)
23
+ distances = np.sum((points - all_center) ** 2, axis=1) ** 0.5
24
+
25
+ for idx in range(ksd):
26
+ candidates = points[labels.labels_ == idx]
27
+ scores = distances[labels.labels_ == idx]
28
+ best_id = np.argmax(scores)
29
+ new_points.append(candidates[best_id])
30
+
31
+ new_points.sort(key=np.sum, reverse=True)
32
+
33
+ new_points = np.stack(new_points, axis=0)
34
+ return new_points.clip(0, 255).astype(np.uint8)
35
+
36
+
37
+ def get_ini_layers(miku, points):
38
+ results = []
39
+ final_target = miku.astype(np.float32)
40
+ bg = np.zeros_like(final_target, dtype=np.float32) + points[0]
41
+ results.append(np.concatenate([bg, np.zeros_like(bg, dtype=np.float32) + 255], axis=2)[:, :, 0:4])
42
+ current_result = bg.copy()
43
+ for layer_index in range(1, ksd):
44
+ current_base = current_result.astype(np.float32)
45
+ current_color = np.zeros_like(final_target, dtype=np.float32) + points[layer_index]
46
+ overall_direction = final_target - current_base
47
+ avaliable_direction = current_color - current_base
48
+ current_alpha = np.sum(overall_direction * avaliable_direction, axis=2, keepdims=True) / np.sum(
49
+ avaliable_direction * avaliable_direction, axis=2, keepdims=True)
50
+ current_alpha = current_alpha.clip(0, 1)
51
+ current_result = (current_color * current_alpha + current_base * (1 - current_alpha)).clip(0, 255)
52
+ results.append(np.concatenate([current_color, current_alpha * 255.0], axis=2))
53
+ return results
54
+
55
+
56
+ def make_reconstruction(layers):
57
+ bg = np.zeros_like(layers[0], dtype=np.float32)[:, :, 0:3] + 255
58
+ for item in layers:
59
+ current_alpha = item[:, :, 3:4] / 255.0
60
+ bg = item[:, :, 0:3] * current_alpha + bg * (1 - current_alpha)
61
+ return bg
62
+
63
+
64
+ def improve_layers(layers, miku):
65
+ reconstruction = make_reconstruction(layers)
66
+ b = miku - reconstruction
67
+ new_layers = []
68
+ for item in layers:
69
+ new_item = item.copy()
70
+ new_item[:, :, 0:3] = (new_item[:, :, 0:3] + b).clip(0, 255)
71
+ new_layers.append(new_item)
72
+ return new_layers
73
+
74
+
75
+ def cluster_all(labeled_array, num_features):
76
+ xs = [[] for _ in range(num_features)]
77
+ ys = [[] for _ in range(num_features)]
78
+ M = labeled_array.shape[0]
79
+ N = labeled_array.shape[1]
80
+ for x in range(M):
81
+ for y in range(N):
82
+ i = labeled_array[x, y]
83
+ xs[i].append(x)
84
+ ys[i].append(y)
85
+ result = []
86
+ for _ in range(num_features):
87
+ result.append((np.array(xs[_]), np.array(ys[_])))
88
+ return result
89
+
90
+
91
+ def meder(x):
92
+ y = x.copy()
93
+ y = cv2.medianBlur(y, 5)
94
+ y = cv2.medianBlur(y, 5)
95
+ y = cv2.medianBlur(y, 3)
96
+ y = cv2.medianBlur(y, 3)
97
+ return y
98
+
99
+
100
+ def re_med(s_2048):
101
+
102
+ sample_2048 = s_2048.astype(np.float32)
103
+ sample_1024 = cv2.pyrDown(sample_2048)
104
+ sample_512 = cv2.pyrDown(sample_1024)
105
+ sample_256 = cv2.pyrDown(sample_512)
106
+
107
+ gradient_2048 = sample_2048 - cv2.pyrUp(sample_1024)
108
+ gradient_1024 = sample_1024 - cv2.pyrUp(sample_512)
109
+ gradient_512 = sample_512 - cv2.pyrUp(sample_256)
110
+
111
+ rec_256 = meder(sample_256)
112
+ rec_512 = cv2.pyrUp(rec_256) + meder(gradient_512)
113
+ rec_1024 = cv2.pyrUp(rec_512) + meder(gradient_1024)
114
+ rec_2048 = cv2.pyrUp(rec_1024) + meder(gradient_2048)
115
+ return rec_2048
116
+
117
+
118
+ def process_ctx(sketch, solid, render):
119
+ solid = solid.astype(np.float32)
120
+ sketch = d_resize(cv2.cvtColor(sketch, cv2.COLOR_GRAY2RGB), solid.shape).astype(np.float32)
121
+ render = d_resize(render, solid.shape).astype(np.float32)
122
+ alpha = sketch / 255.0
123
+ all_diff = render - solid
124
+ all_lines = render.copy()
125
+ all_lines = cv2.erode(all_lines, np.ones((3,3), np.uint8)) * 0.618
126
+ all_diff = re_med(all_diff)
127
+ all_lines = re_med(all_lines)
128
+ recon = solid + all_diff
129
+ recon = recon * alpha + all_lines * (1 - alpha)
130
+ recon2 = (solid + all_diff) * alpha + re_med(solid) * (1 - alpha)
131
+ recon3 = reason_blending(recon2, sketch)
132
+ return recon.clip(0, 255).astype(np.uint8), recon2.clip(0, 255).astype(np.uint8), recon3.clip(0, 255).astype(np.uint8)
133
+
134
+
135
+ def process_psd(sketch, solid, render, path='./'):
136
+ recon = process_ctx(sketch, solid, render)
137
+ points = get_theme(solid)
138
+ points = simplify_points(points, solid)
139
+ compositions = get_ini_layers(solid, points)
140
+ compositions = improve_layers(compositions, solid)
141
+ for _ in range(ksd):
142
+ cv2.imwrite(path + str(_ + 1) + '.color.png', compositions[_].clip(0, 255).astype(np.uint8))
143
+ solid = make_reconstruction(compositions).clip(0, 255).astype(np.uint8)
144
+ os.makedirs(path, exist_ok=True)
145
+ alpha = 1 - sketch.astype(np.float32) / 255.0
146
+ now = solid
147
+ now = (now.astype(np.float32) + sketch.astype(np.float32) - 255.0).clip(0, 255)
148
+ sketch = 255 + now - solid
149
+ cv2.imwrite(path + '9.sketch.png', sketch.clip(0, 255).astype(np.uint8))
150
+ all_diff = recon.astype(np.float32) - now
151
+ all_light = all_diff.copy()
152
+ all_shadow = - all_diff.copy()
153
+ all_light[all_light < 0] = 0
154
+ all_shadow[all_shadow < 0] = 0
155
+ sketch_color = all_light * alpha
156
+ light = all_light * (1 - alpha)
157
+ all_shadow = 255 - all_shadow
158
+ cv2.imwrite(path + '10.sketch_color.png', sketch_color.clip(0, 255).astype(np.uint8))
159
+ cv2.imwrite(path + '11.light.png', light.clip(0, 255).astype(np.uint8))
160
+ cv2.imwrite(path + '12.shadow.png', all_shadow.clip(0, 255).astype(np.uint8))
161
+ return recon
162
+
163
+
164
+ def process_albedo(albedo, composition, sketch):
165
+ DEL = albedo.astype(np.float32)
166
+ HSV = cv2.cvtColor(albedo, cv2.COLOR_RGB2HSV).astype(np.float32)
167
+ YUV = cv2.cvtColor(albedo, cv2.COLOR_RGB2YUV).astype(np.float32)
168
+ solid = composition.astype(np.float32)
169
+ light = sketch[:, :, None].astype(np.float32)
170
+
171
+ DEL = DEL * light / 255.0 + solid * (1 - light / 255.0)
172
+ HSV[:, :, 2:3] = np.minimum(HSV[:, :, 2:3], light)
173
+ YUV[:, :, 0:1] = np.minimum(YUV[:, :, 0:1], light)
174
+
175
+ DEL = DEL.clip(0, 255).astype(np.uint8)
176
+ HSV = HSV.clip(0, 255).astype(np.uint8)
177
+ YUV = YUV.clip(0, 255).astype(np.uint8)
178
+
179
+ return cv2.cvtColor(HSV, cv2.COLOR_HSV2RGB), cv2.cvtColor(YUV, cv2.COLOR_YUV2RGB), DEL
180
+
181
+
182
+ def process_overlay(composition, sketch):
183
+ RGB = composition.astype(np.float32)
184
+ alpha = sketch[:, :, None].astype(np.float32) / 255.0
185
+ return (RGB * alpha).clip(0, 255).astype(np.uint8)
generate_bash.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ lines = []
2
+
3
+ for _ in range(50, 66):
4
+ lines.append("screen -dmS \"server.80"+str(_)+"\" bash -c \'while : ;do python3 server.py 80"+str(_)+"; done;\'\n")
5
+
6
+ with open('run.bash', 'wt') as f:
7
+ f.writelines(lines)
8
+
9
+ lines = []
10
+
11
+ for _ in range(50, 66):
12
+ lines.append("screen -S \"server.80"+str(_)+"\" -X quit\n")
13
+
14
+ with open('kill.bash', 'wt') as f:
15
+ f.writelines(lines)
16
+
17
+ lines = []
18
+
19
+ for _ in range(50, 66):
20
+ lines.append("server 127.0.0.1:80"+str(_)+" weight=4 max_fails=2 fail_timeout=600s;\n")
21
+
22
+ with open('nginx.txt', 'wt') as f:
23
+ f.writelines(lines)
24
+
25
+ lines = ["ufw allow 80/tcp\n"]
26
+
27
+ for _ in range(50, 66):
28
+ lines.append("ufw allow 80"+str(_)+"/tcp\n")
29
+
30
+ with open('tcp.bash', 'wt') as f:
31
+ f.writelines(lines)
32
+
33
+ #/etc/nginx/sites-available
34
+ #/var/log/nginx
35
+
linefiller/__init__.py ADDED
File without changes
linefiller/thinning.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import cv2
3
+ from numba import njit
4
+
5
+
6
+ @njit
7
+ def njit_thin(points, maps):
8
+ result = maps.copy()
9
+ h, w = maps.shape[:2]
10
+ for _ in range(len(points[0])):
11
+ x = points[0][_]
12
+ y = points[1][_]
13
+ if x > 0:
14
+ a = maps[x-1, y]
15
+ if a > 0:
16
+ result[x, y] = a
17
+ continue
18
+ if y > 0:
19
+ a = maps[x, y-1]
20
+ if a > 0:
21
+ result[x, y] = a
22
+ continue
23
+ if x + 1 < h:
24
+ a = maps[x+1, y]
25
+ if a > 0:
26
+ result[x, y] = a
27
+ continue
28
+ if y + 1 < w:
29
+ a = maps[x, y+1]
30
+ if a > 0:
31
+ result[x, y] = a
32
+ continue
33
+ return result
34
+
35
+
36
+ def thinning(fillmap, max_iter=100):
37
+ result = fillmap.copy()
38
+ for iterNum in range(max_iter):
39
+ line_points = np.where(result == 0)
40
+ if not len(line_points[0]) > 0:
41
+ break
42
+ result = njit_thin(line_points, result)
43
+ return result
44
+
linefiller/third_party.py ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ from .thinning import *
3
+ from .trappedball_fill import *
4
+ from skimage.measure import block_reduce
5
+ from skimage.morphology import disk, dilation, erosion
6
+ from numba import njit
7
+
8
+
9
+ def np_min_pool(x):
10
+ return block_reduce(x, (2, 2), np.min)
11
+
12
+
13
+ def np_max_pool(x):
14
+ return block_reduce(x, (2, 2), np.max)
15
+
16
+
17
+ def np_max_441(x):
18
+ return block_reduce(x, (4, 4, 1), np.max)
19
+
20
+
21
+ def np_max_pool_221(x):
22
+ return block_reduce(x, (2, 2, 1), np.max)
23
+
24
+
25
+ def np_max_pool_s(x, s):
26
+ return block_reduce(x, (s, s, 1), np.max)
27
+
28
+
29
+ def binarize(x):
30
+ xp = x.copy()
31
+ xp[xp < 250] = 0
32
+ xp[xp > 0] = 255
33
+ return xp
34
+
35
+
36
+ def get_initial_fillmap(boundary, merge=True):
37
+ fillmap = build_fill_map(boundary, flood_fill_multi(boundary, merge=merge))
38
+ return fillmap
39
+
40
+
41
+ def up_propagate(small_fillmap, big_boundary):
42
+ new_fillmap = cv2.resize(small_fillmap, (big_boundary.shape[1], big_boundary.shape[0]), interpolation=cv2.INTER_NEAREST)
43
+ padded_fillmap = np.pad(new_fillmap, [[1, 1], [1, 1]], 'constant', constant_values=0)
44
+ new_mask = np.ones_like(new_fillmap, dtype=np.uint8) * 255
45
+ new_mask[new_fillmap > 0] = 0
46
+ new_mask[big_boundary < 240] = 0
47
+ fills = flood_fill_multi(new_mask, merge=True)
48
+ max_id = np.max(new_fillmap)
49
+ for item in fills:
50
+ points0 = padded_fillmap[(item[0] + 1, item[1] + 0)]
51
+ points1 = padded_fillmap[(item[0] + 1, item[1] + 2)]
52
+ points2 = padded_fillmap[(item[0] + 0, item[1] + 1)]
53
+ points3 = padded_fillmap[(item[0] + 2, item[1] + 1)]
54
+
55
+ all_points = np.concatenate([points0, points1, points2, points3], axis=0)
56
+ pointsets, pointcounts = np.unique(all_points[all_points > 0], return_counts=True)
57
+
58
+ if len(pointsets) > 0:
59
+ new_fillmap[item] = pointsets[np.argmax(pointcounts)]
60
+ else:
61
+ max_id += 1
62
+ new_fillmap[item] = max_id
63
+ return new_fillmap
64
+
65
+
66
+ def laplas_fill(b_512, b_256, b_128):
67
+ b_512 = binarize(b_512)
68
+ b_256 = binarize(b_256)
69
+ b_128 = binarize(b_128)
70
+ f128 = get_initial_fillmap(b_128)
71
+ f256 = up_propagate(f128, b_256)
72
+ f512 = up_propagate(f256, b_512)
73
+ fin = thinning(f512)
74
+ return fin
75
+
76
+
77
+ @ njit
78
+ def get_corner(x):
79
+ corner = x.copy()
80
+ s0 = corner.shape[0]
81
+ s1 = corner.shape[1]
82
+ for i0 in range(1, s0 - 1):
83
+ for i1 in range(1, s1 - 1):
84
+ if x[i0, i1] == 0:
85
+ continue
86
+ if x[i0, i1 - 1] == 0:
87
+ if x[i0 - 1, i1 - 1] == 0:
88
+ continue
89
+ if x[i0 + 1, i1 - 1] == 0:
90
+ continue
91
+ corner[i0, i1] = 0
92
+ continue
93
+ if x[i0, i1 + 1] == 0:
94
+ if x[i0 - 1, i1 + 1] == 0:
95
+ continue
96
+ if x[i0 + 1, i1 + 1] == 0:
97
+ continue
98
+ corner[i0, i1] = 0
99
+ continue
100
+ if x[i0 - 1, i1] == 0:
101
+ if x[i0 - 1, i1 - 1] == 0:
102
+ continue
103
+ if x[i0 - 1, i1 + 1] == 0:
104
+ continue
105
+ corner[i0, i1] = 0
106
+ continue
107
+ if x[i0 + 1, i1] == 0:
108
+ if x[i0 + 1, i1 - 1] == 0:
109
+ continue
110
+ if x[i0 + 1, i1 + 1] == 0:
111
+ continue
112
+ corner[i0, i1] = 0
113
+ continue
114
+ return corner
115
+
116
+
117
+ def monogrouh(x):
118
+ y = 255 - x
119
+ y = dilation(y, disk(1))
120
+ y = dilation(y, disk(1))
121
+ y = erosion(y, disk(1))
122
+ y = erosion(y, disk(1))
123
+ y = 255 - y
124
+ return y
125
+
126
+
127
+ def corners(x):
128
+ y = x.copy()
129
+ y = monogrouh(y)
130
+ y = get_corner(y)
131
+ y = monogrouh(y)
132
+ y = get_corner(y)
133
+ y = monogrouh(y)
134
+ return y
135
+
136
+
137
+ def save_fill(name, fill):
138
+ cv2.imwrite(name, show_fill_map(fill))
139
+
140
+
141
+ def double_fill(b_1024, b_512, b256):
142
+ b256 = binarize(b256)
143
+ b_512 = binarize(b_512)
144
+ b_1024 = binarize(b_1024)
145
+ b_1024 = corners(b_1024)
146
+ b_512 = np.min(np.stack([b_512, np_min_pool(b_1024)], axis=2), axis=2)
147
+ b_512 = corners(b_512)
148
+ b_256 = np.min(np.stack([b256, np_min_pool(b_512)], axis=2), axis=2)
149
+ b_256 = corners(b_256)
150
+ b_128 = np_min_pool(b_256)
151
+ b_128 = corners(b_128)
152
+ b_64 = np_min_pool(b_128)
153
+ f64 = get_initial_fillmap(b_64)
154
+ print('get_initial_fillmap(b_64)')
155
+ f128 = up_propagate(f64, b_128)
156
+ print('up_propagate(f64, b_128)')
157
+ f256 = up_propagate(f128, b_256)
158
+ print('up_propagate(f128, b_256)')
159
+ f512 = up_propagate(f256, b_512)
160
+ print('up_propagate(f256, b_512)')
161
+ f1024 = up_propagate(f512, b_1024)
162
+ print('up_propagate(f512, b_1024)')
163
+ fin = thinning(f1024)
164
+ print('thinning(f1024)')
165
+
166
+ # cv2.imwrite('b_64.png', b_64)
167
+ # cv2.imwrite('b_128.png', b_128)
168
+ # cv2.imwrite('b_256.png', b_256)
169
+ # cv2.imwrite('b_512.png', b_512)
170
+ # cv2.imwrite('b_1024.png', b_1024)
171
+ # save_fill('f64.png', f64)
172
+ # save_fill('f128.png', f128)
173
+ # save_fill('f256.png', f256)
174
+ # save_fill('f512.png', f512)
175
+ # save_fill('f1024.png', f1024)
176
+ # save_fill('fin.png', fin)
177
+
178
+ return find_all(fin)
179
+
180
+
181
+ def single_fill(b_2048, path):
182
+ b_2048 = corners(binarize(b_2048))
183
+ f2048 = get_initial_fillmap(b_2048, merge=False)
184
+ print(path + 'get_initial_fillmap(b_2048, merge=False)')
185
+ fin = thinning(f2048)
186
+ print(path + 'thinning(f2048)')
187
+ # cv2.imwrite(path + 'b_2048.png', b_2048)
188
+ # save_fill(path + 'f2048.png', f2048)
189
+ # save_fill(path + 'fin.png', fin)
190
+ return find_all(fin)
191
+
192
+
193
+ def deatlize(x):
194
+ x = cv2.GaussianBlur(x, (0, 0), 0.8)
195
+ x = cv2.medianBlur(x, 3)
196
+ return x
197
+
198
+
199
+ def low_down(gradient_mask):
200
+ return 1.0 - cv2.dilate(255 - gradient_mask, np.ones((3, 3), np.uint8), iterations=2).astype(np.float32) / 255.0
201
+
202
+
203
+ def cv2pyrDown(x):
204
+ return cv2.pyrDown(cv2.medianBlur(cv2.medianBlur(x, 3), 3))
205
+
206
+
207
+ def cv2pyrUp(x):
208
+ return cv2.pyrUp(cv2.medianBlur(cv2.medianBlur(x, 3), 3))
209
+
210
+
211
+ def re_deatlize(visulized, s1024):
212
+
213
+ gradient_mask_1024 = binarize(s1024)
214
+ gradient_mask_512 = np_min_pool(gradient_mask_1024)
215
+ gradient_mask_256 = np_min_pool(gradient_mask_512)
216
+ gradient_mask_128 = np_min_pool(gradient_mask_256)
217
+ gradient_mask_64 = np_min_pool(gradient_mask_128)
218
+
219
+ gradient_mask_1024 = low_down(gradient_mask_1024)
220
+ gradient_mask_512 = low_down(gradient_mask_512)
221
+ gradient_mask_256 = low_down(gradient_mask_256)
222
+ gradient_mask_128 = low_down(gradient_mask_128)
223
+ gradient_mask_64 = low_down(gradient_mask_64)
224
+
225
+ sample_1024 = visulized.astype(np.float32)
226
+ sample_512 = cv2pyrDown(sample_1024)
227
+ sample_256 = cv2pyrDown(sample_512)
228
+ sample_128 = cv2pyrDown(sample_256)
229
+ sample_64 = cv2pyrDown(sample_128)
230
+ sample_32 = cv2pyrDown(sample_64)
231
+
232
+ gradient_1024 = sample_1024 - cv2pyrUp(sample_512)
233
+ gradient_512 = sample_512 - cv2pyrUp(sample_256)
234
+ gradient_256 = sample_256 - cv2pyrUp(sample_128)
235
+ gradient_128 = sample_128 - cv2pyrUp(sample_64)
236
+ gradient_64 = sample_64 - cv2pyrUp(sample_32)
237
+
238
+ rec_32 = sample_32
239
+ rec_64 = cv2pyrUp(rec_32) + gradient_64 * (1 - gradient_mask_64[:, :, None])
240
+ rec_128 = cv2pyrUp(rec_64) + gradient_128 * (1 - gradient_mask_128[:, :, None])
241
+ rec_256 = cv2pyrUp(rec_128) + gradient_256 * (1 - gradient_mask_256[:, :, None])
242
+ rec_512 = cv2pyrUp(rec_256) + gradient_512 * (1 - gradient_mask_512[:, :, None])
243
+ rec_1024 = cv2pyrUp(rec_512) + gradient_1024 * (1 - gradient_mask_1024[:, :, None])
244
+
245
+ return rec_1024.clip(0, 255).astype(np.uint8)
246
+
247
+
248
+ def tiny_deatlize(visulized, s2048):
249
+ gradient_mask_2048 = s2048.copy()
250
+ gradient_mask_1024 = np_min_pool(gradient_mask_2048)
251
+ gradient_mask_512 = np_min_pool(gradient_mask_1024)
252
+ gradient_mask_256 = np_min_pool(gradient_mask_512)
253
+
254
+ gradient_mask_2048 = low_down(gradient_mask_2048)
255
+ gradient_mask_1024 = low_down(gradient_mask_1024)
256
+ gradient_mask_512 = low_down(gradient_mask_512)
257
+ gradient_mask_256 = low_down(gradient_mask_256)
258
+
259
+ sample_2048 = visulized.astype(np.float32)
260
+ sample_1024 = cv2.pyrDown(sample_2048)
261
+ sample_512 = cv2.pyrDown(sample_1024)
262
+ sample_256 = cv2.pyrDown(sample_512)
263
+ sample_128 = cv2.pyrDown(sample_256)
264
+
265
+ gradient_2048 = sample_2048 - cv2.pyrUp(sample_1024)
266
+ gradient_1024 = sample_1024 - cv2.pyrUp(sample_512)
267
+ gradient_512 = sample_512 - cv2.pyrUp(sample_256)
268
+ gradient_256 = sample_256 - cv2.pyrUp(sample_128)
269
+
270
+ rec_128 = sample_128
271
+ rec_256 = cv2.pyrUp(rec_128) + gradient_256 * (1 - gradient_mask_256[:, :, None])
272
+ rec_512 = cv2.pyrUp(rec_256) + gradient_512 * (1 - gradient_mask_512[:, :, None])
273
+ rec_1024 = cv2.pyrUp(rec_512) + gradient_1024 * (1 - gradient_mask_1024[:, :, None])
274
+ rec_2048 = cv2.pyrUp(rec_1024) + gradient_2048 * (1 - gradient_mask_2048[:, :, None])
275
+ return rec_2048.clip(0, 255).astype(np.uint8)
276
+
277
+
278
+ def adain(x, y):
279
+ x_high = cv2.GaussianBlur(x, (0, 0), 3.0)
280
+ y_high = cv2.GaussianBlur(y, (0, 0), 3.0)
281
+ return (x.astype(np.float32) - x_high.astype(np.float32) + y_high.astype(np.float32)).clip(0, 255).astype(np.uint8)
282
+
283
+
284
+ def corrupt(x, b128):
285
+ float_sketch = x.astype(float)
286
+ float_base = cv2.resize(float_sketch, (b128.shape[1], b128.shape[0]), cv2.INTER_AREA)
287
+ alpha = b128[:, :, 0] / 255.0
288
+ float_base = alpha * float_base + (1 - alpha) * np.mean(float_base)
289
+ float_base = cv2.GaussianBlur(float_base, (0, 0), 8.0)
290
+ float_base = cv2.resize(float_base, (x.shape[1], x.shape[0]), cv2.INTER_CUBIC)
291
+ result = float_sketch / (float_base + 1e-10)
292
+ result = result.clip(0, 1)
293
+ result -= np.min(result)
294
+ result /= np.max(result)
295
+ return (result * 255.0).clip(0, 255).astype(np.uint8)
296
+
297
+
298
+ def fuse_sketch(color, sketch, fills, fixer, points_arr, colors_arr):
299
+ sketch = cv2.resize(sketch, (color.shape[1], color.shape[0]))
300
+ fills = cv2.resize(fills, (color.shape[1], color.shape[0]), interpolation=cv2.INTER_NEAREST)
301
+ fill_id = np.unique(fills.flatten())
302
+ bg = np.zeros_like(color, dtype=np.uint8)
303
+ checking_result = np.zeros(dtype=np.int32, shape=(np.max(fills) + 1,)) - 1
304
+ length_points = int(len(points_arr))
305
+ for _ in range(length_points):
306
+ checking_result[fills[points_arr[_][0], points_arr[_][1]]] = _
307
+ for id in fill_id:
308
+ points = np.where(fills == id)
309
+ if len(points[0]) > 0:
310
+ color_id = checking_result[id]
311
+ if color_id > -1:
312
+ bg[points] = np.array(colors_arr[color_id])
313
+ else:
314
+ bg[points] = np.median(color[points], axis=0)
315
+ fixed = adain(fixer(sketch, bg), bg)
316
+ result = (fixed.astype(np.float32) + sketch[:, :, None].astype(np.float32) - 255.0).clip(0, 255).astype(np.uint8)
317
+ return result, fixed, bg
318
+
319
+
320
+ def balance_fill(color, fills, points, sizer):
321
+ color = cv2.resize(color, (sizer.shape[1], sizer.shape[0]), interpolation=cv2.INTER_NEAREST)
322
+ points = cv2.resize(points, (sizer.shape[1], sizer.shape[0]), interpolation=cv2.INTER_NEAREST)
323
+ bg = np.zeros_like(color, dtype=np.uint8)
324
+ for region in fills:
325
+ if len(region[0]) > 0:
326
+ region_points = points[region]
327
+ region_points = region_points[region_points[:, 3] > 0]
328
+ if region_points.shape[0] > 0:
329
+ points_color, points_color_count = np.unique(region_points, return_counts=True, axis=0)
330
+ bg[region] = points_color[np.argmax(points_color_count)][0:3]
331
+ else:
332
+ bg[region] = np.median(color[region], axis=0)
333
+ return bg
334
+
335
+
336
+ def shade_fill(color, fills, points, sizer):
337
+ color = cv2.resize(color, (sizer.shape[1], sizer.shape[0]), interpolation=cv2.INTER_NEAREST)
338
+ points = cv2.resize(points, (sizer.shape[1], sizer.shape[0]), interpolation=cv2.INTER_NEAREST)
339
+ bg = np.zeros_like(color, dtype=np.uint8)
340
+ for region in fills:
341
+ if len(region[0]) > 0:
342
+ region_points = points[region]
343
+ region_points = region_points[region_points[:, 3] > 0]
344
+ if region_points.shape[0] > 0:
345
+ points_color, points_color_count = np.unique(region_points, return_counts=True, axis=0)
346
+ c = points_color[np.argmax(points_color_count)][0:3]
347
+ r = c[0]
348
+ g = c[1]
349
+ b = c[2]
350
+ if r == 1 and g == 233 and b == 0:
351
+ bg[region] = 255
352
+ elif r == 0 and g == 233 and b == 1:
353
+ bg[region] = 0
354
+ else:
355
+ bg[region] = np.median(color[region], axis=0)
356
+ else:
357
+ bg[region] = np.median(color[region], axis=0)
358
+ return bg
359
+
360
+
361
+ def get_alpha_piece(points):
362
+ padded_points = np.pad(points, [[1, 1], [1, 1], [0, 0]], 'constant', constant_values=127)
363
+ lines = 255 - padded_points[:, :, 3]
364
+ lines[lines < 240] = 0
365
+ fills = flood_fill_multi(lines, merge=True)
366
+ result = np.zeros_like(padded_points)
367
+ for item in fills:
368
+ points0 = padded_points[(item[0], item[1] + 1)]
369
+ points1 = padded_points[(item[0], item[1] - 1)]
370
+ points2 = padded_points[(item[0] + 1, item[1])]
371
+ points3 = padded_points[(item[0] - 1, item[1])]
372
+ all_points = np.concatenate([points0, points1, points2, points3], axis=0)
373
+ all_points = all_points[all_points[:, 3] > 0]
374
+ all_points = np.unique(all_points, axis=0)
375
+ if all_points.shape[0] == 1:
376
+ result[item] = all_points[0]
377
+ piece = result[1:-1, 1:-1, :]
378
+ piece = np.maximum(piece, points)
379
+ return piece, points
380
+
381
+
382
+ def fin_deatlize(color, sketch):
383
+
384
+ cf = color.astype(np.float32)
385
+ alpha = sketch.astype(np.float32)[:, :, None] / 255.0
386
+
387
+ plain = cf * alpha
388
+ lines = cf * (1 - alpha)
389
+
390
+ plain = cv2.medianBlur(plain, 5)
391
+ plain = cv2.medianBlur(plain, 3)
392
+
393
+ fin = plain + lines
394
+
395
+ return fin.clip(0, 255).astype(np.uint8)
396
+
linefiller/trappedball_fill.py ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ from scipy.ndimage import label
4
+ from numba import njit
5
+
6
+
7
+ def get_ball_structuring_element(radius):
8
+ """Get a ball shape structuring element with specific radius for morphology operation.
9
+ The radius of ball usually equals to (leaking_gap_size / 2).
10
+
11
+ # Arguments
12
+ radius: radius of ball shape.
13
+
14
+ # Returns
15
+ an array of ball structuring element.
16
+ """
17
+ return cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * radius + 1, 2 * radius + 1))
18
+
19
+
20
+ def get_unfilled_point(image):
21
+ """Get points belong to unfilled(value==255) area.
22
+
23
+ # Arguments
24
+ image: an image.
25
+
26
+ # Returns
27
+ an array of points.
28
+ """
29
+ y, x = np.where(image == 255)
30
+
31
+ return np.stack((x.astype(int), y.astype(int)), axis=-1)
32
+
33
+
34
+ def exclude_area(image, radius):
35
+ """Perform erosion on image to exclude points near the boundary.
36
+ We want to pick part using floodfill from the seed point after dilation.
37
+ When the seed point is near boundary, it might not stay in the fill, and would
38
+ not be a valid point for next floodfill operation. So we ignore these points with erosion.
39
+
40
+ # Arguments
41
+ image: an image.
42
+ radius: radius of ball shape.
43
+
44
+ # Returns
45
+ an image after dilation.
46
+ """
47
+ return cv2.morphologyEx(image, cv2.MORPH_ERODE, get_ball_structuring_element(radius), anchor=(-1, -1), iterations=1)
48
+
49
+
50
+ def trapped_ball_fill_single(image, seed_point, radius):
51
+ """Perform a single trapped ball fill operation.
52
+
53
+ # Arguments
54
+ image: an image. the image should consist of white background, black lines and black fills.
55
+ the white area is unfilled area, and the black area is filled area.
56
+ seed_point: seed point for trapped-ball fill, a tuple (integer, integer).
57
+ radius: radius of ball shape.
58
+ # Returns
59
+ an image after filling.
60
+ """
61
+ ball = get_ball_structuring_element(radius)
62
+
63
+ pass1 = np.full(image.shape, 255, np.uint8)
64
+ pass2 = np.full(image.shape, 255, np.uint8)
65
+
66
+ im_inv = cv2.bitwise_not(image)
67
+
68
+ # Floodfill the image
69
+ mask1 = cv2.copyMakeBorder(im_inv, 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0)
70
+ _, pass1, _, _ = cv2.floodFill(pass1, mask1, seed_point, 0, 0, 0, 4)
71
+
72
+ # Perform dilation on image. The fill areas between gaps became disconnected.
73
+ pass1 = cv2.morphologyEx(pass1, cv2.MORPH_DILATE, ball, anchor=(-1, -1), iterations=1)
74
+ mask2 = cv2.copyMakeBorder(pass1, 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0)
75
+
76
+ # Floodfill with seed point again to select one fill area.
77
+ _, pass2, _, rect = cv2.floodFill(pass2, mask2, seed_point, 0, 0, 0, 4)
78
+ # Perform erosion on the fill result leaking-proof fill.
79
+ pass2 = cv2.morphologyEx(pass2, cv2.MORPH_ERODE, ball, anchor=(-1, -1), iterations=1)
80
+
81
+ return pass2
82
+
83
+
84
+ def trapped_ball_fill_multi(image, radius, method='mean', max_iter=1000):
85
+ """Perform multi trapped ball fill operations until all valid areas are filled.
86
+
87
+ # Arguments
88
+ image: an image. The image should consist of white background, black lines and black fills.
89
+ the white area is unfilled area, and the black area is filled area.
90
+ radius: radius of ball shape.
91
+ method: method for filtering the fills.
92
+ 'max' is usually with large radius for select large area such as background.
93
+ max_iter: max iteration number.
94
+ # Returns
95
+ an array of fills' points.
96
+ """
97
+ print('trapped-ball ' + str(radius))
98
+
99
+ unfill_area = image
100
+ filled_area, filled_area_size, result = [], [], []
101
+
102
+ for _ in range(max_iter):
103
+ points = get_unfilled_point(exclude_area(unfill_area, radius))
104
+
105
+ if not len(points) > 0:
106
+ break
107
+
108
+ fill = trapped_ball_fill_single(unfill_area, (points[0][0], points[0][1]), radius)
109
+ unfill_area = cv2.bitwise_and(unfill_area, fill)
110
+
111
+ filled_area.append(np.where(fill == 0))
112
+ filled_area_size.append(len(np.where(fill == 0)[0]))
113
+
114
+ filled_area_size = np.asarray(filled_area_size)
115
+
116
+ if method == 'max':
117
+ area_size_filter = np.max(filled_area_size)
118
+ elif method == 'median':
119
+ area_size_filter = np.median(filled_area_size)
120
+ elif method == 'mean':
121
+ area_size_filter = np.mean(filled_area_size)
122
+ else:
123
+ area_size_filter = 0
124
+
125
+ result_idx = np.where(filled_area_size >= area_size_filter)[0]
126
+
127
+ for i in result_idx:
128
+ result.append(filled_area[i])
129
+
130
+ return result
131
+
132
+
133
+ def flood_fill_single(im, seed_point):
134
+ """Perform a single flood fill operation.
135
+
136
+ # Arguments
137
+ image: an image. the image should consist of white background, black lines and black fills.
138
+ the white area is unfilled area, and the black area is filled area.
139
+ seed_point: seed point for trapped-ball fill, a tuple (integer, integer).
140
+ # Returns
141
+ an image after filling.
142
+ """
143
+ pass1 = np.full(im.shape, 255, np.uint8)
144
+
145
+ im_inv = cv2.bitwise_not(im)
146
+
147
+ mask1 = cv2.copyMakeBorder(im_inv, 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0)
148
+ _, pass1, _, _ = cv2.floodFill(pass1, mask1, seed_point, 0, 0, 0, 4)
149
+
150
+ return pass1
151
+
152
+
153
+ @njit
154
+ def count_all(labeled_array, all_counts):
155
+ M = labeled_array.shape[0]
156
+ N = labeled_array.shape[1]
157
+ for x in range(M):
158
+ for y in range(N):
159
+ i = labeled_array[x, y] - 1
160
+ if i > -1:
161
+ all_counts[i] = all_counts[i] + 1
162
+ return
163
+
164
+
165
+ @njit
166
+ def trace_all(labeled_array, xs, ys, cs):
167
+ M = labeled_array.shape[0]
168
+ N = labeled_array.shape[1]
169
+ for x in range(M):
170
+ for y in range(N):
171
+ current_label = labeled_array[x, y] - 1
172
+ if current_label > -1:
173
+ current_label_count = cs[current_label]
174
+ xs[current_label][current_label_count] = x
175
+ ys[current_label][current_label_count] = y
176
+ cs[current_label] = current_label_count + 1
177
+ return
178
+
179
+
180
+ def find_all(labeled_array):
181
+ hist_size = int(np.max(labeled_array))
182
+ if hist_size == 0:
183
+ return []
184
+ all_counts = [0 for _ in range(hist_size)]
185
+ count_all(labeled_array, all_counts)
186
+ xs = [np.zeros(shape=(item, ), dtype=np.uint32) for item in all_counts]
187
+ ys = [np.zeros(shape=(item, ), dtype=np.uint32) for item in all_counts]
188
+ cs = [0 for item in all_counts]
189
+ trace_all(labeled_array, xs, ys, cs)
190
+ filled_area = []
191
+ for _ in range(hist_size):
192
+ filled_area.append((xs[_], ys[_]))
193
+ return filled_area
194
+
195
+
196
+ def flood_fill_multi(image, merge=False):
197
+ print('floodfill')
198
+
199
+ labeled_array, num_features = label(image / 255)
200
+ print('floodfill_ok1')
201
+
202
+ filled_area = find_all(labeled_array)
203
+
204
+ print('floodfill_ok2')
205
+
206
+ if merge:
207
+ new_fill = []
208
+ for item in filled_area:
209
+ if len(item[0]) > 8:
210
+ new_fill.append(item)
211
+ return new_fill
212
+
213
+ print('floodfill_ok3')
214
+
215
+ return filled_area
216
+
217
+
218
+ def old_flood_fill_multi(image, max_iter=20000):
219
+ """Perform multi flood fill operations until all valid areas are filled.
220
+ This operation will fill all rest areas, which may result large amount of fills.
221
+
222
+ # Arguments
223
+ image: an image. the image should contain white background, black lines and black fills.
224
+ the white area is unfilled area, and the black area is filled area.
225
+ max_iter: max iteration number.
226
+ # Returns
227
+ an array of fills' points.
228
+ """
229
+ print('floodfill')
230
+
231
+ unfill_area = image
232
+ filled_area = []
233
+
234
+ for _ in range(max_iter):
235
+ points = get_unfilled_point(unfill_area)
236
+
237
+ if not len(points) > 0:
238
+ break
239
+
240
+ fill = flood_fill_single(unfill_area, (points[0][0], points[0][1]))
241
+ unfill_area = cv2.bitwise_and(unfill_area, fill)
242
+
243
+ filled_area.append(np.where(fill == 0))
244
+
245
+ return filled_area
246
+
247
+
248
+ def mark_fill(image, fills):
249
+ """Mark filled areas with 0.
250
+
251
+ # Arguments
252
+ image: an image.
253
+ fills: an array of fills' points.
254
+ # Returns
255
+ an image.
256
+ """
257
+ result = image.copy()
258
+
259
+ for fill in fills:
260
+ result[fill] = 0
261
+
262
+ return result
263
+
264
+
265
+ def build_fill_map(image, fills):
266
+ """Make an image(array) with each pixel(element) marked with fills' id. id of line is 0.
267
+
268
+ # Arguments
269
+ image: an image.
270
+ fills: an array of fills' points.
271
+ # Returns
272
+ an array.
273
+ """
274
+ result = np.zeros(image.shape[:2], np.int)
275
+
276
+ for index, fill in enumerate(fills):
277
+
278
+ if(len(fill[0]) == 0):
279
+ continue
280
+
281
+ result[fill] = index + 1
282
+
283
+ return result
284
+
285
+
286
+ def show_fill_map(fillmap):
287
+ """Mark filled areas with colors. It is useful for visualization.
288
+
289
+ # Arguments
290
+ image: an image.
291
+ fills: an array of fills' points.
292
+ # Returns
293
+ an image.
294
+ """
295
+ # Generate color for each fill randomly.
296
+ colors = np.random.randint(0, 255, (np.max(fillmap) + 1, 3))
297
+ # Id of line is 0, and its color is black.
298
+ colors[0] = [0, 0, 0]
299
+
300
+ return colors[fillmap]
301
+
302
+
303
+ def get_bounding_rect(points):
304
+ """Get a bounding rect of points.
305
+
306
+ # Arguments
307
+ points: array of points.
308
+ # Returns
309
+ rect coord
310
+ """
311
+ x1, y1, x2, y2 = np.min(points[1]), np.min(points[0]), np.max(points[1]), np.max(points[0])
312
+ return x1, y1, x2, y2
313
+
314
+
315
+ def get_border_bounding_rect(h, w, p1, p2, r):
316
+ """Get a valid bounding rect in the image with border of specific size.
317
+
318
+ # Arguments
319
+ h: image max height.
320
+ w: image max width.
321
+ p1: start point of rect.
322
+ p2: end point of rect.
323
+ r: border radius.
324
+ # Returns
325
+ rect coord
326
+ """
327
+ x1, y1, x2, y2 = p1[0], p1[1], p2[0], p2[1]
328
+
329
+ x1 = x1 - r if 0 < x1 - r else 0
330
+ y1 = y1 - r if 0 < y1 - r else 0
331
+ x2 = x2 + r + 1 if x2 + r + 1 < w else w
332
+ y2 = y2 + r + 1 if y2 + r + 1 < h else h
333
+
334
+ return x1, y1, x2, y2
335
+
336
+
337
+ def get_border_point(points, rect, max_height, max_width):
338
+ """Get border points of a fill area
339
+
340
+ # Arguments
341
+ points: points of fill .
342
+ rect: bounding rect of fill.
343
+ max_height: image max height.
344
+ max_width: image max width.
345
+ # Returns
346
+ points , convex shape of points
347
+ """
348
+ # Get a local bounding rect.
349
+ border_rect = get_border_bounding_rect(max_height, max_width, rect[:2], rect[2:], 2)
350
+
351
+ # Get fill in rect.
352
+ fill = np.zeros((border_rect[3] - border_rect[1], border_rect[2] - border_rect[0]), np.uint8)
353
+ # Move points to the rect.
354
+ fill[(points[0] - border_rect[1], points[1] - border_rect[0])] = 255
355
+
356
+ # Get shape.
357
+ _, contours, _ = cv2.findContours(fill, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
358
+ # approx_shape = cv2.approxPolyDP(contours[0], 0.02 * cv2.arcLength(contours[0], True), True)
359
+
360
+ # Get border pixel.
361
+ # Structuring element in cross shape is used instead of box to get 4-connected border.
362
+ cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
363
+ border_pixel_mask = cv2.morphologyEx(fill, cv2.MORPH_DILATE, cross, anchor=(-1, -1), iterations=1) - fill
364
+ border_pixel_points = np.where(border_pixel_mask == 255)
365
+
366
+ # Transform points back to fillmap.
367
+ border_pixel_points = (border_pixel_points[0] + border_rect[1], border_pixel_points[1] + border_rect[0])
368
+
369
+ return border_pixel_points
370
+
371
+
372
+ def merge_fill(fillmap, max_iter=20):
373
+ """Merge fill areas.
374
+
375
+ # Arguments
376
+ fillmap: an image.
377
+ max_iter: max iteration number.
378
+ # Returns
379
+ an image.
380
+ """
381
+ max_height, max_width = fillmap.shape[:2]
382
+ result = fillmap.copy()
383
+
384
+ for i in range(max_iter):
385
+ print('merge ' + str(i + 1))
386
+
387
+ result[np.where(fillmap == 0)] = 0
388
+
389
+ fill_id = np.unique(result.flatten())
390
+ fills = []
391
+
392
+ for j in fill_id:
393
+ point = np.where(result == j)
394
+
395
+ fills.append({
396
+ 'id': j,
397
+ 'point': point,
398
+ 'area': len(point[0]),
399
+ })
400
+
401
+ for j, f in enumerate(fills):
402
+ # ignore lines
403
+ if f['id'] == 0:
404
+ continue
405
+
406
+ if f['area'] < 5:
407
+ result[f['point']] = 0
408
+
409
+ if len(fill_id) == len(np.unique(result.flatten())):
410
+ break
411
+
412
+ return result
413
+
414
+
415
+ def merge_one(fillmap):
416
+ result = fillmap.copy()
417
+ print('merge')
418
+ result[np.where(fillmap == 0)] = 0
419
+ fill_id = np.unique(result.flatten())
420
+ fills = []
421
+ for j in fill_id:
422
+ point = np.where(result == j)
423
+ fills.append({
424
+ 'id': j,
425
+ 'point': point,
426
+ 'area': len(point[0]),
427
+ })
428
+ for j, f in enumerate(fills):
429
+ # ignore lines
430
+ if f['id'] == 0:
431
+ continue
432
+
433
+ if f['area'] < 5:
434
+ result[f['point']] = 0
435
+ return result
436
+
models.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from keras.layers import Conv2D, Activation, Input, Concatenate, LeakyReLU, Lambda, AveragePooling2D, UpSampling2D, Convolution2D, BatchNormalization, Deconvolution2D, Add
2
+ from keras.models import Model
3
+ from InstanceNorm import InstanceNormalization
4
+
5
+
6
+ def make_standard_UNET(channels,outs):
7
+
8
+ def relu(x):
9
+ return Activation('relu')(x)
10
+
11
+ def concat(x):
12
+ return Concatenate()(x)
13
+
14
+ c0 = Convolution2D(filters=32, kernel_size=3, strides=1, padding='same', name='c0')
15
+ c1 = Convolution2D(filters=64, kernel_size=4, strides=2, padding='same', name='c1')
16
+ c2 = Convolution2D(filters=64, kernel_size=3, strides=1, padding='same', name='c2')
17
+ c3 = Convolution2D(filters=128, kernel_size=4, strides=2, padding='same', name='c3')
18
+ c4 = Convolution2D(filters=128, kernel_size=3, strides=1, padding='same', name='c4')
19
+ c5 = Convolution2D(filters=256, kernel_size=4, strides=2, padding='same', name='c5')
20
+ c6 = Convolution2D(filters=256, kernel_size=3, strides=1, padding='same', name='c6')
21
+ c7 = Convolution2D(filters=512, kernel_size=4, strides=2, padding='same', name='c7')
22
+ c8 = Convolution2D(filters=512, kernel_size=3, strides=1, padding='same', name='c8')
23
+
24
+ bnc0 = BatchNormalization(axis=3, name='bnc0')
25
+ bnc1 = BatchNormalization(axis=3, name='bnc1')
26
+ bnc2 = BatchNormalization(axis=3, name='bnc2')
27
+ bnc3 = BatchNormalization(axis=3, name='bnc3')
28
+ bnc4 = BatchNormalization(axis=3, name='bnc4')
29
+ bnc5 = BatchNormalization(axis=3, name='bnc5')
30
+ bnc6 = BatchNormalization(axis=3, name='bnc6')
31
+ bnc7 = BatchNormalization(axis=3, name='bnc7')
32
+ bnc8 = BatchNormalization(axis=3, name='bnc8')
33
+
34
+ dc8 = Deconvolution2D(filters=512, kernel_size=4, strides=2, padding='same', name='dc8_')
35
+ dc7 = Convolution2D(filters=256, kernel_size=3, strides=1, padding='same', name='dc7')
36
+ dc6 = Deconvolution2D(filters=256, kernel_size=4, strides=2, padding='same', name='dc6_')
37
+ dc5 = Convolution2D(filters=128, kernel_size=3, strides=1, padding='same', name='dc5')
38
+ dc4 = Deconvolution2D(filters=128, kernel_size=4, strides=2, padding='same', name='dc4_')
39
+ dc3 = Convolution2D(filters=64, kernel_size=3, strides=1, padding='same', name='dc3')
40
+ dc2 = Deconvolution2D(filters=64, kernel_size=4, strides=2, padding='same', name='dc2_')
41
+ dc1 = Convolution2D(filters=32, kernel_size=3, strides=1, padding='same', name='dc1')
42
+ dc0 = Convolution2D(filters=outs, kernel_size=3, strides=1, padding='same', name='dc0')
43
+
44
+ bnd1 = BatchNormalization(axis=3, name='bnd1')
45
+ bnd2 = BatchNormalization(axis=3, name='bnd2')
46
+ bnd3 = BatchNormalization(axis=3, name='bnd3')
47
+ bnd4 = BatchNormalization(axis=3, name='bnd4')
48
+ bnd5 = BatchNormalization(axis=3, name='bnd5')
49
+ bnd6 = BatchNormalization(axis=3, name='bnd6')
50
+ bnd7 = BatchNormalization(axis=3, name='bnd7')
51
+ bnd8 = BatchNormalization(axis=3, name='bnd8')
52
+
53
+ x = Input(shape=(128, 128, channels))
54
+
55
+ e0 = relu(bnc0(c0(x), training = False))
56
+ e1 = relu(bnc1(c1(e0), training = False))
57
+ e2 = relu(bnc2(c2(e1), training = False))
58
+ e3 = relu(bnc3(c3(e2), training = False))
59
+ e4 = relu(bnc4(c4(e3), training = False))
60
+ e5 = relu(bnc5(c5(e4), training = False))
61
+ e6 = relu(bnc6(c6(e5), training = False))
62
+ e7 = relu(bnc7(c7(e6), training = False))
63
+ e8 = relu(bnc8(c8(e7), training = False))
64
+
65
+ d8 = relu(bnd8(dc8(concat([e7, e8])), training = False))
66
+ d7 = relu(bnd7(dc7(d8), training = False))
67
+ d6 = relu(bnd6(dc6(concat([e6, d7])), training = False))
68
+ d5 = relu(bnd5(dc5(d6), training = False))
69
+ d4 = relu(bnd4(dc4(concat([e4, d5])), training = False))
70
+ d3 = relu(bnd3(dc3(d4), training = False))
71
+ d2 = relu(bnd2(dc2(concat([e2, d3])), training = False))
72
+ d1 = relu(bnd1(dc1(d2), training = False))
73
+ d0 = dc0(concat([e0, d1]))
74
+
75
+ model = Model(inputs=x,outputs=d0)
76
+
77
+ return model
78
+
79
+
80
+ def make_diff_net():
81
+
82
+ def conv(x, filters, name):
83
+ return Conv2D(filters=filters, strides=(1, 1), kernel_size=(3, 3), padding='same', name=name)(x)
84
+
85
+ def relu(x):
86
+ return Activation('relu')(x)
87
+
88
+ def lrelu(x):
89
+ return LeakyReLU(alpha=0.1)(x)
90
+
91
+ def r_block(x, filters, name=None):
92
+ return relu(conv(relu(conv(x, filters, None if name is None else name + '_c1')), filters,
93
+ None if name is None else name + '_c2'))
94
+
95
+ def cat(a, b):
96
+ return Concatenate()([UpSampling2D((2, 2))(a), b])
97
+
98
+ def dog(x):
99
+ down = AveragePooling2D((2, 2))(x)
100
+ up = UpSampling2D((2, 2))(down)
101
+ diff = Lambda(lambda p: p[0] - p[1])([x, up])
102
+ return down, diff
103
+
104
+ ip = Input(shape=(512, 512, 3))
105
+
106
+ c512 = r_block(ip, 16, 'c512')
107
+
108
+ c256, l512 = dog(c512)
109
+ c256 = r_block(c256, 32, 'c256')
110
+
111
+ c128, l256 = dog(c256)
112
+ c128 = r_block(c128, 64, 'c128')
113
+
114
+ c64, l128 = dog(c128)
115
+ c64 = r_block(c64, 128, 'c64')
116
+
117
+ c32, l64 = dog(c64)
118
+ c32 = r_block(c32, 256, 'c32')
119
+
120
+ c16, l32 = dog(c32)
121
+ c16 = r_block(c16, 512, 'c16')
122
+
123
+ d32 = cat(c16, l32)
124
+ d32 = r_block(d32, 256, 'd32')
125
+
126
+ d64 = cat(d32, l64)
127
+ d64 = r_block(d64, 128, 'd64')
128
+
129
+ d128 = cat(d64, l128)
130
+ d128 = r_block(d128, 64, 'd128')
131
+
132
+ d256 = cat(d128, l256)
133
+ d256 = r_block(d256, 32, 'd256')
134
+
135
+ d512 = cat(d256, l512)
136
+ d512 = r_block(d512, 16, 'd512')
137
+
138
+ op = conv(d512, 1, 'op')
139
+
140
+ return Model(inputs=ip, outputs=op)
141
+
142
+
143
+ def make_wnet256():
144
+
145
+ def conv(x, filters):
146
+ return Conv2D(filters=filters, strides=(1, 1), kernel_size=(3, 3), padding='same')(x)
147
+
148
+ def relu(x):
149
+ return Activation('relu')(x)
150
+
151
+ def lrelu(x):
152
+ return LeakyReLU(alpha=0.1)(x)
153
+
154
+ def r_block(x, filters):
155
+ return relu(conv(relu(conv(x, filters)), filters))
156
+
157
+ def res_block(x, filters):
158
+ return relu(Add()([x, conv(relu(conv(x, filters)), filters)]))
159
+
160
+ def cat(a, b):
161
+ return Concatenate()([UpSampling2D((2, 2))(a), b])
162
+
163
+ def dog(x):
164
+ down = AveragePooling2D((2, 2))(x)
165
+ up = UpSampling2D((2, 2))(down)
166
+ diff = Lambda(lambda p: p[0] - p[1])([x, up])
167
+ return down, diff
168
+
169
+ ip_sketch = Input(shape=(256, 256, 1))
170
+ ip_color = Input(shape=(256, 256, 3))
171
+
172
+ c256 = r_block(ip_sketch, 32)
173
+
174
+ c128, l256 = dog(c256)
175
+ c128 = r_block(c128, 64)
176
+
177
+ c64, l128 = dog(c128)
178
+ c64 = r_block(c64, 128)
179
+
180
+ c32, l64 = dog(c64)
181
+ c32 = r_block(Concatenate()([c32, AveragePooling2D((8, 8))(ip_color)]), 256)
182
+
183
+ c32 = res_block(c32, 256)
184
+ c32 = res_block(c32, 256)
185
+ c32 = res_block(c32, 256)
186
+
187
+ c32 = res_block(c32, 256)
188
+ c32 = res_block(c32, 256)
189
+ c32 = res_block(c32, 256)
190
+
191
+ c32 = res_block(c32, 256)
192
+ c32 = res_block(c32, 256)
193
+ c32 = res_block(c32, 256)
194
+
195
+ d64 = cat(c32, l64)
196
+ d64 = r_block(d64, 128)
197
+
198
+ d128 = cat(d64, l128)
199
+ d128 = r_block(d128, 64)
200
+
201
+ d256 = cat(d128, l256)
202
+ d256 = r_block(d256, 32)
203
+
204
+ op = conv(d256, 3)
205
+
206
+ return Model(inputs=[ip_sketch, ip_color], outputs=op)
207
+
208
+
209
+ def make_unet512():
210
+
211
+ def conv(x, filters, strides=(1, 1), kernel_size=(3, 3)):
212
+ return Conv2D(filters=filters, strides=strides, kernel_size=kernel_size, padding='same')(x)
213
+
214
+ def donv(x, filters, strides=(2, 2), kernel_size=(4, 4)):
215
+ return Deconvolution2D(filters=filters, strides=strides, kernel_size=kernel_size, padding='same')(x)
216
+
217
+ def relu(x):
218
+ return Activation('relu')(x)
219
+
220
+ def sigmoid(x):
221
+ return Activation('sigmoid')(x)
222
+
223
+ def norm(x):
224
+ return InstanceNormalization(axis=3)(x)
225
+
226
+ def cat(a, b):
227
+ return Concatenate()([a, b])
228
+
229
+ def res(x, filters):
230
+ c1 = relu(norm(conv(x, filters // 2)))
231
+ c2 = norm(conv(c1, filters))
232
+ ad = Add()([x, c2])
233
+ return relu(ad)
234
+
235
+ ip = Input(shape=(512, 512, 3))
236
+
237
+ c512 = relu(norm(conv(ip, 16, strides=(1, 1), kernel_size=(3, 3))))
238
+ c256 = relu(norm(conv(c512, 32, strides=(2, 2), kernel_size=(4, 4))))
239
+
240
+ c128 = relu(norm(conv(c256, 64, strides=(2, 2), kernel_size=(4, 4))))
241
+ c128 = res(c128, 64)
242
+
243
+ c64 = relu(norm(conv(c128, 128, strides=(2, 2), kernel_size=(4, 4))))
244
+ c64 = res(c64, 128)
245
+ c64 = res(c64, 128)
246
+
247
+ c32 = relu(norm(conv(c64, 256, strides=(2, 2), kernel_size=(4, 4))))
248
+ c32 = res(c32, 256)
249
+ c32 = res(c32, 256)
250
+ c32 = res(c32, 256)
251
+ c32 = res(c32, 256)
252
+ c32 = res(c32, 256)
253
+ c32 = res(c32, 256)
254
+ c32 = res(c32, 256)
255
+ c32 = res(c32, 256)
256
+
257
+ c16 = relu(norm(conv(c32, 512, strides=(2, 2), kernel_size=(4, 4))))
258
+ c16 = res(c16, 512)
259
+ c16 = res(c16, 512)
260
+ c16 = res(c16, 512)
261
+ c16 = res(c16, 512)
262
+ c16 = res(c16, 512)
263
+ c16 = res(c16, 512)
264
+ c16 = res(c16, 512)
265
+ c16 = res(c16, 512)
266
+
267
+ c8 = relu(norm(conv(c16, 1024, strides=(2, 2), kernel_size=(4, 4))))
268
+ c8 = res(c8, 1024)
269
+ c8 = res(c8, 1024)
270
+ c8 = res(c8, 1024)
271
+ c8 = res(c8, 1024)
272
+
273
+ e16 = relu(norm(donv(c8, 512, strides=(2, 2), kernel_size=(4, 4))))
274
+ e16 = cat(e16, c16)
275
+ e16 = relu(norm(conv(e16, 512, strides=(1, 1), kernel_size=(3, 3))))
276
+
277
+ e32 = relu(norm(donv(e16, 256, strides=(2, 2), kernel_size=(4, 4))))
278
+ e32 = cat(e32, c32)
279
+ e32 = relu(norm(conv(e32, 256, strides=(1, 1), kernel_size=(3, 3))))
280
+
281
+ e64 = relu(norm(donv(e32, 128, strides=(2, 2), kernel_size=(4, 4))))
282
+ e64 = cat(e64, c64)
283
+ e64 = relu(norm(conv(e64, 128, strides=(1, 1), kernel_size=(3, 3))))
284
+
285
+ e128 = relu(norm(donv(e64, 64, strides=(2, 2), kernel_size=(4, 4))))
286
+ e128 = cat(e128, c128)
287
+ e128 = relu(norm(conv(e128, 64, strides=(1, 1), kernel_size=(3, 3))))
288
+
289
+ e256 = relu(norm(donv(e128, 32, strides=(2, 2), kernel_size=(4, 4))))
290
+ e256 = cat(e256, c256)
291
+ e256 = relu(norm(conv(e256, 32, strides=(1, 1), kernel_size=(3, 3))))
292
+
293
+ e512 = relu(norm(donv(e256, 16, strides=(2, 2), kernel_size=(4, 4))))
294
+ e512 = cat(e512, c512)
295
+ e512 = relu(norm(conv(e512, 16, strides=(1, 1), kernel_size=(3, 3))))
296
+
297
+ ot = sigmoid(conv(e512, 1))
298
+
299
+ return Model(inputs=ip, outputs=ot)
nets/head.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fd5f608bf5511293cd582e6d87e55f483259b8d606feba7a5042382a19cde630
3
+ size 411622416
nets/inception.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9a503841e955ee56f2e0b71219952f0f554c9eaff9e887f82853f600f0ddee80
3
+ size 41501888
nets/mat.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a2998a3cd6446ad62d87259dd5b279e344a9ba8daaf2c3c88f59ebb5ddfe09cd
3
+ size 362262288
nets/neck.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e91e4e688379dc95a14ea8f33fa1c2141584b0387e16be5efcc7acb5299ad5d7
3
+ size 411623808
nets/norm.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:08d230c0a595dc21d2924911b2d2aa9f334c2180a6526d947d11a4d00e5ce4d0
3
+ size 113030088
nets/reader.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5a65a53091acb96dbdcf325afb1b233ff374e220cb822fe8b1771dcd65f999df
3
+ size 41502832
nets/render_head.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cacac78d2e19bd38b2efbdd8eb372594e333e5284e9f2c2b605652c8dd26ffad
3
+ size 411612752
nets/render_neck.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:66050656839363d7977dd970cc2f6d7f81722a8cf5cd67a1793bae8214a07c0b
3
+ size 411613336
nets/tail.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2255073ccdc311d8c61c074ffeb4ad7db200ca9116011e1cf213d6d4b1967e15
3
+ size 4018208
nets/vector.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2738164810e2c998c4e5c7598c9ad991b9aad6c300d075119da9e4201212066a
3
+ size 31618276
nets/vgg7.net ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:84539cc2f46a0937a31ff770af592242e1e2a06f9f3c3fd285ab596a7ab90be6
3
+ size 1188680
refs/1.png ADDED

Git LFS Details

  • SHA256: 2736a06366ac2db392b2c6918765451dc5630412f14cb277aeedf3d9968c07ce
  • Pointer size: 131 Bytes
  • Size of remote file: 602 kB
refs/10.png ADDED

Git LFS Details

  • SHA256: 6927f2295672b66227acf022604288c97d8c5793d28e8ccab1a7d79323c9897f
  • Pointer size: 131 Bytes
  • Size of remote file: 799 kB
refs/11.png ADDED

Git LFS Details

  • SHA256: eefa52b40bdf6d52bfe1f49a58358f0a278860eccdefbb43d0b4aea98078c6e3
  • Pointer size: 132 Bytes
  • Size of remote file: 1.11 MB
refs/12.png ADDED

Git LFS Details

  • SHA256: 3cf0475a9ac342265a72fab9769e65ed18e357e7b1cf510854dcfbb56778447b
  • Pointer size: 131 Bytes
  • Size of remote file: 925 kB
refs/13.png ADDED

Git LFS Details

  • SHA256: c95b8c7627cc3d2651fb924c9bc97693941f33da5bae3f023e41d15e3df55c2c
  • Pointer size: 132 Bytes
  • Size of remote file: 1.16 MB
refs/14.png ADDED

Git LFS Details

  • SHA256: e92abae0ea751770369aa7a202b3709eb8bc5086c2dc8dc28049e726cc288ce5
  • Pointer size: 131 Bytes
  • Size of remote file: 524 kB
refs/15.png ADDED

Git LFS Details

  • SHA256: 4359a4d76e317cd27106e398b4b578f8d504033a9e2b0d73ee17007627b109c8
  • Pointer size: 131 Bytes
  • Size of remote file: 531 kB
refs/16.png ADDED

Git LFS Details

  • SHA256: 37497ec998d50661725fcf8f5fcab4bccb372aecc1c070ebd252e4d80cb81054
  • Pointer size: 131 Bytes
  • Size of remote file: 549 kB
refs/17.png ADDED

Git LFS Details

  • SHA256: b3a2a64cc7d9d58b97ed0f6a5f9d21d4094f2410879c239b26570c5360a1cb41
  • Pointer size: 131 Bytes
  • Size of remote file: 630 kB
refs/18.png ADDED

Git LFS Details

  • SHA256: ab0b5e5da2e863221864f1cb6291aff6556337429e1a80d9b855f62c219b59f5
  • Pointer size: 131 Bytes
  • Size of remote file: 533 kB
refs/19.png ADDED

Git LFS Details

  • SHA256: 87d27e5397f44db5b0196626e3649b6eae00dc1fddb12318d6ac408a4dc16d67
  • Pointer size: 131 Bytes
  • Size of remote file: 627 kB
refs/2.png ADDED

Git LFS Details

  • SHA256: f6609612f37e853361f5881a827a3d861295b082d0dd7b7381d7deaff1fbb9e0
  • Pointer size: 131 Bytes
  • Size of remote file: 499 kB
refs/20.png ADDED

Git LFS Details

  • SHA256: d14d40ad0d0f2bc234ee9fe006da7f4575fb7ccd7da593c0f2563fd45c3c388c
  • Pointer size: 131 Bytes
  • Size of remote file: 841 kB
refs/21.png ADDED

Git LFS Details

  • SHA256: b5e582b0fa8c5aa2649e18f3b9b6ce8959c6e154b4755dbf4411d600e96c245d
  • Pointer size: 131 Bytes
  • Size of remote file: 485 kB
refs/22.png ADDED

Git LFS Details

  • SHA256: f749b530baed40a225947c30099504a9a5627cdf3c9e2c602fe692e249c178fb
  • Pointer size: 131 Bytes
  • Size of remote file: 222 kB
refs/23.png ADDED

Git LFS Details

  • SHA256: 5fdac6c8c3b389054f1ad66fd7fda63b790fe9ea839bad12ecf0253f253cafc0
  • Pointer size: 131 Bytes
  • Size of remote file: 239 kB
refs/24.png ADDED

Git LFS Details

  • SHA256: d08e9fa0e8b27245cddf929c41ca7fe6a554f708408877ed945864cda3ec760b
  • Pointer size: 131 Bytes
  • Size of remote file: 285 kB
refs/25.png ADDED

Git LFS Details

  • SHA256: 2aadaf8fd9ca3fd77b71af27e57a9dad1ba94d4217be9d161a0eb01b4b098dab
  • Pointer size: 131 Bytes
  • Size of remote file: 191 kB
refs/26.png ADDED

Git LFS Details

  • SHA256: 695bf0ea8cd2af0a787006e2dadf8aaaaf3375a8e127eb9afb728c56ed66ff21
  • Pointer size: 131 Bytes
  • Size of remote file: 179 kB
refs/27.png ADDED

Git LFS Details

  • SHA256: cdde197fb1a0c7adedecf07bf03b742b7d98a171f2f328685fad79c0df3d2e70
  • Pointer size: 131 Bytes
  • Size of remote file: 362 kB
refs/28.png ADDED

Git LFS Details

  • SHA256: 5929bfb2f462ad6297241f6dc117cb1e3c96460e2ba09739ef0daffbc1a3c7d2
  • Pointer size: 131 Bytes
  • Size of remote file: 313 kB
refs/29.png ADDED

Git LFS Details

  • SHA256: 635a48fb25864edd8b03cb89ebfd1b3b6d6b52650f23f8d44464cbb03a73e4f8
  • Pointer size: 131 Bytes
  • Size of remote file: 216 kB
refs/3.png ADDED

Git LFS Details

  • SHA256: f481c1f572b11365cd50d0300766a9bfb61f6c001c0d86c6d36ad6950b624104
  • Pointer size: 132 Bytes
  • Size of remote file: 1.07 MB
refs/30.png ADDED

Git LFS Details

  • SHA256: 063a623c9f1c94443ce1fd0049e1929bc66c982ad69b4b4f3a6c6c23f6beee17
  • Pointer size: 131 Bytes
  • Size of remote file: 466 kB
refs/31.png ADDED

Git LFS Details

  • SHA256: 7c36e141bee549ca8ab2be153bbcc12d5a6828be128180320eceb845fab93452
  • Pointer size: 131 Bytes
  • Size of remote file: 198 kB
refs/32.png ADDED

Git LFS Details

  • SHA256: 89d9fc9d25812c1e15a474ef70eaa39a24131752033aee95c30e7e1f6a42ec1e
  • Pointer size: 131 Bytes
  • Size of remote file: 212 kB
refs/4.png ADDED

Git LFS Details

  • SHA256: b4c39b1e33c03be0601573bde3592c5411c8bf87f5bee659c01763b6bcb5cdba
  • Pointer size: 132 Bytes
  • Size of remote file: 3.41 MB
refs/5.png ADDED

Git LFS Details

  • SHA256: f1b632140556ff58b43df05d7e4937caa0bd27f1bff605a3862ad59b7b4cfa73
  • Pointer size: 131 Bytes
  • Size of remote file: 408 kB