Skip to content

Commit 74bce04

Browse files
authored
feat: add configurable reference image processing for edit models (#1780)
1 parent b5d8120 commit 74bce04

15 files changed

Lines changed: 553 additions & 161 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ API and command-line option may change frequently.***
5757
- [SeFi-Image](./docs/sefi_image.md)
5858
- [HiDream-O1-Image](./docs/hidream_o1_image.md)
5959
- [Ideogram4](./docs/ideogram4.md)
60-
- Image Edit Models
60+
- [Image Edit Models](./docs/edit.md)
6161
- [FLUX.1-Kontext-dev](./docs/kontext.md)
6262
- [Qwen Image Edit series](./docs/qwen_image_edit.md)
6363
- [LongCat Image Edit](./docs/longcat_image.md)

docs/edit.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Image Editing
2+
3+
Image editing in `stable-diffusion.cpp` allows you to use reference images to guide the generation process, enabling tasks like identity preservation, style transfer, or layout modification.
4+
5+
6+
## Supported Models
7+
8+
Depending on the architecture, different models handle reference images differently.
9+
10+
| Model | Default Preset |
11+
| :--- | :--- |
12+
| [**FLUX.1-Kontext-dev**](./kontext.md) | `flux_kontext` |
13+
| [**LongCat Image Edit**](./longcat_image.md) | `longcat` |
14+
| [**Qwen Image Edit**](./qwen_image_edit.md) | `qwen` |
15+
| **Qwen Image LAYERED** | `qwen_layered` |
16+
| [**Flux.2 [Dev] / Flux.2 [Klein]**](./flux2.md) | `flux2` |
17+
| [**Boogu Image Edit**](./boogu_image.md) | `z_image_omni` |
18+
| **Krea2 (Community Edit LoRAs)** | `krea2_ostris_edit` |
19+
| **Anima (Community Edit LoRAs)** | `cosmos_reference` |
20+
21+
Stable-diffusion.spp also supports basic Unet-based editing models like instruct-pix2pix or CosXL-Edit. This document is not about those.
22+
23+
---
24+
25+
## Configuring Reference Modes (`--ref-image-args`)
26+
27+
Different DiT-based editing models require different configurations to process reference images correctly (e.g., whether to use a Vision Language Model (VLM) encoder or pass VAE-encoded images directly to the DiT).
28+
29+
To simplify this, we provide **Presets**. By default, the system automatically selects the best preset based on the model architecture. However, you can override this using the `--ref-image-args` argument.
30+
31+
### Usage
32+
The `--ref-image-args` argument accepts a comma-separated list of key-value pairs:
33+
34+
**Using a preset:**
35+
`--ref-image-args "preset=qwen_layered"`
36+
37+
**Using a preset with a specific override:**
38+
`--ref-image-args "preset=krea2_edit,force_ref_timestep_zero=true"`
39+
40+
### Available Presets
41+
42+
| Preset | Primary Use Case |
43+
| :--- | :--- |
44+
| `flux_kontext` | FLUX.1 Kontext |
45+
| `longcat` | LongCat Image Edit |
46+
| `flux2` | FLUX.2 models |
47+
| `qwen` | Qwen Image Edit |
48+
| `qwen_layered` | Qwen Image Layered |
49+
| `z_image_omni` | Boogu, Z-Image Omni |
50+
| `krea2_ostris_edit` | Most Krea2 Community edit LoRAs (trained with Ostris script) |
51+
| `krea2_edit` | Specifically for [lbouaraba/krea2edit](https://huggingface.co/conradlocke/krea2-identity-edit). (or similar) |
52+
| `cosmos_reference` | For Anima |
53+
| `default` | Uses the automatic detection based on model architecture. |
54+
55+
---
56+
57+
## Advanced Parameter Reference
58+
59+
If presets are insufficient, you can manually configure the following parameters via `--ref-image-args`:
60+
61+
| Key | Type | Description | Allowed Values |
62+
| :--- | :--- | :--- | :--- |
63+
| `preset` | string | Overrides the automatic preset. | (See the Presets table above) |
64+
| `pass_to_vlm` | bool | Whether reference images are passed to the VLM encoder. | `true`, `false` |
65+
| `pass_to_dit` | bool | Whether VAE-encoded references are passed directly to the DiT. | `true`, `false` |
66+
| `ref_index_mode` | string | Behavior of the RoPE index. | `fixed`, `increase`, `decrease` |
67+
| `force_ref_timestep_zero` | bool | Forces timestep=0 for reference tokens. | `true`, `false` (Krea2 only) |
68+
| `resize_before_vae` | bool | Whether reference images are resized before VAE encoding. | `true`, `false` |
69+
| `vae_input_max_pixels` | int | Maximum pixel area for VAE reference inputs. | Integer |
70+
| `vlm_resize_mode` | string | How to resize VLM reference inputs. | `longest_side`, `area`, `none` |
71+
| `vlm_max_size` | int | Maximum VLM input size; interpreted according to `vlm_resize_mode`. | Integer |
72+
| `vlm_min_size` | int | Minimum VLM input size; interpreted according to `vlm_resize_mode`. | Integer |
73+
| `vlm_size` | int | Shortcut to set both VLM min and max size to the same value. | Integer |
74+
75+
### Preset Default Values
76+
77+
For a technical overview of how each preset is configured, see the table below.
78+
79+
| Preset | VLM | RoPE Index | Cond Resize | Special Notes |
80+
| :--- | :---: | :---: | :---: | :--- |
81+
| `flux_kontext` | No | `fixed` | `none` | |
82+
| `longcat` | Yes | `fixed` | `area` | |
83+
| `flux2` | No | `increase` | `none` | |
84+
| `qwen` | Yes | `increase` | `area` | |
85+
| `qwen_layered` | Yes | `decrease` | `area` | |
86+
| `z_image_omni` | Yes | `fixed` | `area` | |
87+
| `krea2_ostris_edit`| Yes | `increase` | `area` | `force_ref_timestep_zero = true` |
88+
| `krea2_edit` | Yes | `increase` | `longest` | `vlm_size = 768` |
89+
| `cosmos_reference` | No | `fixed` | `none` | `resize_before_vae = false` |
90+
91+
**Additional Default Notes:**
92+
- **VLM Input Sizes:** For most presets, `vlm_max_size` and `vlm_min_size` are set to `-1`, meaning the values are model-dependent and handled automatically. In `area` mode they represent pixel area; in `longest_side` mode they represent a side length in pixels.
93+
- **VAE Input Size:** `vae_input_max_pixels` defaults to $1024 \times 1024$ pixels (`1048576`).

examples/common/common.cpp

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,11 @@ ArgOptions SDGenerationParams::get_options() {
975975
"extra VAE tiling args, key=value list. LTX video VAE supports temporal_tile_frames (default: 4), temporal_tile_overlap (default: 1)",
976976
(int)',',
977977
&extra_tiling_args},
978+
{"",
979+
"--ref-image-args",
980+
"Key-value list to set up the way the reference images are processed (empty = auto-detect from model weigths)",
981+
(int)',',
982+
&ref_image_args},
978983
};
979984

980985
options.int_options = {
@@ -2418,30 +2423,45 @@ sd_img_gen_params_t SDGenerationParams::to_sd_img_gen_params_t() {
24182423
pulid_id_weight,
24192424
};
24202425

2421-
params.loras = lora_vec.empty() ? nullptr : lora_vec.data();
2422-
params.lora_count = static_cast<uint32_t>(lora_vec.size());
2423-
params.prompt = prompt.c_str();
2424-
params.negative_prompt = negative_prompt.c_str();
2425-
params.clip_skip = clip_skip;
2426-
params.init_image = init_image.get();
2427-
params.ref_images = ref_image_views.empty() ? nullptr : ref_image_views.data();
2428-
params.ref_images_count = static_cast<int>(ref_image_views.size());
2429-
params.auto_resize_ref_image = auto_resize_ref_image;
2430-
params.increase_ref_index = increase_ref_index;
2431-
params.mask_image = mask_image.get();
2432-
params.width = get_resolved_width();
2433-
params.height = get_resolved_height();
2434-
params.sample_params = sample_params;
2435-
params.strength = strength;
2436-
params.seed = seed;
2437-
params.batch_count = batch_count;
2438-
params.qwen_image_layers = qwen_image_layers;
2439-
params.control_image = control_image.get();
2440-
params.control_strength = control_strength;
2441-
params.pm_params = pm_params;
2442-
params.pulid_params = pulid_params;
2443-
params.vae_tiling_params = vae_tiling_params;
2444-
params.cache = cache_params;
2426+
if (!auto_resize_ref_image) {
2427+
if (!ref_image_args.empty()) {
2428+
ref_image_args += ",";
2429+
}
2430+
ref_image_args += "resize_before_vae=0";
2431+
LOG_WARN("Notice: --disable-auto-resize-ref-image is deprecated. Use --ref-image-args \"resize_before_vae=off\" instead.");
2432+
}
2433+
2434+
if (increase_ref_index) {
2435+
if (!ref_image_args.empty()) {
2436+
ref_image_args += ",";
2437+
}
2438+
ref_image_args += "ref_index_mode=increase";
2439+
LOG_WARN("Notice: --increase-ref-index is deprecated. Use --ref-image-args \"ref_index_mode=increase\" instead.");
2440+
}
2441+
2442+
params.loras = lora_vec.empty() ? nullptr : lora_vec.data();
2443+
params.lora_count = static_cast<uint32_t>(lora_vec.size());
2444+
params.prompt = prompt.c_str();
2445+
params.negative_prompt = negative_prompt.c_str();
2446+
params.clip_skip = clip_skip;
2447+
params.init_image = init_image.get();
2448+
params.ref_images = ref_image_views.empty() ? nullptr : ref_image_views.data();
2449+
params.ref_images_count = static_cast<int>(ref_image_views.size());
2450+
params.ref_image_args = ref_image_args.c_str();
2451+
params.mask_image = mask_image.get();
2452+
params.width = get_resolved_width();
2453+
params.height = get_resolved_height();
2454+
params.sample_params = sample_params;
2455+
params.strength = strength;
2456+
params.seed = seed;
2457+
params.batch_count = batch_count;
2458+
params.qwen_image_layers = qwen_image_layers;
2459+
params.control_image = control_image.get();
2460+
params.control_strength = control_strength;
2461+
params.pm_params = pm_params;
2462+
params.pulid_params = pulid_params;
2463+
params.vae_tiling_params = vae_tiling_params;
2464+
params.cache = cache_params;
24452465

24462466
params.hires.enabled = hires_enabled;
24472467
params.hires.upscaler = resolved_hires_upscaler;

examples/common/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ struct SDGenerationParams {
227227
sd_tiling_params_t vae_tiling_params = {false, false, 0, 0, 0.5f, 0.0f, 0.0f, nullptr};
228228
std::string extra_tiling_args;
229229

230+
std::string ref_image_args;
231+
230232
std::string pm_id_images_dir;
231233
std::string pm_id_embed_path;
232234
float pm_style_strength = 20.f;

include/stable-diffusion.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,7 @@ typedef struct {
363363
sd_image_t init_image;
364364
sd_image_t* ref_images;
365365
int ref_images_count;
366-
bool auto_resize_ref_image;
367-
bool increase_ref_index;
366+
const char* ref_image_args;
368367
sd_image_t mask_image;
369368
int width;
370369
int height;

0 commit comments

Comments
 (0)