Beispiel #1
0
def chenschmidt(alg, content, style, outfile, size, stylescale, algparams):
    """Runs Chen and Schmidt fast style-transfer algorithm

    References:
        * https://arxiv.org/pdf/1612.04337.pdf
        * https://github.com/rtqichen/style-swap
    """
    if alg not in ["chen-schmidt", "chen-schmidt-inverse"]:
        raise ValueError(
            "Unnaceptable subalgorithm %s for Chen-Schmidt family")

    # Rescale style as requested
    instyle = NamedTemporaryFile()
    copyfile(style, instyle.name)
    resize(instyle.name, int(stylescale * shape(style)[0]))
    # Run algorithm
    outdir = TemporaryDirectory()
    runalgorithm(alg, [
        "--save", outdir.name, "--content", content, "--style", instyle.name,
        "--maxContentSize", size if size is not None else shape(content)[0],
        "--maxStyleSize", size if size is not None else shape(content)[0],
        *algparams
    ])
    # Gather output results
    output = outdir.name + "/" + filename(content) + "_stylized" + fileext(
        content)
    convert(output, outfile)
    instyle.close()
Beispiel #2
0
def gatys(content, style, outfile, size, weight, stylescale, algparams):
    """Runs Gatys et al style-transfer algorithm

    References:
        * https://arxiv.org/abs/1508.06576
        * https://github.com/jcjohnson/neural-style
    """
    # Gatys can only process one combination of content, style, weight and scale at a time, so we need to iterate
    tmpout = NamedTemporaryFile(suffix=".png")
    runalgorithm(
        "gatys",
        [
            "-content_image",
            content,
            "-style_image",
            style,
            "-style_weight",
            weight * 100,  # Because content weight is 100
            "-style_scale",
            stylescale,
            "-output_image",
            tmpout.name,
            "-image_size",
            size if size is not None else shape(content)[0],
            *algparams
        ])
    # Transform to original file format
    convert(tmpout.name, outfile)
    tmpout.close()
def test_convert_nolayers():
    """Convert a single image with no layers works as expected"""
    for content in [CONTENTS + f for f in ["docker.png", "goldengate.jpg"]]:
        for ext in [".png", ".jpg", ".psd", ".tga"]:
            tmpdir = TemporaryDirectory()
            outname = tmpdir.name + "/" + "output" + ext
            convert(content, outname)
            assert len(glob(tmpdir.name + "/" + filename(outname) + ext)) == 1
            assert shape(outname) == shape(content)
Beispiel #4
0
def styletransfer_single(content,
                         style,
                         outfile,
                         size=None,
                         alg="gatys",
                         weight=5.0,
                         stylescale=1.0,
                         algparams=None):
    """General style transfer routine over a single set of options"""
    workdir = TemporaryDirectory()

    # Cut out alpha channel from content
    rgbfile = workdir.name + "/" + "rgb.png"
    alphafile = workdir.name + "/" + "alpha.png"
    extractalpha(content, rgbfile, alphafile)

    # Transform style to png, as some algorithms don't understand other formats
    stylepng = workdir.name + "/" + "style.png"
    convert(style, stylepng)

    # Call style transfer algorithm
    algfile = workdir.name + "/" + "algoutput.png"
    if alg == "gatys":
        gatys(rgbfile, stylepng, algfile, size, weight, stylescale, algparams)
    elif alg == "gatys-multiresolution":
        gatys_multiresolution(rgbfile, stylepng, algfile, size, weight,
                              stylescale, algparams)
    elif alg in ["chen-schmidt", "chen-schmidt-inverse"]:
        chenschmidt(alg, rgbfile, stylepng, algfile, size, stylescale,
                    algparams)
    # Enforce correct size
    correctshape(algfile, content, size)

    # Recover alpha channel
    correctshape(alphafile, content, size)
    mergealpha(algfile, alphafile, outfile)
