https://github.com/MarkMoHR/virtual_sketching
Revision 958efe45a9120b9d467ba7701efba28c11e38f8f authored by Your Name on 21 August 2021, 08:13:15 UTC, committed by Your Name on 21 August 2021, 08:13:15 UTC
1 parent 149a4be
Raw File
Tip revision: 958efe45a9120b9d467ba7701efba28c11e38f8f authored by Your Name on 21 August 2021, 08:13:15 UTC
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
back to top