14个版本

0.8.3 2022年2月7日
0.8.2 2021年3月26日
0.8.1 2020年11月17日
0.8.0 2020年2月26日
0.7.1 2019年11月19日

#130图像

Download history 3/week @ 2024-03-14 24/week @ 2024-03-28 17/week @ 2024-04-04

每月162次 下载

MIT/Apache

140KB
3K SLoC

🎨 texture-synthesis

Embark Embark Crates.io Docs dependency status Build Status

A light Rust API for Multiresolution Stochastic Texture Synthesis [1], a non-parametric example-based algorithm for image generation.

The repo also includes multiple code examples to get you started (along with test images), and you can find a compiled binary with a command line interface under the release tab.

Also see our talk More Like This, Please! Texture Synthesis and Remixing from a Single Example which explains this technique and the background more in-depth

Video thumbnail

功能和示例

1. 单个示例生成

Imgur

从单个示例生成相似外观的图像。

API - 01_single_example_synthesis

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    //create a new session
    let texsynth = ts::Session::builder()
        //load a single example image
        .add_example(&"imgs/1.jpg")
        .build()?;

    //generate an image
    let generated = texsynth.run(None);

    //save the image to the disk
    generated.save("out/01.jpg")
}

CLI

cargo运行 --发布 ----out out/01.jpg 生成 imgs/1.jpg

您应该得到以下结果,使用本仓库提供的图像

2. 多个示例生成

Imgur

我们还可以提供多个示例图像,算法将“混搭”它们生成新图像。

API - 02_multi_example_synthesis

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    // create a new session
    let texsynth = ts::Session::builder()
        // load multiple example image
        .add_examples(&[
            &"imgs/multiexample/1.jpg",
            &"imgs/multiexample/2.jpg",
            &"imgs/multiexample/3.jpg",
            &"imgs/multiexample/4.jpg",
        ])
        // we can ensure all of them come with same size
        // that is however optional, the generator doesnt care whether all images are same sizes
        // however, if you have guides or other additional maps, those have to be same size(s) as corresponding example(s)
        .resize_input(ts::Dims {
            width: 300,
            height: 300,
        })
        // randomly initialize first 10 pixels
        .random_init(10)
        .seed(211)
        .build()?;

    // generate an image
    let generated = texsynth.run(None);

    // save the image to the disk
    generated.save("out/02.jpg")?;

    //save debug information to see "remixing" borders of different examples in map_id.jpg
    //different colors represent information coming from different maps
    generated.save_debug("out/")
}

CLI

cargo运行 --发布 ----rand-init 10 --seed 211 --in-size 300x300 -o out/02.png --debug-out-dir out generate imgs/multiexample/1.jpg imgs/multiexample/2.jpg imgs/multiexample/3.jpg imgs/multiexample/4.jpg

您应该得到以下结果,使用本仓库提供的图像

3. 引导合成

Imgur

我们还可以通过提供“从...到...”的转换“引导图”来引导生成。

API - 03_guided_synthesis

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    let texsynth = ts::Session::builder()
        // NOTE: it is important that example(s) and their corresponding guides have same size(s)
        // you can ensure that by overwriting the input images sizes with .resize_input()
        .add_example(ts::Example::builder(&"imgs/2.jpg").with_guide(&"imgs/masks/2_example.jpg"))
        // load target "heart" shape that we would like the generated image to look like
        // now the generator will take our target guide into account during synthesis
        .load_target_guide(&"imgs/masks/2_target.jpg")
        .build()?;

    let generated = texsynth.run(None);

    // save the image to the disk
    generated.save("out/03.jpg")
}

CLI

cargo运行 --发布 ---o out/03.png generate --target-guide imgs/masks/2_target.jpg --guides imgs/masks/2_example.jpg -- imgs/2.jpg

注意:注意使用--来分隔到示例imgs/2.jpg的路径,如果不指定--,示例的路径将被用作另一个引导路径,并且将没有示例。

您应该得到以下结果,使用本仓库提供的图像

4. 风格迁移

Imgur

纹理合成API支持自动生成示例引导图,产生类似风格迁移的效果。

API - 04_style_transfer

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    let texsynth = ts::Session::builder()
        // load example which will serve as our style, note you can have more than 1!
        .add_examples(&[&"imgs/multiexample/4.jpg"])
        // load target which will be the content
        // with style transfer, we do not need to provide example guides
        // they will be auto-generated if none were provided
        .load_target_guide(&"imgs/tom.jpg")
        .guide_alpha(0.8)
        .build()?;

    // generate an image that applies 'style' to "tom.jpg"
    let generated = texsynth.run(None);

    // save the result to the disk
    generated.save("out/04.jpg")
}

CLI

cargo运行 --发布 ----alpha 0.8 -o out/04.png transfer-style --style imgs/multiexample/4.jpg --guide imgs/tom.jpg

