Exemple #1
0
    def gen_and_optimize(self, writer=None, color_optimisation_activated=False):

        # Thanks to Katherine Crowson for this.
        # In the CLIPDraw code used to generate examples, we don't normalize images
        # before passing into CLIP, but really you should. Turn this to True to do that.
        use_normalized_clip = True
        pydiffvg.set_print_timing(False)
        gamma = 1.0

        # Use GPU if available
        pydiffvg.set_use_gpu(torch.cuda.is_available())
        pydiffvg.set_device(device)

        max_width = 50

        shapes, shape_groups = self.generator_func()  # self.setup_parameters(colors)

        # Just some diffvg setup
        scene_args = pydiffvg.RenderFunction.serialize_scene(
            self.canvas_width, self.canvas_height, shapes, shape_groups)
        render = pydiffvg.RenderFunction.apply
        img = render(self.canvas_width, self.canvas_height, 2, 2, 0, None, *scene_args)
        background_image = torch.ones(img.shape)

        points_vars = []

        for path in shapes:
            path.points.requires_grad = True
            points_vars.append(path.points)

        color_vars = list()
        for group in shape_groups:
            group.stroke_color.requires_grad = True
            color_vars.append(group.stroke_color)

        stroke_vars = list()
        for path in shapes:
            path.stroke_width.requires_grad = True
            stroke_vars.append(path.stroke_width)

        # Optimizers
        points_optim = torch.optim.Adam(points_vars, lr=1.0)
        color_optim = torch.optim.Adam(color_vars, lr=0.1)
        stroke_optim = torch.optim.Adam(stroke_vars, lr=0.01)

        # Run the main optimization loop
        #all_groups = sum([g.param_groups for g in [points_optim, color_optim, stroke_optim]], [])
        for t in range(self.num_iter):
            # Anneal learning rate (makes videos look cleaner)
            if t == int(self.num_iter * 0.5):
                print(f"Iter {t}")
                for g in points_optim.param_groups:
                    g['lr'] *= 0.5
            if t == int(self.num_iter * 0.75):
                print(f"Iter {t}")
                for g in points_optim.param_groups:
                    g['lr'] *= 0.5

            points_optim.zero_grad()
            if color_optimisation_activated:
                color_optim.zero_grad()
                stroke_optim.zero_grad()

            img = self.gen_image_from_curves(t, shapes, shape_groups, gamma, background_image)
            im_batch = self.data_augment(img, self.n_augms, use_normalized_clip)
            loss = self.forward_model_func(im_batch)

            # Back-propagate the gradients.
            loss.backward()

            # Take a gradient descent step.
            points_optim.step()
            if color_optimisation_activated:
                color_optim.step()
                stroke_optim.step()

            for path in shapes:
                path.stroke_width.data.clamp_(1.0, max_width)
            for group in shape_groups:
                group.stroke_color.data.clamp_(0.0, 1.0)

            if t % int(self.num_iter / 10) == 0 and writer is not None:
                writer.add_scalars("neuron_excitation", {"loss": loss}, t)
                writer.add_image('Rendering', img[0], t)

        return shapes, shape_groups
Exemple #2
0
# python finite_difference_comp.py --size_scale 0.5 --clamping_factor 0.05 imgs/hawaii.svg &&
# python finite_difference_comp.py --size_scale 0.5 --clamping_factor 0.05 --use_prefiltering True imgs/hawaii.svg &&
# python finite_difference_comp.py imgs/mcseem2.svg &&
# python finite_difference_comp.py --use_prefiltering True imgs/mcseem2.svg &&
# python finite_difference_comp.py imgs/reschart.svg &&
# python finite_difference_comp.py --use_prefiltering True imgs/reschart.svg

import argparse

import diffvg
# import matplotlib.pyplot as plt
import pydiffvg
import torch
from matplotlib import cm

pydiffvg.set_print_timing(True)
# pydiffvg.set_use_gpu(False)


