This commit is contained in:
Akko
2023-05-15 16:23:02 +02:00
63 changed files with 1067 additions and 948 deletions

View File

@@ -1,5 +0,0 @@
v 100 150
v 42.3 50
v 157.7 50
f 1 2 3

View File

@@ -3,140 +3,146 @@ import torch
import skimage import skimage
import numpy as np import numpy as np
# Use GPU if available def run():
pydiffvg.set_use_gpu(torch.cuda.is_available())
canvas_width, canvas_height = 256, 256 # Use GPU if available
num_control_points = torch.tensor([2, 2, 2]) pydiffvg.set_use_gpu(torch.cuda.is_available())
points = torch.tensor([[20.0, 30.0], # base
[50.0, 60.0], # control point
[ 90.0, 198.0], # control point
[ 60.0, 218.0], # base
[ 90.0, 180.0], # control point
[200.0, 85.0], # control point
[230.0, 90.0], # base
[220.0, 70.0], # control point
[130.0, 55.0]]) # control point
path = pydiffvg.Path(num_control_points = num_control_points,
points = points,
is_closed = True)
shapes = [path]
path_group = pydiffvg.ShapeGroup(shape_ids = torch.tensor([0]),
fill_color = torch.tensor([0.3, 0.6, 0.3, 1.0]))
shape_groups = [path_group]
scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups)
render = pydiffvg.RenderFunction.apply canvas_width, canvas_height = 256, 256
img = render(256, # width num_control_points = torch.tensor([2, 2, 2])
256, # height points = torch.tensor([[20.0, 30.0], # base
2, # num_samples_x [50.0, 60.0], # control point
2, # num_samples_y [ 90.0, 198.0], # control point
0, # seed [ 60.0, 218.0], # base
None, [ 90.0, 180.0], # control point
*scene_args) [200.0, 85.0], # control point
# The output image is in linear RGB space. Do Gamma correction before saving the image. [230.0, 90.0], # base
pydiffvg.imwrite(img.cpu(), 'results/test_curve/target.png', gamma=2.2) [220.0, 70.0], # control point
target = img.clone() [130.0, 55.0]]) # control point
path = pydiffvg.Path(num_control_points = num_control_points,
points = points,
is_closed = True)
shapes = [path]
path_group = pydiffvg.ShapeGroup(shape_ids = torch.tensor([0]),
fill_color = torch.tensor([0.3, 0.6, 0.3, 1.0]))
shape_groups = [path_group]
scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups)
# Load the obj file, get the vertices/control points render = pydiffvg.RenderFunction.apply
obj = "imgs/Triangle.obj" img = render(256, # width
vertices_tmp, faces_tmp = pydiffvg.obj_to_scene(obj) 256, # height
print(float(vertices_tmp[1][1])) 2, # num_samples_x
print(faces_tmp) 2, # num_samples_y
0, # seed
None,
*scene_args)
# The output image is in linear RGB space. Do Gamma correction before saving the image.
pydiffvg.imwrite(img.cpu(), 'results/test_curve/target.png', gamma=2.2)
target = img.clone()
vertices = [] # Load the obj file, get the vertices/control points
faces = [] obj = "imgs/Triangle.obj"
for v in vertices_tmp: vertices_tmp, faces_tmp = pydiffvg.obj_to_scene(obj)
vertices.append([float(v[1]), float(v[2])]) print(float(vertices_tmp[1][1]))
for f in faces_tmp: print(faces_tmp)
vs_count = len(f)
tmp = []
for v in f[1:]:
tmp.append(int(v))
faces.append(tmp)
print(vertices)
print(faces)
# Ternary subdivision vertices = []
# Move the path to produce initial guess faces = []
# normalize points for easier learning rate for v in vertices_tmp:
points_n = torch.tensor([[vertices[0][0]/256.0, vertices[0][1]/256.0], # base vertices.append([float(v[1]), float(v[2])])
[70.0/256.0, 140.0/256.0], # control point for f in faces_tmp:
[50.0/256.0, 100.0/256.0], # control point vs_count = len(f)
[vertices[1][0]/256.0, vertices[1][1]/256.0], # base tmp = []
[80.0/256.0, 40.0/256.0], # control point for v in f[1:]:
[120.0/256.0, 40.0/256.0], # control point tmp.append(int(v))
[vertices[2][0]/256.0, vertices[2][1]/256.0], # base faces.append(tmp)
[150.0/256.0, 100.0/256.0], # control point print(vertices)
[130.0/256.0, 140.0/256.0]], # control point print(faces)
requires_grad = True)
color = torch.tensor([0.3, 0.2, 0.5, 1.0], requires_grad=True)
path.points = points_n * 256
path_group.fill_color = color
scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups)
img = render(256, # width
256, # height
2, # num_samples_x
2, # num_samples_y
1, # seed
None,
*scene_args)
pydiffvg.imwrite(img.cpu(), 'results/test_curve/init.png', gamma=2.2)
# Optimize # Ternary subdivision
optimizer = torch.optim.Adam([points_n, color], lr=1e-2) # Move the path to produce initial guess
# Run 100 Adam iterations. # normalize points for easier learning rate
for t in range(100): points_n = torch.tensor([[vertices[0][0]/256.0, vertices[0][1]/256.0], # base
print('iteration:', t) [70.0/256.0, 140.0/256.0], # control point
optimizer.zero_grad() [50.0/256.0, 100.0/256.0], # control point
# Forward pass: render the image. [vertices[1][0]/256.0, vertices[1][1]/256.0], # base
[80.0/256.0, 40.0/256.0], # control point
[120.0/256.0, 40.0/256.0], # control point
[vertices[2][0]/256.0, vertices[2][1]/256.0], # base
[150.0/256.0, 100.0/256.0], # control point
[130.0/256.0, 140.0/256.0]], # control point
requires_grad = True)
color = torch.tensor([0.3, 0.2, 0.5, 1.0], requires_grad=True)
path.points = points_n * 256 path.points = points_n * 256
path_group.fill_color = color path_group.fill_color = color
scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups)
return scene_args
img = render(256, # width
256, # height
2, # num_samples_x
2, # num_samples_y
1, # seed
None,
*scene_args)
pydiffvg.imwrite(img.cpu(), 'results/test_curve/init.png', gamma=2.2)
# Optimize
optimizer = torch.optim.Adam([points_n, color], lr=1e-2)
# Run 100 Adam iterations.
for t in range(100):
print('iteration:', t)
optimizer.zero_grad()
# Forward pass: render the image.
path.points = points_n * 256
path_group.fill_color = color
scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups)
img = render(256, # width
256, # height
2, # num_samples_x
2, # num_samples_y
t+1, # seed
None,
*scene_args)
# Save the intermediate render.
pydiffvg.imwrite(img.cpu(),
'results/test_curve/iter_{}.png'.format(t), gamma=2.2)
# Compute the loss function. Here it is L2.
loss = (img - target).pow(2).sum()
print('loss:', loss.item())
# Backpropagate the gradients.
loss.backward()
# Print the gradients
print('points_n.grad:', points_n.grad)
print('color.grad:', color.grad)
# Take a gradient descent step.
optimizer.step()
# Print the current params.
print('points:', path.points)
print('color:', path_group.fill_color)
# Render the final result.
scene_args = pydiffvg.RenderFunction.serialize_scene(\ scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups) canvas_width, canvas_height, shapes, shape_groups)
img = render(256, # width img = render(256, # width
256, # height 256, # height
2, # num_samples_x 2, # num_samples_x
2, # num_samples_y 2, # num_samples_y
t+1, # seed 102, # seed
None, None,
*scene_args) *scene_args)
# Save the intermediate render. # Save the images and differences.
pydiffvg.imwrite(img.cpu(), 'results/test_curve/iter_{}.png'.format(t), gamma=2.2) pydiffvg.imwrite(img.cpu(), 'results/test_curve/final.png')
# Compute the loss function. Here it is L2.
loss = (img - target).pow(2).sum()
print('loss:', loss.item())
# Backpropagate the gradients. # Convert the intermediate renderings to a video.
loss.backward() from subprocess import call
# Print the gradients call(["ffmpeg", "-framerate", "24", "-i",
print('points_n.grad:', points_n.grad) "results/test_curve/iter_%d.png", "-vb", "20M",
print('color.grad:', color.grad) "results/test_curve/out.mp4"])
# Take a gradient descent step.
optimizer.step()
# Print the current params.
print('points:', path.points)
print('color:', path_group.fill_color)
# Render the final result.
scene_args = pydiffvg.RenderFunction.serialize_scene(\
canvas_width, canvas_height, shapes, shape_groups)
img = render(256, # width
256, # height
2, # num_samples_x
2, # num_samples_y
102, # seed
None,
*scene_args)
# Save the images and differences.
pydiffvg.imwrite(img.cpu(), 'results/test_curve/final.png')
# Convert the intermediate renderings to a video.
from subprocess import call
call(["ffmpeg", "-framerate", "24", "-i",
"results/test_curve/iter_%d.png", "-vb", "20M",
"results/test_curve/out.mp4"])
if __name__ == "__main__":
run()