您应该得到以下结果,使用本仓库提供的图像

5. 填充

Imgur

我们还可以使用填充来填补缺失的信息。通过更改种子,我们将获得不同版本的“填充”。

API - 05_inpaint

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    let texsynth = ts::Session::builder()
        // let the generator know which part we would like to fill in
        // if we had more examples, they would be additional information
        // the generator could use to inpaint
        .inpaint_example(
            &"imgs/masks/3_inpaint.jpg",
            // load a "corrupted" example with missing red information we would like to fill in
            ts::Example::builder(&"imgs/3.jpg")
                // we would also like to prevent sampling from "corrupted" red areas
                // otherwise, generator will treat that those as valid areas it can copy from in the example,
                // we could also use SampleMethod::Ignore to ignore the example altogether, but we
                // would then need at least 1 other example image to actually source from
                // example.set_sample_method(ts::SampleMethod::Ignore);
                .set_sample_method(&"imgs/masks/3_inpaint.jpg"),
            // Inpaint requires that inputs and outputs be the same size, so it's a required
            // parameter that overrides both `resize_input` and `output_size`
            ts::Dims::square(400),
        )
        // Ignored
        .resize_input(ts::Dims::square(200))
        // Ignored
        .output_size(ts::Dims::square(100))
        .build()?;

    let generated = texsynth.run(None);

    //save the result to the disk
    generated.save("out/05.jpg")
}

CLI

请注意,在填充时使用--out-size参数确定所有输入和输出的尺寸!

cargo运行 --发布 ----out-size 400 --inpaint imgs/masks/3_inpaint.jpg -o out/05.png generate imgs/3.jpg

您应该得到以下结果,使用本仓库提供的图像

6. 填充通道

bricks

我们不必使用单独的图像作为填充掩码,而是可以从特定的通道中获取信息。在这个例子中,alpha通道是图像中间的一个圆。

API - 06_inpaint_channel

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    let texsynth = ts::Session::builder()
        // Let the generator know that it is using 
        .inpaint_example_channel(
            ts::ChannelMask::A,
            &"imgs/bricks.png",
            ts::Dims::square(400),
        )
        .build()?;

    let generated = texsynth.run(None);

    //save the result to the disk
    generated.save("out/06.jpg")
}

CLI

cargo运行 --发布 ----inpaint-channel a -o out/06.png generate imgs/bricks.jpg

您应该得到以下结果,使用本仓库提供的图像

7. 平铺纹理

我们可以使生成的图像平铺(这意味着如果将多个图像并排放置,则不会有接缝)。通过同时调用填充模式和平铺,我们可以使现有的图像平铺。

API - 07_tiling_texture

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    // Let's start layering some of the "verbs" of texture synthesis
    // if we just run tiling_mode(true) we will generate a completely new image from scratch (try it!)
    // but what if we want to tile an existing image?
    // we can use inpaint!

    let texsynth = ts::Session::builder()
        // load a mask that specifies borders of the image we can modify to make it tiling
        .inpaint_example(
            &"imgs/masks/1_tile.jpg",
            ts::Example::new(&"imgs/1.jpg"),
            ts::Dims::square(400),
        )
        //turn on tiling mode!
        .tiling_mode(true)
        .build()?;

    let generated = texsynth.run(None);

    generated.save("out/07.jpg")
}

CLI

cargo运行 --发布 ----inpaint imgs/masks/1_tile.jpg --out-size 400 --tiling -o out/07.bmp generate imgs/1.jpg

您应该得到以下结果,使用本仓库提供的图像

8. 在新图像上重复纹理合成变换

我们可以将纹理合成执行的坐标变换重新应用于新图像。

API - 08_repeat_transform

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    // create a new session
    let texsynth = ts::Session::builder()
        //load a single example image
        .add_example(&"imgs/1.jpg")
        .build()?;

    // generate an image
    let generated = texsynth.run(None);

    // now we can apply the same transformation of the generated image
    // onto a new image (which can be used to ensure 1-1 mapping between multiple images)
    // NOTE: it is important to provide same number of input images as the 
    // otherwise, there will be coordinates mismatch
    let repeat_transform_img = generated
        .get_coordinate_transform()
        .apply(&["imgs/1_bw.jpg"])?;

    // save the image to the disk
    // 08 and 08_repeated images should match perfectly
    repeat_transform_img.save("out/08_repeated.jpg").unwrap();
    generated.save("out/08.jpg")
}

CLI

  1. 首先,我们需要创建一个可重复使用的变换

这里值得注意的是--save-transform out/multi.xform,它创建了一个文件,可以用它来生成新的输出。