def normalize(x, min_, max_):
    range = max(abs(min_), abs(max_))
    return (x + range) / (2 * range)


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)
Exemple #3
0
def main(args):
    if args.seed:
        np.random.seed(args.seed)
        random.seed(args.seed)
        torch.manual_seed(args.seed)

    pydiffvg.set_print_timing(False)

    outdir = os.path.join(args.results_dir, args.prompt, args.subdir)

    # Use GPU if available
    pydiffvg.set_use_gpu(torch.cuda.is_available())

    canvas_width, canvas_height = 224, 224
    margin = args.initial_margin
    total_paths = args.open_paths + args.closed_paths
    step = min(args.step, total_paths)
    if step == 0:
        step = total_paths

    fill_color = None
    stroke_color = None
    shapes = []
    shape_groups = []
    losses = []
    tt = 0
    for num_paths in range(step, total_paths + 1, step):
        for i in range(num_paths - step, num_paths):
            num_segments = random.randint(1, args.extra_segments + 1)
            p0 = (margin + random.random() * (1 - 2 * margin),
                  margin + random.random() * (1 - 2 * margin))
            points = [p0]
            is_closed = i >= args.open_paths
            if is_closed:
                num_segments += 2
            for j in range(num_segments):
                p1 = (p0[0] + radius * (random.random() - 0.5),
                      p0[1] + radius * (random.random() - 0.5))
                p2 = (p1[0] + radius * (random.random() - 0.5),
                      p1[1] + radius * (random.random() - 0.5))
                p3 = (p2[0] + radius * (random.random() - 0.5),
                      p2[1] + radius * (random.random() - 0.5))
                points.append(p1)
                points.append(p2)
                if is_closed and j < num_segments - 1 or not is_closed:
                    points.append(p3)
                    p0 = p3
            points = torch.tensor(points)
            points[:, 0] *= canvas_width
            points[:, 1] *= canvas_height
            stroke_width = torch.tensor(1.0)
            color = torch.tensor([
                random.random(),
                random.random(),
                random.random(),
                random.random()
            ])
            num_control_points = torch.zeros(num_segments,
                                             dtype=torch.int32) + 2
            path = pydiffvg.Path(num_control_points=num_control_points,
                                 points=points,
                                 stroke_width=stroke_width,
                                 is_closed=is_closed)
            shapes.append(path)
            path_group = pydiffvg.ShapeGroup(
                shape_ids=torch.tensor([len(shapes) - 1]),
                fill_color=color if is_closed else None,
                stroke_color=None if is_closed else color)
            shape_groups.append(path_group)

        scene_args = pydiffvg.RenderFunction.serialize_scene(\
            canvas_width, canvas_height, shapes, shape_groups)

        render = pydiffvg.RenderFunction.apply
        img = render(
            canvas_width,  # width
            canvas_height,  # height
            2,  # num_samples_x
            2,  # num_samples_y
            0,  # seed
            None,
            *scene_args)

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            pydiffvg.imwrite(img.cpu(),
                             os.path.join(outdir, 'init.png'),
                             gamma=gamma)

        points_vars = []
        stroke_width_vars = []
        color_vars = []
        for path in shapes:
            path.points.requires_grad = True
            points_vars.append(path.points)
            if not path.is_closed and args.max_width > 1:
                path.stroke_width.requires_grad = True
                stroke_width_vars.append(path.stroke_width)
        for group in shape_groups:
            if group.fill_color is not None:
                group.fill_color.requires_grad = True
                color_vars.append(group.fill_color)
            else:
                group.stroke_color.requires_grad = True
                color_vars.append(group.stroke_color)

        # Embed prompt
        text_features = clip_utils.embed_text(args.prompt)

        # Optimize
        points_optim = torch.optim.Adam(points_vars, lr=args.points_lr)
        if len(stroke_width_vars) > 0:
            width_optim = torch.optim.Adam(stroke_width_vars, lr=args.width_lr)
        color_optim = torch.optim.Adam(color_vars, lr=args.color_lr)
        # Adam iterations.
        final = False
        this_step_iters = max(1, round(args.num_iter * step / total_paths))
        if num_paths + step > total_paths:
            final = True
            this_step_iters += args.extra_iter
        for t in range(this_step_iters):
            points_optim.zero_grad()
            if len(stroke_width_vars) > 0:
                width_optim.zero_grad()
            color_optim.zero_grad()
            # Forward pass: render the image.
            scene_args = pydiffvg.RenderFunction.serialize_scene(\
                canvas_width, canvas_height, shapes, shape_groups)
            img = render(
                canvas_width,  # width
                canvas_height,  # height
                2,  # num_samples_x
                2,  # num_samples_y
                tt,  # seed
                None,
                *scene_args)
            # Save the intermediate render.
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                pydiffvg.imwrite(img.cpu(),
                                 os.path.join(outdir,
                                              'iter_{}.png'.format(tt)),
                                 gamma=gamma)
            image_features = clip_utils.embed_image(img)
            loss = -torch.cosine_similarity(
                text_features, image_features, dim=-1).mean()

            # Backpropagate the gradients.
            loss.backward()
            losses.append(loss.item())

            # Take a gradient descent step.
            points_optim.step()
            if len(stroke_width_vars) > 0:
                width_optim.step()
            color_optim.step()

            for path in shapes:
                path.points.data[:, 0].clamp_(0.0, canvas_width)
                path.points.data[:, 1].clamp_(0.0, canvas_height)
                if not path.is_closed:
                    path.stroke_width.data.clamp_(1.0, args.max_width)
            for group in shape_groups:
                if group.fill_color is not None:
                    group.fill_color.data[:3].clamp_(0.0, 1.0)
                    group.fill_color.data[3].clamp_(args.min_alpha, 1.0)
                else:
                    group.stroke_color.data[:3].clamp_(0.0, 1.0)
                    group.stroke_color.data[3].clamp_(args.min_alpha, 1.0)

            if tt % 10 == 0 or final and t == this_step_iters - 1:
                print('%d loss=%.3f' % (tt, 1 + losses[-1]))
                pydiffvg.save_svg(
                    os.path.join(outdir, 'iter_{}.svg'.format(tt)),
                    canvas_width, canvas_height, shapes, shape_groups)
                clip_utils.plot_losses(losses, outdir)
            tt += 1

    # Render the final result.
    img = render(
        args.final_px,  # width
        args.final_px,  # height
        2,  # num_samples_x
        2,  # num_samples_y
        0,  # seed
        None,
        *scene_args)
    # Save the intermediate render
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        pydiffvg.imwrite(img.cpu(),
                         os.path.join(outdir, 'final.png'),
                         gamma=gamma)
    # Convert the intermediate renderings to a video with a white background.
    from subprocess import call
    call([
        "ffmpeg", "-framerate", "24", "-i",
        os.path.join(outdir, "iter_%d.png"), "-vb", "20M", "-filter_complex",
        "color=white,format=rgb24[c];[c][0]scale2ref[c][i];[c][i]overlay=format=auto:shortest=1,setsar=1",
        "-c:v", "libx264", "-pix_fmt", "yuv420p", "-profile:v", "baseline",
        "-movflags", "+faststart",
        os.path.join(outdir, "out.mp4")
    ])