https://github.com/MarkMoHR/virtual_sketching
Tip revision: 958efe45a9120b9d467ba7701efba28c11e38f8f authored by Your Name on 21 August 2021, 08:13:15 UTC
Added bilibili links
Added bilibili links
Tip revision: 958efe4
RealRenderer.py
import numpy as np
import gizeh
class GizehRasterizor(object):
def __init__(self):
self.name = 'GizehRasterizor'
def get_line_array_v2(self, image_size, seq_strokes, stroke_width, is_bin=True):
"""
:param p1: (x, y)
:param p2: (x, y)
:return: line_arr: (image_size, image_size), {0, 1}, 0 for BG and 1 for strokes
"""
surface = gizeh.Surface(width=image_size, height=image_size) # in pixels
shape_list = []
for seq_i in range(len(seq_strokes) - 1):
p1, p2 = seq_strokes[seq_i, :2], seq_strokes[seq_i + 1, :2]
pen_state = seq_strokes[seq_i, 2]
if pen_state == 0.0:
line = gizeh.polyline(points=[p1, p2], stroke_width=stroke_width, stroke=(1, 1, 1), fill=(0, 0, 0))
shape_list.append(line)
group = gizeh.Group(shape_list)
group.draw(surface)
# Now export the surface
line_arr = surface.get_npimage()[:, :, 0] # returns a (width x height x 3) numpy array
if is_bin:
line_arr[line_arr <= 128] = 0
line_arr[line_arr != 0] = 1 # (image_size, image_size)
else:
line_arr = np.array(line_arr, dtype=np.float32) / 255.0
return line_arr
def get_line_array(self, p1, p2, image_size, stroke_width, is_bin=True):
"""
:param p1: (x, y)
:param p2: (x, y)
:return: line_arr: (image_size, image_size), {0, 1}, 0 for BG and 1 for strokes
"""
surface = gizeh.Surface(width=image_size, height=image_size) # in pixels
line = gizeh.polyline(points=[p1, p2], stroke_width=stroke_width, stroke=(1, 1, 1), fill=(0, 0, 0))
line.draw(surface)
# Now export the surface
line_arr = surface.get_npimage()[:, :, 0] # returns a (width x height x 3) numpy array
if is_bin:
line_arr[line_arr <= 128] = 0
line_arr[line_arr != 0] = 1 # (image_size, image_size)
else:
line_arr = np.array(line_arr, dtype=np.float32) / 255.0
return line_arr
def load_sketch_images_on_the_fly_v2(self, image_size, norm_strokes3, stroke_width, is_bin=True):
"""
:param norm_strokes3: list (N_sketches,), each with (N_points, 3)
:return: list (N_sketches,), each with (raster_size, raster_size), 0-BG and 1-strokes
"""
assert type(norm_strokes3) is list
sketch_imgs_list = []
for stroke_i in range(len(norm_strokes3)):
seq_strokes3 = norm_strokes3[stroke_i] # (N_points, 3)
sketch_img = self.get_line_array_v2(image_size, seq_strokes3, stroke_width=stroke_width, is_bin=is_bin)
sketch_img = np.clip(sketch_img, 0.0, 1.0) # (image_size, image_size), 0 for BG and 1 for strokes
sketch_imgs_list.append(sketch_img)
return sketch_imgs_list
def load_sketch_images_on_the_fly(self, image_size, norm_strokes3, stroke_width, is_bin=True):
"""
:param norm_strokes3: list (N_sketches,), each with (N_points, 3)
:return: list (N_sketches,), each with (raster_size, raster_size), 0-BG and 1-strokes
"""
assert type(norm_strokes3) is list
sketch_imgs_list = []
for stroke_i in range(len(norm_strokes3)):
seq_strokes3 = norm_strokes3[stroke_i] # (N_points, 3)
seq_len = len(seq_strokes3)
stroke_imgs_list = []
for seq_i in range(seq_len - 1):
stroke_img = self.get_line_array(seq_strokes3[seq_i, :2], seq_strokes3[seq_i + 1, :2], image_size,
stroke_width=stroke_width, is_bin=is_bin)
pen_state = seq_strokes3[seq_i, 2]
stroke_img = stroke_img.astype(np.float32) * (1. - pen_state)
stroke_imgs_list.append(stroke_img)
stroke_imgs_list = np.stack(stroke_imgs_list,
axis=-1) # (image_size, image_size, seq_len-1), 0 for BG and 1 for strokes
stroke_imgs_list = np.sum(stroke_imgs_list, axis=-1)
stroke_imgs_list = np.clip(stroke_imgs_list, 0.0, 1.0) # (image_size, image_size), 0 for BG and 1 for strokes
sketch_imgs_list.append(stroke_imgs_list)
return sketch_imgs_list
def normalize_coordinate_np(self, sx, sy, image_size, raster_padding=10.0):
"""
Convert offset to normalized absolute points. The numpy version as in NeuralRasterizor.
:param sx: (N, seq_len)
:param sy: (N, seq_len)
:return:
"""
seq_len = sx.shape[1]
# transfer to abs points
abs_x = np.cumsum(sx, axis=1) # (N, seq_len)
abs_y = np.cumsum(sy, axis=1)
min_x = np.min(abs_x, axis=1, keepdims=True) # (N, 1)
max_x = np.max(abs_x, axis=1, keepdims=True)
min_y = np.min(abs_y, axis=1, keepdims=True)
max_y = np.max(abs_y, axis=1, keepdims=True)
# transform to positive coordinate
abs_x = np.subtract(abs_x, np.tile(min_x, [1, seq_len])) # (N, seq_len)
abs_y = np.subtract(abs_y, np.tile(min_y, [1, seq_len]))
# scaling to [0.0, raster_size - 2 * padding - 1]
bbox_w = np.squeeze(np.subtract(max_x, min_x), axis=-1) # (N)
bbox_h = np.squeeze(np.subtract(max_y, min_y), axis=-1)
unpad_raster_size = (image_size - 1.0) - 2.0 * raster_padding
scaling = np.divide(unpad_raster_size, np.maximum(bbox_w, bbox_h)) # (N)
scaling_tile = np.tile(np.expand_dims(scaling, axis=-1), [1, seq_len]) # (N, seq_len)
abs_x = np.multiply(abs_x, scaling_tile) # (N, seq_len)
abs_y = np.multiply(abs_y, scaling_tile)
# add padding
abs_x = np.add(abs_x, raster_padding) # (N, seq_len)
abs_y = np.add(abs_y, raster_padding)
# transform to the middle
trans_x = np.divide(np.subtract(unpad_raster_size, np.multiply(bbox_w, scaling)), 2.0) # (N)
trans_y = np.divide(np.subtract(unpad_raster_size, np.multiply(bbox_h, scaling)), 2.0)
trans_x = np.tile(np.expand_dims(trans_x, axis=-1), [1, seq_len]) # (N, seq_len)
trans_y = np.tile(np.expand_dims(trans_y, axis=-1), [1, seq_len]) # (N, seq_len)
abs_x = np.add(abs_x, trans_x) # (N, seq_len)
abs_y = np.add(abs_y, trans_y)
return abs_x, abs_y
def normalize_strokes_np(self, strokes_list, image_size):
"""
:param strokes_list: list (N_sketches,), each with (N_points, 3)
:return:
"""
assert type(strokes_list) is list
rst_list = []
for i in range(len(strokes_list)):
strokes_data = strokes_list[i] # (N_points, 3)
norm_x, norm_y = self.normalize_coordinate_np(np.expand_dims(strokes_data[:, 0], axis=0),
np.expand_dims(strokes_data[:, 1], axis=0),
image_size) # (1, N_points)
norm_strokes_data = np.stack([norm_x[0], norm_y[0], strokes_data[:, 2]], axis=-1) # (N_points, 3)
rst_list.append(norm_strokes_data)
return rst_list
def raster_func(self, input_data, image_size, stroke_width, is_bin=True, version='v2'):
"""
:param input_data: (N_sketches,), each with (N_points, 3)
:return: raster_image_array: list (N_sketches,), each with (raster_size, raster_size), 0-BG and 1-strokes
"""
norm_test_strokes3 = self.normalize_strokes_np(input_data, image_size)
if version == 'v1':
raster_image_array = self.load_sketch_images_on_the_fly(image_size, norm_test_strokes3, stroke_width, is_bin=is_bin)
else:
raster_image_array = self.load_sketch_images_on_the_fly_v2(image_size, norm_test_strokes3, stroke_width, is_bin=is_bin)
return raster_image_array