import sys sys.path.append("../svg") from geometry import GeometryLoss import numpy as np import pygame as pg import torch import pydiffvg import tkinter as tk from tkinter import filedialog def box_kernel(val): return np.heaviside(-val+1,0) def cone_kernel(val): return np.maximum(0,1-val) def nptosurf(arr): if arr.shape[2]==1: #greyscale shape=arr.shape shape=(shape[0],shape[1],3) arr=np.broadcast_to(arr,shape) return pg.surfarray.make_surface(arr*255) def brush_tensor(screen_size,coords,radius,kernel): coordarr=np.stack(np.meshgrid(np.linspace(0,screen_size[0]-1,screen_size[0]),np.linspace(0,screen_size[1]-1,screen_size[1]),indexing='ij'),axis=2) ctrarr = np.reshape(np.array(coords), [1, 1, 2]) distarr=np.sqrt(np.sum(np.power(coordarr-ctrarr,2),axis=2)) valarr=kernel(distarr/radius) return torch.tensor(valarr,requires_grad=False,dtype=torch.float32) def checkerboard(shape, square_size=2): xv,yv=np.meshgrid(np.floor(np.linspace(0,shape[1]-1,shape[1])/square_size),np.floor(np.linspace(0,shape[0]-1,shape[0])/square_size)) bin=np.expand_dims(((xv+yv)%2),axis=2) res=bin*np.array([[[1., 1., 1.,]]])+(1-bin)*np.array([[[.75, .75, .75,]]]) return torch.tensor(res,requires_grad=False,dtype=torch.float32) def render(optim, viewport): scene_args = pydiffvg.RenderFunction.serialize_scene(*optim.build_scene()) render = pydiffvg.RenderFunction.apply img = render(viewport[0], # width viewport[1], # height 2, # num_samples_x 2, # num_samples_y 0, # seed None, *scene_args) return img def optimize(optim, viewport, brush_kernel, increase=True, strength=0.1): optim.zero_grad() geomLoss=torch.tensor(0.) for shape, gloss in zip(optim.scene[2],geometryLosses): geomLoss+=gloss.compute(shape) img=render(optim,viewport) imalpha=img[:,:,3] multiplied=imalpha*brush_kernel loss=((1-multiplied).mean() if increase else multiplied.mean())*strength loss+=geomLoss loss.backward() optim.step() return render(optim,viewport) def get_infile(): pydiffvg.set_use_gpu(False) root = tk.Tk() #root.withdraw() file_path = filedialog.askopenfilename(initialdir = ".",title = "Select graphic to optimize",filetypes = (("SVG files","*.svg"),("all files","*.*"))) root.destroy() return file_path def compositebg(img): bg=checkerboard(img.shape,2) color=img[:,:,0:3] alpha=img[:,:,3] composite=alpha.unsqueeze(2)*color+(1-alpha).unsqueeze(2)*bg return composite def main(): infile=get_infile() settings=pydiffvg.SvgOptimizationSettings() settings.global_override(["optimize_color"],False) settings.global_override(["transforms","optimize_transforms"], False) settings.global_override(["optimizer"], "SGD") settings.global_override(["paths","shape_lr"], 1e-1) optim=pydiffvg.OptimizableSvg(infile,settings) global geometryLosses geometryLosses = [] for shape in optim.build_scene()[2]: geometryLosses.append(GeometryLoss(shape)) scaling=1 brush_radius=100 graphic_size=optim.canvas screen_size=(graphic_size[1]*scaling, graphic_size[0]*scaling) pg.init() screen=pg.display.set_mode(screen_size) screen.fill((255,255,255)) img=render(optim,graphic_size) print(img.max()) npsurf = pg.transform.scale(nptosurf(compositebg(img).detach().permute(1,0,2).numpy()), screen_size) screen.blit(npsurf,(0,0)) pg.display.update() clock=pg.time.Clock() z=0 btn=0 while True: clock.tick(60) for event in pg.event.get(): if event.type==pg.QUIT: pg.quit() sys.exit() y, x = pg.mouse.get_pos() if event.type == pg.MOUSEBUTTONDOWN: if event.button in [1,3]: z=1 btn=event.button elif event.button == 4: brush_radius*=1.1 elif event.button == 5: brush_radius/=1.1 brush_radius=max(brush_radius,5) elif event.type == pg.MOUSEBUTTONUP: if event.button in [1,3]: z=0 if z==1: brush=brush_tensor((graphic_size[0],graphic_size[1]), (x/scaling, y/scaling), brush_radius, box_kernel) img=optimize(optim,graphic_size,brush,btn==1) npsurf = pg.transform.scale(nptosurf(compositebg(img).detach().permute(1,0,2).numpy()), screen_size) screen.blit(npsurf,(0,0)) pg.draw.circle(screen, (255,255,255), (y,x), int(brush_radius*scaling), 1) pg.display.update() if __name__ == '__main__': main()