Beispiel #5
0
def gatys_multiresolution(content,
                          style,
                          outfile,
                          size,
                          weight,
                          stylescale,
                          algparams,
                          startres=256):
    """Runs a multiresolution version of Gatys et al method

    The multiresolution strategy starts by generating a small image, then using that image as initializer
    for higher resolution images. This procedure is repeated up to the tilesize.

    Once the maximum tile size attainable by L-BFGS is reached, more iterations are run by using Adam. This allows
    to produce larger images using this method than the basic Gatys.

    References:
        * Gatys et al - Controlling Perceptual Factors in Neural Style Transfer (https://arxiv.org/abs/1611.07865)
        * https://gist.github.com/jcjohnson/ca1f29057a187bc7721a3a8c418cc7db
    """
    # Multiresolution strategy: list of rounds, each round composed of a optimization method and a number of
    # upresolution steps.
    # Using "adam" as optimizer means that Adam will be used when necessary to attain higher resolutions
    strategy = [["lbfgs", 7], ["lbfgs", 7], ["lbfgs", 7], ["lbfgs", 7],
                ["lbfgs", 7]]
    LOGGER.info("Starting gatys-multiresolution with strategy " +
                str(strategy))

    # Initialization
    workdir = TemporaryDirectory()
    maxres = targetshape(content, size)[0]
    if maxres < startres:
        LOGGER.warning(
            "Target resolution (%d) might too small for the multiresolution method to work well"
            % maxres)
        startres = maxres / 2.0
    seed = None
    tmpout = workdir.name + "/tmpout.png"

    # Iterate over rounds
    for roundnumber, (optimizer, steps) in enumerate(strategy):
        LOGGER.info(
            "gatys-multiresolution round %d with %s optimizer and %d steps" %
            (roundnumber, optimizer, steps))
        roundmax = min(maxtile("gatys"),
                       maxres) if optimizer == "lbfgs" else maxres
        resolutions = np.linspace(startres, roundmax, steps, dtype=int)
        iters = 1000
        for stepnumber, res in enumerate(resolutions):
            stepopt = "adam" if res > maxtile("gatys") else "lbfgs"
            LOGGER.info("Step %d, resolution %d, optimizer %s" %
                        (stepnumber, res, stepopt))
            passparams = algparams[:]
            passparams.extend([
                "-num_iterations", iters, "-tv_weight", "0", "-print_iter",
                "0", "-optimizer", stepopt
            ])
            if seed is not None:
                passparams.extend(["-init", "image", "-init_image", seed])
            gatys(content, style, tmpout, res, weight, stylescale, passparams)
            seed = workdir.name + "/seed.png"
            copyfile(tmpout, seed)
            iters = max(iters / 2.0, 100)

    convert(tmpout, outfile)
Beispiel #6
0
def neuraltile(content,
               style,
               outfile,
               size=None,
               overlap=100,
               alg="gatys",
               weight=5.0,
               stylescale=1.0,
               algparams=None):
    """Strategy to generate a high resolution image by running style transfer on overlapping image tiles"""
    LOGGER.info("Starting tiling strategy")
    if algparams is None:
        algparams = []
    workdir = TemporaryDirectory()

    # Gather size info from original image
    fullshape = targetshape(content, size)

    # Compute number of tiles required to map all the image
    xtiles, ytiles = tilegeometry(fullshape, alg, overlap)

    # First scale image to target resolution
    firstpass = workdir.name + "/" + "lowres.png"
    convert(content, firstpass)
    resize(firstpass, fullshape)

    # Chop the styled image into tiles with the specified overlap value.
    lowrestiles = choptiles(firstpass,
                            xtiles=xtiles,
                            ytiles=ytiles,
                            overlap=overlap,
                            outname=workdir.name + "/" + "lowres_tiles")

    # High resolution pass over each tile
    highrestiles = []
    for i, tile in enumerate(lowrestiles):
        name = workdir.name + "/" + "highres_tiles_" + str(i) + ".png"
        styletransfer_single(tile,
                             style,
                             name,
                             size=None,
                             alg=alg,
                             weight=weight,
                             stylescale=stylescale,
                             algparams=algparams)
        highrestiles.append(name)

    # Feather tiles
    featheredtiles = []
    for i, tile in enumerate(highrestiles):
        name = workdir.name + "/" + "feathered_tiles_" + str(i) + ".png"
        feather(tile, name)
        featheredtiles.append(name)

    # Smush the feathered tiles together
    smushedfeathered = workdir.name + "/" + "feathered_smushed.png"
    smush(featheredtiles, xtiles, ytiles, overlap, overlap, smushedfeathered)

    # Smush also the non-feathered tiles
    smushedhighres = workdir.name + "/" + "highres_smushed.png"
    smush(highrestiles, xtiles, ytiles, overlap, overlap, smushedhighres)

    # Combine feathered and un-feathered output images to disguise feathering
    composite([smushedfeathered, smushedhighres], outfile)

    # Adjust back to desired size
    assertshape(outfile, fullshape)