|
import os |
|
import torch as th |
|
import torch.multiprocessing as mp |
|
import threading as mt |
|
import numpy as np |
|
import random |
|
|
|
import ttools |
|
|
|
import pydiffvg |
|
import time |
|
|
|
|
|
def render(canvas_width, canvas_height, shapes, shape_groups, samples=2, |
|
seed=None): |
|
if seed is None: |
|
seed = random.randint(0, 1000000) |
|
_render = pydiffvg.RenderFunction.apply |
|
scene_args = pydiffvg.RenderFunction.serialize_scene( |
|
canvas_width, canvas_height, shapes, shape_groups) |
|
img = _render(canvas_width, canvas_height, samples, samples, |
|
seed, |
|
None, |
|
*scene_args) |
|
return img |
|
|
|
|
|
def opacityStroke2diffvg(strokes, canvas_size=128, debug=False, relative=True, |
|
force_cpu=True): |
|
|
|
dev = strokes.device |
|
if force_cpu: |
|
strokes = strokes.to("cpu") |
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Rasterize strokes given in (dx, dy, opacity) sequence format.""" |
|
bs, nsegs, dims = strokes.shape |
|
out = [] |
|
|
|
start = time.time() |
|
for batch_idx, stroke in enumerate(strokes): |
|
|
|
if relative: |
|
all_points = stroke[..., :2].cumsum(0) |
|
else: |
|
all_points = stroke[..., :2] |
|
|
|
all_opacities = stroke[..., 2] |
|
|
|
|
|
|
|
all_points = 0.5*(all_points + 1.0) * canvas_size |
|
|
|
|
|
|
|
eps = 1e-4 |
|
all_points = all_points + eps*th.randn_like(all_points) |
|
|
|
shapes = [] |
|
shape_groups = [] |
|
|
|
for start_idx in range(0, nsegs-1): |
|
points = all_points[start_idx:start_idx+2].contiguous().float() |
|
opacity = all_opacities[start_idx] |
|
|
|
num_ctrl_pts = th.zeros(points.shape[0] - 1, dtype=th.int32) |
|
width = th.ones(1) |
|
|
|
path = pydiffvg.Path( |
|
num_control_points=num_ctrl_pts, points=points, |
|
stroke_width=width, is_closed=False) |
|
|
|
shapes.append(path) |
|
|
|
color = th.cat([th.ones(3, device=opacity.device), |
|
opacity.unsqueeze(0)], 0) |
|
path_group = pydiffvg.ShapeGroup( |
|
shape_ids=th.tensor([len(shapes) - 1]), |
|
fill_color=None, |
|
stroke_color=color) |
|
shape_groups.append(path_group) |
|
|
|
|
|
if shapes: |
|
inner_start = time.time() |
|
out.append(render(canvas_size, canvas_size, shapes, shape_groups, |
|
samples=4)) |
|
if debug: |
|
inner_elapsed = time.time() - inner_start |
|
print("diffvg call took %.2fms" % inner_elapsed) |
|
else: |
|
out.append(th.zeros(canvas_size, canvas_size, 4, |
|
device=strokes.device)) |
|
|
|
if debug: |
|
elapsed = (time.time() - start)*1000 |
|
print("rendering took %.2fms" % elapsed) |
|
images = th.stack(out, 0).permute(0, 3, 1, 2).contiguous() |
|
|
|
|
|
return images.to(dev) |
|
|
|
|
|
def stroke2diffvg(strokes, canvas_size=128): |
|
"""Rasterize strokes given some sequential data.""" |
|
bs, nsegs, dims = strokes.shape |
|
out = [] |
|
for stroke_idx, stroke in enumerate(strokes): |
|
end_of_stroke = stroke[:, 4] == 1 |
|
last = end_of_stroke.cpu().numpy().argmax() |
|
stroke = stroke[:last+1, :] |
|
|
|
|
|
|
|
split_idx = stroke[:, 3].nonzero().squeeze(1) |
|
|
|
|
|
all_points = stroke[..., :2].cumsum(0) |
|
|
|
|
|
all_points[..., 0] += 0.5 |
|
all_points[..., 0] *= canvas_size |
|
all_points[..., 1] += 0.5 |
|
all_points[..., 1] *= canvas_size |
|
|
|
|
|
all_points[..., :2] = th.clamp(all_points[..., :2], 0, canvas_size) |
|
|
|
shape_groups = [] |
|
shapes = [] |
|
start_idx = 0 |
|
|
|
for count, end_idx in enumerate(split_idx): |
|
points = all_points[start_idx:end_idx+1].contiguous().float() |
|
|
|
if points.shape[0] <= 2: |
|
continue |
|
|
|
num_ctrl_pts = th.zeros(points.shape[0] - 1, dtype=th.int32) |
|
width = th.ones(1) |
|
path = pydiffvg.Path( |
|
num_control_points=num_ctrl_pts, points=points, |
|
stroke_width=width, is_closed=False) |
|
|
|
start_idx = end_idx+1 |
|
shapes.append(path) |
|
|
|
color = th.ones(4, 1) |
|
path_group = pydiffvg.ShapeGroup( |
|
shape_ids=th.tensor([len(shapes) - 1]), |
|
fill_color=None, |
|
stroke_color=color) |
|
shape_groups.append(path_group) |
|
|
|
|
|
if shapes: |
|
|
|
out.append(render(canvas_size, canvas_size, shapes, shape_groups, samples=2)) |
|
else: |
|
out.append(th.zeros(canvas_size, canvas_size, 4, |
|
device=strokes.device)) |
|
|
|
return th.stack(out, 0).permute(0, 3, 1, 2)[:, :3].contiguous() |
|
|
|
|
|
def line_render(all_points, all_widths, all_alphas, force_cpu=True, |
|
canvas_size=32, colors=None): |
|
dev = all_points.device |
|
if force_cpu: |
|
all_points = all_points.to("cpu") |
|
all_widths = all_widths.to("cpu") |
|
all_alphas = all_alphas.to("cpu") |
|
|
|
if colors is not None: |
|
colors = colors.to("cpu") |
|
|
|
all_points = 0.5*(all_points + 1.0) * canvas_size |
|
|
|
eps = 1e-4 |
|
all_points = all_points + eps*th.randn_like(all_points) |
|
|
|
bs, num_segments, _, _ = all_points.shape |
|
n_out = 3 if colors is not None else 1 |
|
output = th.zeros(bs, n_out, canvas_size, canvas_size, |
|
device=all_points.device) |
|
|
|
scenes = [] |
|
for k in range(bs): |
|
shapes = [] |
|
shape_groups = [] |
|
for p in range(num_segments): |
|
points = all_points[k, p].contiguous().cpu() |
|
num_ctrl_pts = th.zeros(1, dtype=th.int32) |
|
width = all_widths[k, p].cpu() |
|
alpha = all_alphas[k, p].cpu() |
|
if colors is not None: |
|
color = colors[k, p] |
|
else: |
|
color = th.ones(3, device=alpha.device) |
|
|
|
color = th.cat([color, alpha.view(1,)]) |
|
|
|
path = pydiffvg.Path( |
|
num_control_points=num_ctrl_pts, points=points, |
|
stroke_width=width, is_closed=False) |
|
shapes.append(path) |
|
path_group = pydiffvg.ShapeGroup( |
|
shape_ids=th.tensor([len(shapes) - 1]), |
|
fill_color=None, |
|
stroke_color=color) |
|
shape_groups.append(path_group) |
|
|
|
|
|
scenes.append((canvas_size, canvas_size, shapes, shape_groups)) |
|
raster = render(canvas_size, canvas_size, shapes, shape_groups, |
|
samples=2) |
|
raster = raster.permute(2, 0, 1).view(4, canvas_size, canvas_size) |
|
|
|
alpha = raster[3:4] |
|
if colors is not None: |
|
image = raster[:3] |
|
alpha = alpha.repeat(3, 1, 1) |
|
else: |
|
image = raster[:1] |
|
|
|
|
|
image = image*alpha |
|
output[k] = image |
|
|
|
output = output.to(dev) |
|
|
|
return output, scenes |
|
|
|
|
|
def bezier_render(all_points, all_widths, all_alphas, force_cpu=True, |
|
canvas_size=32, colors=None): |
|
dev = all_points.device |
|
if force_cpu: |
|
all_points = all_points.to("cpu") |
|
all_widths = all_widths.to("cpu") |
|
all_alphas = all_alphas.to("cpu") |
|
|
|
if colors is not None: |
|
colors = colors.to("cpu") |
|
|
|
all_points = 0.5*(all_points + 1.0) * canvas_size |
|
|
|
eps = 1e-4 |
|
all_points = all_points + eps*th.randn_like(all_points) |
|
|
|
bs, num_strokes, num_pts, _ = all_points.shape |
|
num_segments = (num_pts - 1) // 3 |
|
n_out = 3 if colors is not None else 1 |
|
output = th.zeros(bs, n_out, canvas_size, canvas_size, |
|
device=all_points.device) |
|
|
|
scenes = [] |
|
for k in range(bs): |
|
shapes = [] |
|
shape_groups = [] |
|
for p in range(num_strokes): |
|
points = all_points[k, p].contiguous().cpu() |
|
|
|
num_ctrl_pts = th.zeros(num_segments, dtype=th.int32) + 2 |
|
width = all_widths[k, p].cpu() |
|
alpha = all_alphas[k, p].cpu() |
|
if colors is not None: |
|
color = colors[k, p] |
|
else: |
|
color = th.ones(3, device=alpha.device) |
|
|
|
color = th.cat([color, alpha.view(1,)]) |
|
|
|
path = pydiffvg.Path( |
|
num_control_points=num_ctrl_pts, points=points, |
|
stroke_width=width, is_closed=False) |
|
shapes.append(path) |
|
path_group = pydiffvg.ShapeGroup( |
|
shape_ids=th.tensor([len(shapes) - 1]), |
|
fill_color=None, |
|
stroke_color=color) |
|
shape_groups.append(path_group) |
|
|
|
|
|
scenes.append((canvas_size, canvas_size, shapes, shape_groups)) |
|
raster = render(canvas_size, canvas_size, shapes, shape_groups, |
|
samples=2) |
|
raster = raster.permute(2, 0, 1).view(4, canvas_size, canvas_size) |
|
|
|
alpha = raster[3:4] |
|
if colors is not None: |
|
image = raster[:3] |
|
alpha = alpha.repeat(3, 1, 1) |
|
else: |
|
image = raster[:1] |
|
|
|
|
|
image = image*alpha |
|
output[k] = image |
|
|
|
output = output.to(dev) |
|
|
|
return output, scenes |
|
|