cargo运行 --发布 ----rand-init 10 --seed 211 --in-size 300x300 -o out/02.png generate --save-transform out/multi.xform imgs/multiexample/1.jpg imgs/multiexample/2.jpg imgs/multiexample/3.jpg imgs/multiexample/4.jpg

  1. 接下来,我们使用repeat子命令重复变换与不同的输入

这里值得注意的是使用repeat子命令而不是generate,以及--transform out/multi.xform,它告诉应用于输入的变换。唯一的限制是您指定的图像数量必须与原始示例数量完全相同。如果输入图像的尺寸与示例图像不同,它们将自动为您调整尺寸。

cargo运行 --发布 ---o out/02-repeated.png repeat --transform out/multi.xform imgs/multiexample/1.jpg imgs/multiexample/2.jpg imgs/multiexample/4.jpg imgs/multiexample/3.jpg

请注意,与generate一起使用的正常参数不适用于repeat子命令,并且将被忽略。

9. 样本掩码

样本掩码允许您指定在生成过程中如何采样示例图像。

API - 09_sample_masks

use texture_synthesis as ts;

fn main() -> Result<(), ts::Error> {
    let session = ts::Session::builder()
        .add_example(
            ts::Example::builder(&"imgs/4.png").set_sample_method(ts::SampleMethod::Ignore),
        )
        .add_example(ts::Example::builder(&"imgs/5.png").set_sample_method(ts::SampleMethod::All))
        .seed(211)
        .output_size(ts::Dims::square(200))
        .build()?;

    // generate an image
    let generated = session.run(None);

    // save the image to the disk
    generated.save("out/09.png")
}

CLI

cargo运行 --发布 ----seed 211 --out-size 200 --sample-masks IGNORE ALL --out 09_sample_masks.png generate imgs/4.png imgs/5.png

您应该得到以下结果,使用本仓库提供的图像

10. 组合纹理合成“动词”

我们还可以将多种模式组合在一起。例如,多示例引导合成

或将生成多个阶段串联起来

有关更多用例和示例,请参阅演示文稿 "更多类似这样的,请!从单个示例进行纹理合成和混搭"

额外的 CLI 功能

某些功能仅通过 CLI 暴露,并未集成到库中。

翻转和旋转

此子命令将每个示例翻转和旋转,以生成额外的示例输入用于生成。此子命令不支持目标或示例引导。

示例: cargo run --release -- -o out/output.png flip-and-rotate imgs/1.jpg

命令行二进制文件

  • 为您的操作系统下载二进制文件
  • 或者 从源代码安装。
    • 安装 Rust - 最小要求版本是 1.37.0
    • 克隆此仓库
    • 在终端中 cd 到您克隆此仓库的目录
    • 运行 cargo install --path=cli
    • 或者 如果您希望查看正在合成的纹理,运行 cargo install --path=cli --features="progress"
  • 打开终端
  • 导航到您下载二进制文件的目录,如果您没有直接运行 cargo install
  • 运行 texture_synthesis --help 以获取您可以运行的所有选项和命令列表
  • 请参阅此说明文档中的示例部分以获取运行二进制文件的示例

注意事项

  • 默认情况下,生成输出将使用您所有的逻辑核心
  • 当使用多个线程进行生成时,输出图像不一定具有相同的输入的可确定性。为了达到 100% 的可确定性,您必须使用一个线程数,这可以通过以下方式完成
    • CLI - texture-synthesis --threads 1
    • API - SessionBuilder::max_thread_count(1)

限制

  • 处理超出像素颜色之外复杂语义的能力有限(除非您引导它)
  • 对于常规纹理表现不佳(接缝可能变得明显)
  • 不能从现有信息中推断新信息(仅操作已存在的信息)
  • 设计用于单个示例或非常小的数据集(与基于深度学习的方法不同)

其他依赖项

如果您正在为 Linux 编译,则需要安装 libxkbcommon 开发库。对于 Ubuntu,这是 libxkbcommon-x11-dev

链接/参考

[1] [Opara & Stachowiak] "更多类似这样的,请!从单个示例进行纹理合成和混搭"

[2] [Harrison] 图像纹理工具

[3] [Ashikhmin] 自然纹理合成

[4] [Efros & Leung] 基于非参数采样的纹理合成

【5】 [Wey & Levoy] 使用树结构矢量量化进行快速纹理合成

【6】 [De Bonet] 用于纹理图像分析和合成的多分辨率采样过程

【7】 本仓库中所有测试图像均来自 Unsplash

贡献

Contributor Covenant

我们欢迎社区为此项目做出贡献。

请阅读我们的 贡献指南 了解如何开始。

许可

以下任一许可下提供:

任选其一。

贡献

除非您明确声明,否则您提交给作品以包含在内的任何贡献,根据 Apache-2.0 许可定义,将如上双许可,不附加任何额外条款或条件。

依赖项

~14–23MB
~167K SLoC