def main(args): canvas_width, canvas_height, shapes, shape_groups = \ pydiffvg.svg_to_scene(args.svg_file) w = int(canvas_width * args.size_scale) h = int(canvas_height * args.size_scale) pfilter = pydiffvg.PixelFilter(type=diffvg.FilterType.box, radius=torch.tensor(0.5)) use_prefiltering = False scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) num_samples_x = 16 num_samples_y = 16 render = pydiffvg.RenderFunction.apply img = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, *scene_args) pydiffvg.imwrite(img.cpu(), 'results/finite_difference_comp/img.png', gamma=1.0) epsilon = 0.1 def perturb_scene(axis, epsilon): shapes[2].points[:, axis] += epsilon # for s in shapes: # if isinstance(s, pydiffvg.Circle): # s.center[axis] += epsilon # elif isinstance(s, pydiffvg.Ellipse): # s.center[axis] += epsilon # elif isinstance(s, pydiffvg.Path): # s.points[:, axis] += epsilon # elif isinstance(s, pydiffvg.Polygon): # s.points[:, axis] += epsilon # elif isinstance(s, pydiffvg.Rect): # s.p_min[axis] += epsilon # s.p_max[axis] += epsilon # for s in shape_groups: # if isinstance(s.fill_color, pydiffvg.LinearGradient): # s.fill_color.begin[axis] += epsilon # s.fill_color.end[axis] += epsilon perturb_scene(0, epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) render = pydiffvg.RenderFunction.apply img0 = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, *scene_args) forward_diff = (img0 - img) / (epsilon) forward_diff = forward_diff.sum(axis=2) x_diff_max = 1.5 x_diff_min = -1.5 print(forward_diff.max()) print(forward_diff.min()) forward_diff = cm.viridis( normalize(forward_diff, x_diff_min, x_diff_max).cpu().numpy()) pydiffvg.imwrite( forward_diff, 'results/finite_difference_comp/shared_edge_forward_diff.png', gamma=1.0) perturb_scene(0, -2 * epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) img1 = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, *scene_args) backward_diff = (img - img1) / (epsilon) backward_diff = backward_diff.sum(axis=2) print(backward_diff.max()) print(backward_diff.min()) backward_diff = cm.viridis( normalize(backward_diff, x_diff_min, x_diff_max).cpu().numpy()) pydiffvg.imwrite( backward_diff, 'results/finite_difference_comp/shared_edge_backward_diff.png', gamma=1.0) perturb_scene(0, epsilon) num_samples_x = 4 num_samples_y = 4 scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) render_grad = pydiffvg.RenderFunction.render_grad img_grad = render_grad( torch.ones(h, w, 4), w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed *scene_args) print(img_grad[:, :, 0].max()) print(img_grad[:, :, 0].min()) x_diff = cm.viridis( normalize(img_grad[:, :, 0], x_diff_min, x_diff_max).cpu().numpy()) pydiffvg.imwrite(x_diff, 'results/finite_difference_comp/ours_x_diff.png', gamma=1.0)
def serialize_scene(canvas_width, canvas_height, shapes, shape_groups, filter=pydiffvg.PixelFilter(type=diffvg.FilterType.box, radius=torch.tensor(0.5)), output_type=OutputType.color, use_prefiltering=False, eval_positions=torch.tensor([])): """ Given a list of shapes, convert them to a linear list of argument, so that we can use it in PyTorch. """ num_shapes = len(shapes) num_shape_groups = len(shape_groups) args = [] args.append(canvas_width) args.append(canvas_height) args.append(num_shapes) args.append(num_shape_groups) args.append(output_type) args.append(use_prefiltering) args.append(eval_positions.to(pydiffvg.get_device())) for shape in shapes: use_thickness = False if isinstance(shape, pydiffvg.Circle): assert(shape.center.is_contiguous()) args.append(diffvg.ShapeType.circle) args.append(shape.radius.cpu()) args.append(shape.center.cpu()) elif isinstance(shape, pydiffvg.Ellipse): assert(shape.radius.is_contiguous()) assert(shape.center.is_contiguous()) args.append(diffvg.ShapeType.ellipse) args.append(shape.radius.cpu()) args.append(shape.center.cpu()) elif isinstance(shape, pydiffvg.Path): assert(shape.num_control_points.is_contiguous()) assert(shape.points.is_contiguous()) assert(shape.points.shape[1] == 2) assert(torch.isfinite(shape.points).all()) args.append(diffvg.ShapeType.path) args.append(shape.num_control_points.to(torch.int32).cpu()) args.append(shape.points.cpu()) if len(shape.stroke_width.shape) > 0 and shape.stroke_width.shape[0] > 1: assert(torch.isfinite(shape.stroke_width).all()) use_thickness = True args.append(shape.stroke_width.cpu()) else: args.append(None) args.append(shape.is_closed) args.append(shape.use_distance_approx) elif isinstance(shape, pydiffvg.Polygon): assert(shape.points.is_contiguous()) assert(shape.points.shape[1] == 2) args.append(diffvg.ShapeType.path) if shape.is_closed: args.append(torch.zeros(shape.points.shape[0], dtype=torch.int32)) else: args.append(torch.zeros(shape.points.shape[0] - 1, dtype=torch.int32)) args.append(shape.points.cpu()) args.append(None) args.append(shape.is_closed) args.append(False) # use_distance_approx elif isinstance(shape, pydiffvg.Rect): assert(shape.p_min.is_contiguous()) assert(shape.p_max.is_contiguous()) args.append(diffvg.ShapeType.rect) args.append(shape.p_min.cpu()) args.append(shape.p_max.cpu()) else: assert(False) if use_thickness: args.append(torch.tensor(0.0)) else: args.append(shape.stroke_width.cpu()) for shape_group in shape_groups: assert(shape_group.shape_ids.is_contiguous()) args.append(shape_group.shape_ids.to(torch.int32).cpu()) # Fill color if shape_group.fill_color is None: args.append(None) elif isinstance(shape_group.fill_color, torch.Tensor): assert(shape_group.fill_color.is_contiguous()) args.append(diffvg.ColorType.constant) args.append(shape_group.fill_color.cpu()) elif isinstance(shape_group.fill_color, pydiffvg.LinearGradient): assert(shape_group.fill_color.begin.is_contiguous()) assert(shape_group.fill_color.end.is_contiguous()) assert(shape_group.fill_color.offsets.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.append(shape_group.fill_color.end.cpu()) args.append(shape_group.fill_color.offsets.cpu()) args.append(shape_group.fill_color.stop_colors.cpu()) elif isinstance(shape_group.fill_color, pydiffvg.RadialGradient): assert(shape_group.fill_color.center.is_contiguous()) assert(shape_group.fill_color.radius.is_contiguous()) assert(shape_group.fill_color.offsets.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.append(shape_group.fill_color.radius.cpu()) args.append(shape_group.fill_color.offsets.cpu()) args.append(shape_group.fill_color.stop_colors.cpu()) if shape_group.fill_color is not None: # go through the underlying shapes and check if they are all closed for shape_id in shape_group.shape_ids: if isinstance(shapes[shape_id], pydiffvg.Path): if not shapes[shape_id].is_closed: warnings.warn("Detected non-closed paths with fill color. This might causes unexpected results.", Warning) # Stroke color if shape_group.stroke_color is None: args.append(None) elif isinstance(shape_group.stroke_color, torch.Tensor): assert(shape_group.stroke_color.is_contiguous()) args.append(diffvg.ColorType.constant) args.append(shape_group.stroke_color.cpu()) elif isinstance(shape_group.stroke_color, pydiffvg.LinearGradient): assert(shape_group.stroke_color.begin.is_contiguous()) assert(shape_group.stroke_color.end.is_contiguous()) assert(shape_group.stroke_color.offsets.is_contiguous()) assert(shape_group.stroke_color.stop_colors.is_contiguous()) 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.append(shape_group.stroke_color.end.cpu()) args.append(shape_group.stroke_color.offsets.cpu()) args.append(shape_group.stroke_color.stop_colors.cpu()) elif isinstance(shape_group.stroke_color, pydiffvg.RadialGradient): assert(shape_group.stroke_color.center.is_contiguous()) assert(shape_group.stroke_color.radius.is_contiguous()) assert(shape_group.stroke_color.offsets.is_contiguous()) assert(shape_group.stroke_color.stop_colors.is_contiguous()) 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.append(shape_group.stroke_color.radius.cpu()) args.append(shape_group.stroke_color.offsets.cpu()) args.append(shape_group.stroke_color.stop_colors.cpu()) args.append(shape_group.use_even_odd_rule) # Transformation args.append(shape_group.shape_to_canvas.contiguous().cpu()) args.append(filter.type) args.append(filter.radius.cpu()) return args
def main(args): case_name = args.svg_file.split('/')[-1].split('.')[0] canvas_width, canvas_height, shapes, shape_groups = \ pydiffvg.svg_to_scene(args.svg_file) w = int(canvas_width * args.size_scale) h = int(canvas_height * args.size_scale) print(w, h) curve_counts = 0 for s in shapes: if isinstance(s, pydiffvg.Circle): curve_counts += 1 elif isinstance(s, pydiffvg.Ellipse): curve_counts += 1 elif isinstance(s, pydiffvg.Path): curve_counts += len(s.num_control_points) elif isinstance(s, pydiffvg.Polygon): curve_counts += len(s.points) - 1 if s.is_closed: curve_counts += 1 elif isinstance(s, pydiffvg.Rect): curve_counts += 1 print('curve_counts:', curve_counts) pfilter = pydiffvg.PixelFilter(type=diffvg.FilterType.box, radius=torch.tensor(0.5)) use_prefiltering = args.use_prefiltering print('use_prefiltering:', use_prefiltering) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) num_samples_x = args.num_spp num_samples_y = args.num_spp if (use_prefiltering): num_samples_x = 1 num_samples_y = 1 render = pydiffvg.RenderFunction.apply img = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, # background_image *scene_args) pydiffvg.imwrite( img.cpu(), f'results/finite_difference_comp/{case_name}_{use_prefiltering}/img.png', gamma=1.0) epsilon = 0.1 def perturb_scene(axis, epsilon): for s in shapes: if isinstance(s, pydiffvg.Circle): s.center[axis] += epsilon elif isinstance(s, pydiffvg.Ellipse): s.center[axis] += epsilon elif isinstance(s, pydiffvg.Path): s.points[:, axis] += epsilon elif isinstance(s, pydiffvg.Polygon): s.points[:, axis] += epsilon elif isinstance(s, pydiffvg.Rect): s.p_min[axis] += epsilon s.p_max[axis] += epsilon for s in shape_groups: if isinstance(s.fill_color, pydiffvg.LinearGradient): s.fill_color.begin[axis] += epsilon s.fill_color.end[axis] += epsilon perturb_scene(0, epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) render = pydiffvg.RenderFunction.apply img0 = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, # background_image *scene_args) perturb_scene(0, -2 * epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) img1 = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, # background_image *scene_args) x_diff = (img0 - img1) / (2 * epsilon) x_diff = x_diff.sum(axis=2) x_diff_max = x_diff.max() * args.clamping_factor x_diff_min = x_diff.min() * args.clamping_factor print(x_diff.max()) print(x_diff.min()) x_diff = cm.viridis( normalize(x_diff, x_diff_min, x_diff_max).cpu().numpy()) pydiffvg.imwrite( x_diff, f'results/finite_difference_comp//{case_name}_{use_prefiltering}/finite_x_diff.png', gamma=1.0) perturb_scene(0, epsilon) perturb_scene(1, epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) render = pydiffvg.RenderFunction.apply img0 = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, # background_image *scene_args) perturb_scene(1, -2 * epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) img1 = render( w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, # background_image *scene_args) y_diff = (img0 - img1) / (2 * epsilon) y_diff = y_diff.sum(axis=2) y_diff_max = y_diff.max() * args.clamping_factor y_diff_min = y_diff.min() * args.clamping_factor y_diff = cm.viridis( normalize(y_diff, y_diff_min, y_diff_max).cpu().numpy()) pydiffvg.imwrite( y_diff, f'results/finite_difference_comp/{case_name}_{use_prefiltering}/finite_y_diff.png', gamma=1.0) perturb_scene(1, epsilon) scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width, canvas_height, shapes, shape_groups, filter=pfilter, use_prefiltering=use_prefiltering) render_grad = pydiffvg.RenderFunction.render_grad img_grad = render_grad( torch.ones(h, w, 4, device=pydiffvg.get_device()), w, # width h, # height num_samples_x, # num_samples_x num_samples_y, # num_samples_y 0, # seed None, # background_image *scene_args) print(img_grad[:, :, 0].max()) print(img_grad[:, :, 0].min()) x_diff = cm.viridis( normalize(img_grad[:, :, 0], x_diff_min, x_diff_max).cpu().numpy()) y_diff = cm.viridis( normalize(img_grad[:, :, 1], y_diff_min, y_diff_max).cpu().numpy()) pydiffvg.imwrite( x_diff, f'results/finite_difference_comp/{case_name}_{use_prefiltering}/ours_x_diff.png', gamma=1.0) pydiffvg.imwrite( y_diff, f'results/finite_difference_comp/{case_name}_{use_prefiltering}/ours_y_diff.png', gamma=1.0)
canvas_width = 256 canvas_height = 256 circle = pydiffvg.Circle(radius=torch.tensor(40.0), center=torch.tensor([128.0, 128.0])) shapes = [circle] circle_group = pydiffvg.ShapeGroup(shape_ids=torch.tensor([0]), fill_color=torch.tensor( [0.3, 0.6, 0.3, 1.0])) shape_groups = [circle_group] scene_args = pydiffvg.RenderFunction.serialize_scene( canvas_width=canvas_width, canvas_height=canvas_height, shapes=shapes, shape_groups=shape_groups, filter=pydiffvg.PixelFilter(type=diffvg.FilterType.hann, radius=torch.tensor(8.0))) render = pydiffvg.RenderFunction.apply img = render( 256, # width 256, # height 2, # num_samples_x 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/optimize_pixel_filter/target.png', gamma=2.2) target = img.clone()