13
color.h
View File

@@ -7,7 +7,8 @@
enum class ColorType { enum class ColorType {
Constant, Constant,
LinearGradient, LinearGradient,
RadialGradient RadialGradient,
PatchGradient
}; };
struct Constant { struct Constant {
@@ -61,3 +62,13 @@ struct RadialGradient {
float *stop_offsets; float *stop_offsets;
float *stop_colors; // rgba float *stop_colors; // rgba
}; };
/*
struct PatchGradient {
PatchGradient(const Vector2f &topLeft,
const Vector2f &topRight,
const Vector2f &bottomLeft,
const Vector2f &bottomRight,
const )
}
*/

View File

@@ -1490,6 +1490,11 @@ void render(std::shared_ptr<Scene> scene,
bool use_prefiltering, bool use_prefiltering,
ptr<float> eval_positions, ptr<float> eval_positions,
int num_eval_positions) { int num_eval_positions) {
/////////////////
// Setup stuff //
/////////////////
#ifdef __NVCC__ #ifdef __NVCC__
int old_device_id = -1; int old_device_id = -1;
if (scene->use_gpu) { if (scene->use_gpu) {
@@ -1519,6 +1524,11 @@ void render(std::shared_ptr<Scene> scene,
} }
} }
///////////////////////////////////////////////////////////////////
// IDK what this does but I think it relates to the prefiltering //
// TODO //
///////////////////////////////////////////////////////////////////
if (render_image.get() != nullptr || d_render_image.get() != nullptr || if (render_image.get() != nullptr || d_render_image.get() != nullptr ||
render_sdf.get() != nullptr || d_render_sdf.get() != nullptr) { render_sdf.get() != nullptr || d_render_sdf.get() != nullptr) {
if (weight_image != nullptr) { if (weight_image != nullptr) {
@@ -1533,6 +1543,11 @@ void render(std::shared_ptr<Scene> scene,
}, width * height * num_samples_x * num_samples_y, scene->use_gpu); }, width * height * num_samples_x * num_samples_y, scene->use_gpu);
} }
////////////////////////////////////////////////
// Think this relates to the actual rendering //
////////////////////////////////////////////////
auto num_samples = eval_positions.get() == nullptr ? auto num_samples = eval_positions.get() == nullptr ?
width * height * num_samples_x * num_samples_y : num_eval_positions; width * height * num_samples_x * num_samples_y : num_eval_positions;
parallel_for(render_kernel{ parallel_for(render_kernel{
@@ -1555,6 +1570,11 @@ void render(std::shared_ptr<Scene> scene,
}, num_samples, scene->use_gpu); }, num_samples, scene->use_gpu);
} }
/////////////////////////////////////////////////////////////////////
// The reason for this is described in the diffvg paper //
// I don't think it's especially important for the gradient meshes //
/////////////////////////////////////////////////////////////////////
// Boundary sampling // Boundary sampling
if (!use_prefiltering && d_render_image.get() != nullptr) { if (!use_prefiltering && d_render_image.get() != nullptr) {
auto num_samples = width * height * num_samples_x * num_samples_y; auto num_samples = width * height * num_samples_x * num_samples_y;

1104
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -586,13 +586,17 @@ def obj_to_scene(filename):
""" """
Load from a obj file and convert to PyTorch tensors. Load from a obj file and convert to PyTorch tensors.
""" """
f = open(filename) with open(filename, 'r') as f:
lines = f.readlines() lines = f.readlines()
data_lines = [] data_lines = []
vertices = [] vertices = []
faces = [] faces = []
for line in lines: for line in lines:
l=line.split() l=line.split()
# Ignore empty lines
if not l:
continue
#vertex #vertex
if(l[0] == "v"): if(l[0] == "v"):
vertices.append(l) vertices.append(l)

View File

@@ -7,6 +7,9 @@ import warnings
print_timing = False print_timing = False
def popmult(lst, n):
return (lst[:n], lst[n:])
def set_print_timing(val): def set_print_timing(val):
global print_timing global print_timing
print_timing=val print_timing=val
@@ -35,98 +38,128 @@ class RenderFunction(torch.autograd.Function):
""" """
num_shapes = len(shapes) num_shapes = len(shapes)
num_shape_groups = len(shape_groups) num_shape_groups = len(shape_groups)
args = [] args = [canvas_width,
args.append(canvas_width) canvas_height,
args.append(canvas_height) num_shapes,
args.append(num_shapes) num_shape_groups,
args.append(num_shape_groups) output_type,
args.append(output_type) use_prefiltering,
args.append(use_prefiltering) eval_positions.to(pydiffvg.get_device())]
args.append(eval_positions.to(pydiffvg.get_device()))
for shape in shapes: for shape in shapes:
use_thickness = False use_thickness = False
if isinstance(shape, pydiffvg.Circle): if isinstance(shape, pydiffvg.Circle):
assert(shape.center.is_contiguous()) assert shape.center.is_contiguous()
args.append(diffvg.ShapeType.circle) args += [
args.append(shape.radius.cpu()) diffvg.ShapeType.circle,
args.append(shape.center.cpu()) shape.radius.cpu(),
shape.center.cpu()
]
elif isinstance(shape, pydiffvg.Ellipse): elif isinstance(shape, pydiffvg.Ellipse):
assert(shape.radius.is_contiguous()) assert shape.radius.is_contiguous()
assert(shape.center.is_contiguous()) assert shape.center.is_contiguous()
args.append(diffvg.ShapeType.ellipse) args += [
args.append(shape.radius.cpu()) diffvg.ShapeType.ellipse,
args.append(shape.center.cpu()) shape.radius.cpu(),
shape.center.cpu()
]
elif isinstance(shape, pydiffvg.Path): elif isinstance(shape, pydiffvg.Path):
assert(shape.num_control_points.is_contiguous()) assert shape.num_control_points.is_contiguous()
assert(shape.points.is_contiguous()) assert shape.points.is_contiguous()
assert(shape.points.shape[1] == 2) assert shape.points.shape[1] == 2
assert(torch.isfinite(shape.points).all()) assert torch.isfinite(shape.points).all()
args.append(diffvg.ShapeType.path)
args.append(shape.num_control_points.to(torch.int32).cpu()) args += [
args.append(shape.points.cpu()) diffvg.ShapeType.path,
shape.num_control_points.to(torch.int32).cpu(),
shape.points.cpu()
]
if len(shape.stroke_width.shape) > 0 and shape.stroke_width.shape[0] > 1: if len(shape.stroke_width.shape) > 0 and shape.stroke_width.shape[0] > 1:
assert(torch.isfinite(shape.stroke_width).all()) assert torch.isfinite(shape.stroke_width).all()
use_thickness = True use_thickness = True
args.append(shape.stroke_width.cpu()) args.append(shape.stroke_width.cpu())
else: else:
args.append(None) args.append(None)
args.append(shape.is_closed)
args.append(shape.use_distance_approx) args += [shape.is_closed, shape.use_distance_approx]
elif isinstance(shape, pydiffvg.Polygon): elif isinstance(shape, pydiffvg.Polygon):
assert(shape.points.is_contiguous()) assert shape.points.is_contiguous()
assert(shape.points.shape[1] == 2) assert shape.points.shape[1] == 2
args.append(diffvg.ShapeType.path) args.append(diffvg.ShapeType.path)
if shape.is_closed: if shape.is_closed:
args.append(torch.zeros(shape.points.shape[0], dtype = torch.int32)) args.append(torch.zeros(shape.points.shape[0], dtype = torch.int32))
else: else:
args.append(torch.zeros(shape.points.shape[0] - 1, dtype = torch.int32)) args.append(torch.zeros(shape.points.shape[0] - 1, dtype = torch.int32))
args.append(shape.points.cpu())
args.append(None) args += [
args.append(shape.is_closed) shape.points.cpu(),
args.append(False) # use_distance_approx None,
shape.is_closed(),
False # use_distance_approx
]
elif isinstance(shape, pydiffvg.Rect): elif isinstance(shape, pydiffvg.Rect):
assert(shape.p_min.is_contiguous()) assert shape.p_min.is_contiguous()
assert(shape.p_max.is_contiguous()) assert shape.p_max.is_contiguous()
args.append(diffvg.ShapeType.rect)
args.append(shape.p_min.cpu()) args += [
args.append(shape.p_max.cpu()) diffvg.ShapeType.rect,
shape.p_min.cpu(),
shape.p_max.cpu()
]
else: else:
assert(False) assert False
if use_thickness: if use_thickness:
args.append(torch.tensor(0.0)) args.append(torch.tensor(0.0))
else: else:
args.append(shape.stroke_width.cpu()) args.append(shape.stroke_width.cpu())
for shape_group in shape_groups: for shape_group in shape_groups:
assert(shape_group.shape_ids.is_contiguous()) assert shape_group.shape_ids.is_contiguous()
args.append(shape_group.shape_ids.to(torch.int32).cpu()) args.append(shape_group.shape_ids.to(torch.int32).cpu())
# Fill color # Fill color
if shape_group.fill_color is None: if shape_group.fill_color is None:
args.append(None) args.append(None)
elif isinstance(shape_group.fill_color, torch.Tensor): elif isinstance(shape_group.fill_color, torch.Tensor):
assert(shape_group.fill_color.is_contiguous()) assert shape_group.fill_color.is_contiguous()
args.append(diffvg.ColorType.constant)
args.append(shape_group.fill_color.cpu()) args += [
diffvg.ColorType.constant,
shape_group.fill_color.cpu()
]
elif isinstance(shape_group.fill_color, pydiffvg.LinearGradient): elif isinstance(shape_group.fill_color, pydiffvg.LinearGradient):
assert(shape_group.fill_color.begin.is_contiguous()) assert shape_group.fill_color.begin.is_contiguous()
assert(shape_group.fill_color.end.is_contiguous()) assert shape_group.fill_color.end.is_contiguous()
assert(shape_group.fill_color.offsets.is_contiguous()) assert shape_group.fill_color.offsets.is_contiguous()
assert(shape_group.fill_color.stop_colors.is_contiguous()) assert shape_group.fill_color.stop_colors.is_contiguous()
args.append(diffvg.ColorType.linear_gradient)
args.append(shape_group.fill_color.begin.cpu()) args += [
args.append(shape_group.fill_color.end.cpu()) diffvg.ColorType.linear_gradient,
args.append(shape_group.fill_color.offsets.cpu()) shape_group.fill_color.begin.cpu(),
args.append(shape_group.fill_color.stop_colors.cpu()) shape_group.fill_color.end.cpu(),
shape_group.fill_color.offsets.cpu(),
shape_group.fill_color.stop_colors.cpu(),
]
elif isinstance(shape_group.fill_color, pydiffvg.RadialGradient): elif isinstance(shape_group.fill_color, pydiffvg.RadialGradient):
assert(shape_group.fill_color.center.is_contiguous()) assert shape_group.fill_color.center.is_contiguous()
assert(shape_group.fill_color.radius.is_contiguous()) assert shape_group.fill_color.radius.is_contiguous()
assert(shape_group.fill_color.offsets.is_contiguous()) assert shape_group.fill_color.offsets.is_contiguous()
assert(shape_group.fill_color.stop_colors.is_contiguous()) assert shape_group.fill_color.stop_colors.is_contiguous()
args.append(diffvg.ColorType.radial_gradient)
args.append(shape_group.fill_color.center.cpu()) args += [
args.append(shape_group.fill_color.radius.cpu()) diffvg.ColorType.radial_gradient,
args.append(shape_group.fill_color.offsets.cpu()) shape_group.fill_color.center.cpu(),
args.append(shape_group.fill_color.stop_colors.cpu()) shape_group.fill_color.radius.cpu(),
shape_group.fill_color.offsets.cpu(),
shape_group.fill_color.stop_colors.cpu()
]
if shape_group.fill_color is not None: if shape_group.fill_color is not None:
# go through the underlying shapes and check if they are all closed # go through the underlying shapes and check if they are all closed
@@ -138,35 +171,44 @@ class RenderFunction(torch.autograd.Function):
# Stroke color # Stroke color
if shape_group.stroke_color is None: if shape_group.stroke_color is None:
args.append(None) args.append(None)
elif isinstance(shape_group.stroke_color, torch.Tensor): elif isinstance(shape_group.stroke_color, torch.Tensor):
assert(shape_group.stroke_color.is_contiguous()) assert shape_group.stroke_color.is_contiguous()
args.append(diffvg.ColorType.constant) args += [ diffvg.ColorType.constant, shape_group.stroke_color.cpu() ]
args.append(shape_group.stroke_color.cpu())
elif isinstance(shape_group.stroke_color, pydiffvg.LinearGradient): elif isinstance(shape_group.stroke_color, pydiffvg.LinearGradient):
assert(shape_group.stroke_color.begin.is_contiguous()) assert shape_group.stroke_color.begin.is_contiguous()
assert(shape_group.stroke_color.end.is_contiguous()) assert shape_group.stroke_color.end.is_contiguous()
assert(shape_group.stroke_color.offsets.is_contiguous()) assert shape_group.stroke_color.offsets.is_contiguous()
assert(shape_group.stroke_color.stop_colors.is_contiguous()) assert shape_group.stroke_color.stop_colors.is_contiguous()
assert(torch.isfinite(shape_group.stroke_color.stop_colors).all()) assert torch.isfinite(shape_group.stroke_color.stop_colors).all()
args.append(diffvg.ColorType.linear_gradient)
args.append(shape_group.stroke_color.begin.cpu()) args += [
args.append(shape_group.stroke_color.end.cpu()) diffvg.ColorType.linear_gradient,
args.append(shape_group.stroke_color.offsets.cpu()) shape_group.stroke_color.begin.cpu(),
args.append(shape_group.stroke_color.stop_colors.cpu()) shape_group.stroke_color.end.cpu(),
shape_group.stroke_color.offsets.cpu(),
shape_group.stroke_color.stop_colors.cpu()
]
elif isinstance(shape_group.stroke_color, pydiffvg.RadialGradient): elif isinstance(shape_group.stroke_color, pydiffvg.RadialGradient):
assert(shape_group.stroke_color.center.is_contiguous()) assert shape_group.stroke_color.center.is_contiguous()
assert(shape_group.stroke_color.radius.is_contiguous()) assert shape_group.stroke_color.radius.is_contiguous()
assert(shape_group.stroke_color.offsets.is_contiguous()) assert shape_group.stroke_color.offsets.is_contiguous()
assert(shape_group.stroke_color.stop_colors.is_contiguous()) assert shape_group.stroke_color.stop_colors.is_contiguous()
assert(torch.isfinite(shape_group.stroke_color.stop_colors).all()) assert torch.isfinite(shape_group.stroke_color.stop_colors).all()
args.append(diffvg.ColorType.radial_gradient)
args.append(shape_group.stroke_color.center.cpu()) args += [
args.append(shape_group.stroke_color.radius.cpu()) diffvg.ColorType.radial_gradient,
args.append(shape_group.stroke_color.offsets.cpu()) shape_group.stroke_color.center.cpu(),
args.append(shape_group.stroke_color.stop_colors.cpu()) shape_group.stroke_color.radius.cpu(),
args.append(shape_group.use_even_odd_rule) shape_group.stroke_color.offsets.cpu(),
# Transformation shape_group.stroke_color.stop_colors.cpu()
args.append(shape_group.shape_to_canvas.contiguous().cpu()) ]
args += [ shape_group.use_even_odd_rule,
shape_group.shape_to_canvas.contiguous().cpu() ]
args.append(filter.type) args.append(filter.type)
args.append(filter.radius.cpu()) args.append(filter.radius.cpu())
return args return args
@@ -184,52 +226,31 @@ class RenderFunction(torch.autograd.Function):
Forward rendering pass. Forward rendering pass.
""" """
# Unpack arguments # Unpack arguments
current_index = 0 args = list(args)
canvas_width = args[current_index]
current_index += 1 (canvas_width, canvas_height, num_shapes,
canvas_height = args[current_index] num_shape_groups, output_type, use_prefiltering, eval_positions), args = popmult(args, 7)
current_index += 1
num_shapes = args[current_index]
current_index += 1
num_shape_groups = args[current_index]
current_index += 1
output_type = args[current_index]
current_index += 1
use_prefiltering = args[current_index]
current_index += 1
eval_positions = args[current_index]
current_index += 1
shapes = [] shapes = []
shape_groups = [] shape_groups = []
shape_contents = [] # Important to avoid GC deleting the shapes shape_contents = [] # Important to avoid GC deleting the shapes
color_contents = [] # Same as above color_contents = [] # Same as above
for shape_id in range(num_shapes): for shape_id in range(num_shapes):
shape_type = args[current_index] shape_type = args.pop(0)
current_index += 1
if shape_type == diffvg.ShapeType.circle: if shape_type == diffvg.ShapeType.circle:
radius = args[current_index] (radius, center), args = popmult(args, 2)
current_index += 1
center = args[current_index]
current_index += 1
shape = diffvg.Circle(radius, diffvg.Vector2f(center[0], center[1])) shape = diffvg.Circle(radius, diffvg.Vector2f(center[0], center[1]))
elif shape_type == diffvg.ShapeType.ellipse: elif shape_type == diffvg.ShapeType.ellipse:
radius = args[current_index] (radius, center), args = popmult(args, 2)
current_index += 1
center = args[current_index]
current_index += 1
shape = diffvg.Ellipse(diffvg.Vector2f(radius[0], radius[1]), shape = diffvg.Ellipse(diffvg.Vector2f(radius[0], radius[1]),
diffvg.Vector2f(center[0], center[1])) diffvg.Vector2f(center[0], center[1]))
elif shape_type == diffvg.ShapeType.path: elif shape_type == diffvg.ShapeType.path:
num_control_points = args[current_index]
current_index += 1 (num_control_points, points, thickness,
points = args[current_index] is_closed, use_distance_approx), args = popmult(args, 5)
current_index += 1
thickness = args[current_index]
current_index += 1
is_closed = args[current_index]
current_index += 1
use_distance_approx = args[current_index]
current_index += 1
shape = diffvg.Path(diffvg.int_ptr(num_control_points.data_ptr()), shape = diffvg.Path(diffvg.int_ptr(num_control_points.data_ptr()),
diffvg.float_ptr(points.data_ptr()), diffvg.float_ptr(points.data_ptr()),
diffvg.float_ptr(thickness.data_ptr() if thickness is not None else 0), diffvg.float_ptr(thickness.data_ptr() if thickness is not None else 0),
@@ -238,55 +259,36 @@ class RenderFunction(torch.autograd.Function):
is_closed, is_closed,
use_distance_approx) use_distance_approx)
elif shape_type == diffvg.ShapeType.rect: elif shape_type == diffvg.ShapeType.rect:
p_min = args[current_index] (p_min, p_max), args = popmult(args, 2)
current_index += 1
p_max = args[current_index]
current_index += 1
shape = diffvg.Rect(diffvg.Vector2f(p_min[0], p_min[1]), shape = diffvg.Rect(diffvg.Vector2f(p_min[0], p_min[1]),
diffvg.Vector2f(p_max[0], p_max[1])) diffvg.Vector2f(p_max[0], p_max[1]))
else: else:
assert(False) assert False
stroke_width = args[current_index]
current_index += 1 stroke_width = args.pop(0)
shapes.append(diffvg.Shape(\ shapes.append(diffvg.Shape(\
shape_type, shape.get_ptr(), stroke_width.item())) shape_type, shape.get_ptr(), stroke_width.item()))
shape_contents.append(shape) shape_contents.append(shape)
for shape_group_id in range(num_shape_groups): for shape_group_id in range(num_shape_groups):
shape_ids = args[current_index] (shape_ids, fill_color_type), args = popmult(args, 2)
current_index += 1
fill_color_type = args[current_index]
current_index += 1
if fill_color_type == diffvg.ColorType.constant: if fill_color_type == diffvg.ColorType.constant:
color = args[current_index] color = args.pop(0)
current_index += 1
fill_color = diffvg.Constant(\ fill_color = diffvg.Constant(\
diffvg.Vector4f(color[0], color[1], color[2], color[3])) diffvg.Vector4f(color[0], color[1], color[2], color[3]))
elif fill_color_type == diffvg.ColorType.linear_gradient: elif fill_color_type == diffvg.ColorType.linear_gradient:
beg = args[current_index] (beg, end, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
end = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
fill_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]), fill_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]),
diffvg.Vector2f(end[0], end[1]), diffvg.Vector2f(end[0], end[1]),
offsets.shape[0], offsets.shape[0],
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif fill_color_type == diffvg.ColorType.radial_gradient: elif fill_color_type == diffvg.ColorType.radial_gradient:
center = args[current_index] (center, radius, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
radius = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
fill_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]), fill_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]),
diffvg.Vector2f(radius[0], radius[1]), diffvg.Vector2f(radius[0], radius[1]),
offsets.shape[0], offsets.shape[0],
@@ -295,39 +297,28 @@ class RenderFunction(torch.autograd.Function):
elif fill_color_type is None: elif fill_color_type is None:
fill_color = None fill_color = None
else: else:
assert(False) assert False
stroke_color_type = args[current_index]
current_index += 1 stroke_color_type = args.pop(0)
if stroke_color_type == diffvg.ColorType.constant: if stroke_color_type == diffvg.ColorType.constant:
color = args[current_index] color = args.pop(0)
current_index += 1
stroke_color = diffvg.Constant(\ stroke_color = diffvg.Constant(\
diffvg.Vector4f(color[0], color[1], color[2], color[3])) diffvg.Vector4f(color[0], color[1], color[2], color[3]))
elif stroke_color_type == diffvg.ColorType.linear_gradient: elif stroke_color_type == diffvg.ColorType.linear_gradient:
beg = args[current_index] (beg, end, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
end = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
stroke_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]), stroke_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]),
diffvg.Vector2f(end[0], end[1]), diffvg.Vector2f(end[0], end[1]),
offsets.shape[0], offsets.shape[0],
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif stroke_color_type == diffvg.ColorType.radial_gradient: elif stroke_color_type == diffvg.ColorType.radial_gradient:
center = args[current_index] (center, radius, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
radius = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
stroke_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]), stroke_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]),
diffvg.Vector2f(radius[0], radius[1]), diffvg.Vector2f(radius[0], radius[1]),
offsets.shape[0], offsets.shape[0],
@@ -335,17 +326,18 @@ class RenderFunction(torch.autograd.Function):
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif stroke_color_type is None: elif stroke_color_type is None:
stroke_color = None stroke_color = None
else: else:
assert(False) assert False
use_even_odd_rule = args[current_index]
current_index += 1 (use_even_odd_rule, shape_to_canvas), args = popmult(args, 2)
shape_to_canvas = args[current_index]
current_index += 1
if fill_color is not None: if fill_color is not None:
color_contents.append(fill_color) color_contents.append(fill_color)
if stroke_color is not None: if stroke_color is not None:
color_contents.append(stroke_color) color_contents.append(stroke_color)
shape_groups.append(diffvg.ShapeGroup(\ shape_groups.append(diffvg.ShapeGroup(\
diffvg.int_ptr(shape_ids.data_ptr()), diffvg.int_ptr(shape_ids.data_ptr()),
shape_ids.shape[0], shape_ids.shape[0],
@@ -356,10 +348,7 @@ class RenderFunction(torch.autograd.Function):
use_even_odd_rule, use_even_odd_rule,
diffvg.float_ptr(shape_to_canvas.data_ptr()))) diffvg.float_ptr(shape_to_canvas.data_ptr())))
filter_type = args[current_index] (filter_type, filter_radius), args = popmult(args, 2)
current_index += 1
filter_radius = args[current_index]
current_index += 1
filt = diffvg.Filter(filter_type, filter_radius) filt = diffvg.Filter(filter_type, filter_radius)
start = time.time() start = time.time()
@@ -367,15 +356,16 @@ class RenderFunction(torch.autograd.Function):
shapes, shape_groups, filt, pydiffvg.get_use_gpu(), shapes, shape_groups, filt, pydiffvg.get_use_gpu(),
pydiffvg.get_device().index if pydiffvg.get_device().index is not None else -1) pydiffvg.get_device().index if pydiffvg.get_device().index is not None else -1)
time_elapsed = time.time() - start time_elapsed = time.time() - start
global print_timing global print_timing
if print_timing: if print_timing:
print('Scene construction, time: %.5f s' % time_elapsed) print('Scene construction, time: %.5f s' % time_elapsed)
if output_type == OutputType.color: if output_type == OutputType.color:
assert(eval_positions.shape[0] == 0) assert eval_positions.shape[0] == 0
rendered_image = torch.zeros(height, width, 4, device = pydiffvg.get_device()) rendered_image = torch.zeros(height, width, 4, device = pydiffvg.get_device())
else: else:
assert(output_type == OutputType.sdf) assert output_type == OutputType.sdf
if eval_positions.shape[0] == 0: if eval_positions.shape[0] == 0:
rendered_image = torch.zeros(height, width, 1, device = pydiffvg.get_device()) rendered_image = torch.zeros(height, width, 1, device = pydiffvg.get_device())
else: else:
@@ -386,9 +376,10 @@ class RenderFunction(torch.autograd.Function):
if background_image.shape[2] == 3: if background_image.shape[2] == 3:
raise NotImplementedError('Background image must have 4 channels, not 3. Add a fourth channel with all ones via torch.ones().') raise NotImplementedError('Background image must have 4 channels, not 3. Add a fourth channel with all ones via torch.ones().')
background_image = background_image.contiguous() background_image = background_image.contiguous()
assert(background_image.shape[0] == rendered_image.shape[0])
assert(background_image.shape[1] == rendered_image.shape[1]) assert background_image.shape[0] == rendered_image.shape[0]
assert(background_image.shape[2] == 4) assert background_image.shape[1] == rendered_image.shape[1]
assert background_image.shape[2] == 4
start = time.time() start = time.time()
diffvg.render(scene, diffvg.render(scene,
@@ -407,7 +398,7 @@ class RenderFunction(torch.autograd.Function):
use_prefiltering, use_prefiltering,
diffvg.float_ptr(eval_positions.data_ptr()), diffvg.float_ptr(eval_positions.data_ptr()),
eval_positions.shape[0]) eval_positions.shape[0])
assert(torch.isfinite(rendered_image).all()) assert torch.isfinite(rendered_image).all()
time_elapsed = time.time() - start time_elapsed = time.time() - start
if print_timing: if print_timing:
print('Forward pass, time: %.5f s' % time_elapsed) print('Forward pass, time: %.5f s' % time_elapsed)
@@ -438,55 +429,33 @@ class RenderFunction(torch.autograd.Function):
*args): *args):
if not grad_img.is_contiguous(): if not grad_img.is_contiguous():
grad_img = grad_img.contiguous() grad_img = grad_img.contiguous()
assert(torch.isfinite(grad_img).all()) assert torch.isfinite(grad_img).all()
args = list(args)
# Unpack arguments # Unpack arguments
current_index = 0 (canvas_width, canvas_height, num_shapes,
canvas_width = args[current_index] num_shape_groups, output_type, use_prefiltering,
current_index += 1 eval_positions), args = popmult(args, 7)
canvas_height = args[current_index]
current_index += 1
num_shapes = args[current_index]
current_index += 1
num_shape_groups = args[current_index]
current_index += 1
output_type = args[current_index]
current_index += 1
use_prefiltering = args[current_index]
current_index += 1
eval_positions = args[current_index]
current_index += 1
shapes = [] shapes = []
shape_groups = [] shape_groups = []
shape_contents = [] # Important to avoid GC deleting the shapes shape_contents = [] # Important to avoid GC deleting the shapes
color_contents = [] # Same as above color_contents = [] # Same as above
for shape_id in range(num_shapes): for shape_id in range(num_shapes):
shape_type = args[current_index] shape_type = args.pop(0)
current_index += 1
if shape_type == diffvg.ShapeType.circle: if shape_type == diffvg.ShapeType.circle:
radius = args[current_index] (radius, center), args = popmult(args, 2)
current_index += 1
center = args[current_index]
current_index += 1
shape = diffvg.Circle(radius, diffvg.Vector2f(center[0], center[1])) shape = diffvg.Circle(radius, diffvg.Vector2f(center[0], center[1]))
elif shape_type == diffvg.ShapeType.ellipse: elif shape_type == diffvg.ShapeType.ellipse:
radius = args[current_index] (radius, center), args = popmult(args, 2)
current_index += 1
center = args[current_index]
current_index += 1
shape = diffvg.Ellipse(diffvg.Vector2f(radius[0], radius[1]), shape = diffvg.Ellipse(diffvg.Vector2f(radius[0], radius[1]),
diffvg.Vector2f(center[0], center[1])) diffvg.Vector2f(center[0], center[1]))
elif shape_type == diffvg.ShapeType.path: elif shape_type == diffvg.ShapeType.path:
num_control_points = args[current_index] (num_control_points, points, thickness,
current_index += 1 is_closed, use_distance_approx), args = popmult(args, 5)
points = args[current_index]
current_index += 1
thickness = args[current_index]
current_index += 1
is_closed = args[current_index]
current_index += 1
use_distance_approx = args[current_index]
current_index += 1
shape = diffvg.Path(diffvg.int_ptr(num_control_points.data_ptr()), shape = diffvg.Path(diffvg.int_ptr(num_control_points.data_ptr()),
diffvg.float_ptr(points.data_ptr()), diffvg.float_ptr(points.data_ptr()),
diffvg.float_ptr(thickness.data_ptr() if thickness is not None else 0), diffvg.float_ptr(thickness.data_ptr() if thickness is not None else 0),
@@ -495,114 +464,93 @@ class RenderFunction(torch.autograd.Function):
is_closed, is_closed,
use_distance_approx) use_distance_approx)
elif shape_type == diffvg.ShapeType.rect: elif shape_type == diffvg.ShapeType.rect:
p_min = args[current_index] (p_min, p_max), args = popmult(args, 2)
current_index += 1
p_max = args[current_index]
current_index += 1
shape = diffvg.Rect(diffvg.Vector2f(p_min[0], p_min[1]), shape = diffvg.Rect(diffvg.Vector2f(p_min[0], p_min[1]),
diffvg.Vector2f(p_max[0], p_max[1])) diffvg.Vector2f(p_max[0], p_max[1]))
else: else:
assert(False) assert False
stroke_width = args[current_index]
current_index += 1 stroke_width = args.pop(0)
shapes.append(diffvg.Shape(\ shapes.append(diffvg.Shape(\
shape_type, shape.get_ptr(), stroke_width.item())) shape_type, shape.get_ptr(), stroke_width.item()))
shape_contents.append(shape) shape_contents.append(shape)
for shape_group_id in range(num_shape_groups): for shape_group_id in range(num_shape_groups):
shape_ids = args[current_index] (shape_ids, fill_color_type), args = popmult(args, 2)
current_index += 1
fill_color_type = args[current_index]
current_index += 1
if fill_color_type == diffvg.ColorType.constant: if fill_color_type == diffvg.ColorType.constant:
color = args[current_index] color = args.pop(0)
current_index += 1
fill_color = diffvg.Constant(\ fill_color = diffvg.Constant(\
diffvg.Vector4f(color[0], color[1], color[2], color[3])) diffvg.Vector4f(color[0], color[1], color[2], color[3]))
elif fill_color_type == diffvg.ColorType.linear_gradient: elif fill_color_type == diffvg.ColorType.linear_gradient:
beg = args[current_index] (beg, end, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
end = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
fill_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]), fill_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]),
diffvg.Vector2f(end[0], end[1]), diffvg.Vector2f(end[0], end[1]),
offsets.shape[0], offsets.shape[0],
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif fill_color_type == diffvg.ColorType.radial_gradient: elif fill_color_type == diffvg.ColorType.radial_gradient:
center = args[current_index] (center, radius, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
radius = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
fill_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]), fill_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]),
diffvg.Vector2f(radius[0], radius[1]), diffvg.Vector2f(radius[0], radius[1]),
offsets.shape[0], offsets.shape[0],
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif fill_color_type is None: elif fill_color_type is None:
fill_color = None fill_color = None
else: else:
assert(False) assert False
stroke_color_type = args[current_index]
current_index += 1 stroke_color_type = args.pop(0)
if stroke_color_type == diffvg.ColorType.constant: if stroke_color_type == diffvg.ColorType.constant:
color = args[current_index] color = args.pop(0)
current_index += 1
stroke_color = diffvg.Constant(\ stroke_color = diffvg.Constant(\
diffvg.Vector4f(color[0], color[1], color[2], color[3])) diffvg.Vector4f(color[0], color[1], color[2], color[3]))
elif stroke_color_type == diffvg.ColorType.linear_gradient: elif stroke_color_type == diffvg.ColorType.linear_gradient:
beg = args[current_index] (beg, end, offsets, stop_colors) = popmult(args, 4)
current_index += 1
end = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
stroke_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]), stroke_color = diffvg.LinearGradient(diffvg.Vector2f(beg[0], beg[1]),
diffvg.Vector2f(end[0], end[1]), diffvg.Vector2f(end[0], end[1]),
offsets.shape[0], offsets.shape[0],
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif stroke_color_type == diffvg.ColorType.radial_gradient: elif stroke_color_type == diffvg.ColorType.radial_gradient:
center = args[current_index] (center, radius, offsets, stop_colors), args = popmult(args, 4)
current_index += 1
radius = args[current_index] assert offsets.shape[0] == stop_colors.shape[0]
current_index += 1
offsets = args[current_index]
current_index += 1
stop_colors = args[current_index]
current_index += 1
assert(offsets.shape[0] == stop_colors.shape[0])
stroke_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]), stroke_color = diffvg.RadialGradient(diffvg.Vector2f(center[0], center[1]),
diffvg.Vector2f(radius[0], radius[1]), diffvg.Vector2f(radius[0], radius[1]),
offsets.shape[0], offsets.shape[0],
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
elif stroke_color_type is None: elif stroke_color_type is None:
stroke_color = None stroke_color = None
else: else:
assert(False) assert False
use_even_odd_rule = args[current_index]
current_index += 1 (use_even_odd_rule, shape_to_canvas), args = popmult(args, 2)
shape_to_canvas = args[current_index]
current_index += 1
if fill_color is not None: if fill_color is not None:
color_contents.append(fill_color) color_contents.append(fill_color)
if stroke_color is not None: if stroke_color is not None:
color_contents.append(stroke_color) color_contents.append(stroke_color)
shape_groups.append(diffvg.ShapeGroup(\ shape_groups.append(diffvg.ShapeGroup(\
diffvg.int_ptr(shape_ids.data_ptr()), diffvg.int_ptr(shape_ids.data_ptr()),
shape_ids.shape[0], shape_ids.shape[0],
@@ -613,31 +561,32 @@ class RenderFunction(torch.autograd.Function):
use_even_odd_rule, use_even_odd_rule,
diffvg.float_ptr(shape_to_canvas.data_ptr()))) diffvg.float_ptr(shape_to_canvas.data_ptr())))
filter_type = args[current_index] (filter_type, filter_radius), args = popmult(args, 2)
current_index += 1
filter_radius = args[current_index]
current_index += 1
filt = diffvg.Filter(filter_type, filter_radius) filt = diffvg.Filter(filter_type, filter_radius)
scene = diffvg.Scene(canvas_width, canvas_height, scene = diffvg.Scene(canvas_width, canvas_height,
shapes, shape_groups, filt, pydiffvg.get_use_gpu(), shapes, shape_groups, filt, pydiffvg.get_use_gpu(),
pydiffvg.get_device().index if pydiffvg.get_device().index is not None else -1) pydiffvg.get_device().index if pydiffvg.get_device().index is not None else -1)
if output_type == OutputType.color: if output_type == OutputType.color:
assert(grad_img.shape[2] == 4) assert grad_img.shape[2] == 4
else: else:
assert(grad_img.shape[2] == 1) assert grad_img.shape[2] == 1
if background_image is not None: if background_image is not None:
background_image = background_image.to(pydiffvg.get_device()) background_image = background_image.to(pydiffvg.get_device())
if background_image.shape[2] == 3: if background_image.shape[2] == 3:
background_image = torch.cat((\ background_image = torch.cat((
background_image, torch.ones(background_image.shape[0], background_image.shape[1], 1, background_image, torch.ones(background_image.shape[0],
device = background_image.device)), dim = 2) background_image.shape[1],
1,
device=background_image.device)),
dim=2)
background_image = background_image.contiguous() background_image = background_image.contiguous()
assert(background_image.shape[0] == rendered_image.shape[0]) assert background_image.shape[0] == rendered_image.shape[0]
assert(background_image.shape[1] == rendered_image.shape[1]) assert background_image.shape[1] == rendered_image.shape[1]
assert(background_image.shape[2] == 4) assert background_image.shape[2] == 4
translation_grad_image = \ translation_grad_image = \
torch.zeros(height, width, 2, device = pydiffvg.get_device()) torch.zeros(height, width, 2, device = pydiffvg.get_device())
@@ -661,7 +610,7 @@ class RenderFunction(torch.autograd.Function):
time_elapsed = time.time() - start time_elapsed = time.time() - start
if print_timing: if print_timing:
print('Gradient pass, time: %.5f s' % time_elapsed) print('Gradient pass, time: %.5f s' % time_elapsed)
assert(torch.isfinite(translation_grad_image).all()) assert torch.isfinite(translation_grad_image).all()
return translation_grad_image return translation_grad_image
@@ -670,7 +619,7 @@ class RenderFunction(torch.autograd.Function):
grad_img): grad_img):
if not grad_img.is_contiguous(): if not grad_img.is_contiguous():
grad_img = grad_img.contiguous() grad_img = grad_img.contiguous()
assert(torch.isfinite(grad_img).all()) assert torch.isfinite(grad_img).all()
scene = ctx.scene scene = ctx.scene
width = ctx.width width = ctx.width
@@ -710,20 +659,11 @@ class RenderFunction(torch.autograd.Function):
if print_timing: if print_timing:
print('Backward pass, time: %.5f s' % time_elapsed) print('Backward pass, time: %.5f s' % time_elapsed)
d_args = [] # [width, height, num_samples_x, num_samples_y, seed,
d_args.append(None) # width # d_background_image, canvas_width, canvas_height, num_shapes,
d_args.append(None) # height # num_shape_groups, output_type, use_prefiltering, _eval_positions]
d_args.append(None) # num_samples_x d_args = [None] * 5 + [d_background_image] + [None] * 7
d_args.append(None) # num_samples_y
d_args.append(None) # seed
d_args.append(d_background_image)
d_args.append(None) # canvas_width
d_args.append(None) # canvas_height
d_args.append(None) # num_shapes
d_args.append(None) # num_shape_groups
d_args.append(None) # output_type
d_args.append(None) # use_prefiltering
d_args.append(None) # eval_positions
for shape_id in range(scene.num_shapes): for shape_id in range(scene.num_shapes):
d_args.append(None) # type d_args.append(None) # type
d_shape = scene.get_d_shape(shape_id) d_shape = scene.get_d_shape(shape_id)
@@ -731,21 +671,21 @@ class RenderFunction(torch.autograd.Function):
if d_shape.type == diffvg.ShapeType.circle: if d_shape.type == diffvg.ShapeType.circle:
d_circle = d_shape.as_circle() d_circle = d_shape.as_circle()
radius = torch.tensor(d_circle.radius) radius = torch.tensor(d_circle.radius)
assert(torch.isfinite(radius).all()) assert torch.isfinite(radius).all()
d_args.append(radius) d_args.append(radius)
c = d_circle.center c = d_circle.center
c = torch.tensor((c.x, c.y)) c = torch.tensor((c.x, c.y))
assert(torch.isfinite(c).all()) assert torch.isfinite(c).all()
d_args.append(c) d_args.append(c)
elif d_shape.type == diffvg.ShapeType.ellipse: elif d_shape.type == diffvg.ShapeType.ellipse:
d_ellipse = d_shape.as_ellipse() d_ellipse = d_shape.as_ellipse()
r = d_ellipse.radius r = d_ellipse.radius
r = torch.tensor((d_ellipse.radius.x, d_ellipse.radius.y)) r = torch.tensor((d_ellipse.radius.x, d_ellipse.radius.y))
assert(torch.isfinite(r).all()) assert torch.isfinite(r).all()
d_args.append(r) d_args.append(r)
c = d_ellipse.center c = d_ellipse.center
c = torch.tensor((c.x, c.y)) c = torch.tensor((c.x, c.y))
assert(torch.isfinite(c).all()) assert torch.isfinite(c).all()
d_args.append(c) d_args.append(c)
elif d_shape.type == diffvg.ShapeType.path: elif d_shape.type == diffvg.ShapeType.path:
d_path = d_shape.as_path() d_path = d_shape.as_path()
@@ -757,9 +697,9 @@ class RenderFunction(torch.autograd.Function):
d_path.copy_to(diffvg.float_ptr(points.data_ptr()), diffvg.float_ptr(thickness.data_ptr())) d_path.copy_to(diffvg.float_ptr(points.data_ptr()), diffvg.float_ptr(thickness.data_ptr()))
else: else:
d_path.copy_to(diffvg.float_ptr(points.data_ptr()), diffvg.float_ptr(0)) d_path.copy_to(diffvg.float_ptr(points.data_ptr()), diffvg.float_ptr(0))
assert(torch.isfinite(points).all()) assert torch.isfinite(points).all()
if thickness is not None: if thickness is not None:
assert(torch.isfinite(thickness).all()) assert torch.isfinite(thickness).all()
d_args.append(None) # num_control_points d_args.append(None) # num_control_points
d_args.append(points) d_args.append(points)
d_args.append(thickness) d_args.append(thickness)
@@ -769,17 +709,17 @@ class RenderFunction(torch.autograd.Function):
d_rect = d_shape.as_rect() d_rect = d_shape.as_rect()
p_min = torch.tensor((d_rect.p_min.x, d_rect.p_min.y)) p_min = torch.tensor((d_rect.p_min.x, d_rect.p_min.y))
p_max = torch.tensor((d_rect.p_max.x, d_rect.p_max.y)) p_max = torch.tensor((d_rect.p_max.x, d_rect.p_max.y))
assert(torch.isfinite(p_min).all()) assert torch.isfinite(p_min).all()
assert(torch.isfinite(p_max).all()) assert torch.isfinite(p_max).all()
d_args.append(p_min) d_args.append(p_min)
d_args.append(p_max) d_args.append(p_max)
else: else:
assert(False) assert False
if use_thickness: if use_thickness:
d_args.append(None) d_args.append(None)
else: else:
w = torch.tensor((d_shape.stroke_width)) w = torch.tensor((d_shape.stroke_width))
assert(torch.isfinite(w).all()) assert torch.isfinite(w).all()
d_args.append(w) d_args.append(w)
for group_id in range(scene.num_shape_groups): for group_id in range(scene.num_shape_groups):
@@ -802,7 +742,7 @@ class RenderFunction(torch.autograd.Function):
d_linear_gradient.copy_to(\ d_linear_gradient.copy_to(\
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
assert(torch.isfinite(stop_colors).all()) assert torch.isfinite(stop_colors).all()
d_args.append(offsets) d_args.append(offsets)
d_args.append(stop_colors) d_args.append(stop_colors)
elif d_shape_group.fill_color_type == diffvg.ColorType.radial_gradient: elif d_shape_group.fill_color_type == diffvg.ColorType.radial_gradient:
@@ -816,11 +756,11 @@ class RenderFunction(torch.autograd.Function):
d_radial_gradient.copy_to(\ d_radial_gradient.copy_to(\
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
assert(torch.isfinite(stop_colors).all()) assert torch.isfinite(stop_colors).all()
d_args.append(offsets) d_args.append(offsets)
d_args.append(stop_colors) d_args.append(stop_colors)
else: else:
assert(False) assert False
d_args.append(None) # stroke_color_type d_args.append(None) # stroke_color_type
if d_shape_group.has_stroke_color(): if d_shape_group.has_stroke_color():
if d_shape_group.stroke_color_type == diffvg.ColorType.constant: if d_shape_group.stroke_color_type == diffvg.ColorType.constant:
@@ -838,7 +778,7 @@ class RenderFunction(torch.autograd.Function):
d_linear_gradient.copy_to(\ d_linear_gradient.copy_to(\
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
assert(torch.isfinite(stop_colors).all()) assert torch.isfinite(stop_colors).all()
d_args.append(offsets) d_args.append(offsets)
d_args.append(stop_colors) d_args.append(stop_colors)
elif d_shape_group.fill_color_type == diffvg.ColorType.radial_gradient: elif d_shape_group.fill_color_type == diffvg.ColorType.radial_gradient:
@@ -852,15 +792,15 @@ class RenderFunction(torch.autograd.Function):
d_radial_gradient.copy_to(\ d_radial_gradient.copy_to(\
diffvg.float_ptr(offsets.data_ptr()), diffvg.float_ptr(offsets.data_ptr()),
diffvg.float_ptr(stop_colors.data_ptr())) diffvg.float_ptr(stop_colors.data_ptr()))
assert(torch.isfinite(stop_colors).all()) assert torch.isfinite(stop_colors).all()
d_args.append(offsets) d_args.append(offsets)
d_args.append(stop_colors) d_args.append(stop_colors)
else: else:
assert(False) assert False
d_args.append(None) # use_even_odd_rule d_args.append(None) # use_even_odd_rule
d_shape_to_canvas = torch.zeros((3, 3)) d_shape_to_canvas = torch.zeros((3, 3))
d_shape_group.copy_to(diffvg.float_ptr(d_shape_to_canvas.data_ptr())) d_shape_group.copy_to(diffvg.float_ptr(d_shape_to_canvas.data_ptr()))
assert(torch.isfinite(d_shape_to_canvas).all()) assert torch.isfinite(d_shape_to_canvas).all()
d_args.append(d_shape_to_canvas) d_args.append(d_shape_to_canvas)
d_args.append(None) # filter_type d_args.append(None) # filter_type
d_args.append(torch.tensor(scene.get_d_filter_radius())) d_args.append(torch.tensor(scene.get_d_filter_radius()))

View File

@@ -5,8 +5,11 @@ description = ""
authors = ["Marco Lee <marco@goodnotesapp.com>"] authors = ["Marco Lee <marco@goodnotesapp.com>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = ">=3.8,<3.11" python = ">=3.9,<3.11"
pygame = "^2.0.1" pygame = "^2.0.1"
torch = "^2.0.1"
ipython = "^8.13.2"
pytest-metadata = "^2.0.4"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
torch = "^2.0.0" torch = "^2.0.0"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB