Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
111f9fdffb | ||
|
|
9479106c1d | ||
|
|
db4bbbe9f2 | ||
|
|
1a3e15964c | ||
|
|
4cc30f8a1d | ||
|
|
d1e609192f | ||
|
|
bf46831196 | ||
|
|
c9d9a79b18 | ||
|
|
175156af86 | ||
|
|
3281946b32 | ||
|
|
83f557ff4c | ||
|
|
5e7fe4d5e4 | ||
|
|
69f2aded4d | ||
|
|
5f1b6d8989 | ||
|
|
7b0d144db9 | ||
|
|
27ebb6e7af | ||
|
|
f148e4b631 | ||
|
|
cc9ec8873a | ||
|
|
565087e8f8 | ||
|
|
ebdc5dcc02 | ||
|
|
9336523576 | ||
|
|
21520b38fb | ||
|
|
868bbaeefe | ||
|
|
3581d6c217 | ||
|
|
d4da280a92 | ||
|
|
d0bcd459cc | ||
|
|
469012d183 | ||
|
|
3f4a5cdb5a | ||
|
|
e0ce52b1be | ||
|
|
2c8f4baec0 | ||
|
|
daf1bdf4be | ||
|
|
f4d4dfdd61 | ||
|
|
6d624e7e1e | ||
|
|
e0940059e6 | ||
|
|
76ce20b51f | ||
|
|
29ed0b3da5 | ||
|
|
3d5aa3a3fa | ||
|
|
6109df6591 | ||
|
|
536716a7b9 | ||
|
|
ece228ab10 | ||
|
|
c048230250 | ||
|
|
aa885d9fa6 | ||
|
|
80d55a47b0 | ||
|
|
79db1765e3 | ||
|
|
929328d08d | ||
|
|
c12897040b | ||
|
|
48b9a59ca3 | ||
|
|
d55f8c61d0 | ||
|
|
a097b9c9b2 | ||
|
|
70cc94cc6a | ||
|
|
e653f45103 | ||
|
|
c9c237c2de | ||
|
|
c5aa0116d5 | ||
|
|
1820d88594 | ||
|
|
c265bcc989 | ||
|
|
b8973c570b | ||
|
|
1b50a90424 | ||
|
|
dab41249da | ||
|
|
b2b2b21bf1 | ||
|
|
099d4137a9 | ||
|
|
2f7967a584 | ||
|
|
e28e115297 | ||
|
|
f2cc70fed3 | ||
|
|
b8e140f7aa | ||
|
|
e6f61e806c | ||
|
|
ba506f2654 | ||
|
|
986dee6bd9 | ||
|
|
e514553120 | ||
|
|
40d7f0854e | ||
|
|
a5e3af84f9 | ||
|
|
598ca776eb | ||
|
|
b36584b2a7 | ||
|
|
082c549b24 | ||
|
|
453b6c090e | ||
|
|
07229ecbcd | ||
|
|
76cf0ff5fe | ||
|
|
e1f84469f1 | ||
|
|
1fa77b0d1e | ||
|
|
cd62e71467 | ||
|
|
deaf2cec2a | ||
|
|
587a941607 | ||
|
|
7bdbab75e6 | ||
|
|
b77c25677f | ||
|
|
bf5b607238 | ||
|
|
ad77fb7836 | ||
|
|
3f8eb2552f | ||
|
|
238e49e31f | ||
|
|
7aeb6e535f | ||
|
|
eda0f19944 | ||
|
|
e20c8f20ce | ||
|
|
89b9010b35 | ||
|
|
ee0c65656e | ||
|
|
48b1dd4be6 | ||
|
|
9d304cd5a3 | ||
|
|
61c19ac31d | ||
|
|
1ca6e53090 | ||
|
|
520932cee0 | ||
|
|
37612bb399 | ||
|
|
0e6cb45081 | ||
|
|
0a5e36d55e | ||
|
|
b319f772cb | ||
|
|
340376ad18 | ||
|
|
dbfc1585fc | ||
|
|
c3ae2c644d | ||
|
|
c7017373c9 | ||
|
|
850f707eb6 | ||
|
|
62870f060a | ||
|
|
a91cefacf0 | ||
|
|
4265f71a85 | ||
|
|
4189ba80c2 | ||
|
|
23ad6e47fd | ||
|
|
4d3d5d17f0 |
@@ -98,3 +98,5 @@ cookiecutter-pypackage-env/
|
||||
# vscode settings
|
||||
.history/
|
||||
*.code-workspace
|
||||
.vscode/
|
||||
/.vscode
|
||||
|
||||
@@ -5,4 +5,8 @@
|
||||
"/PATH/TO/ComfyUI/",
|
||||
"/PATH/TO/ComfyUI/custom_nodes/"
|
||||
],
|
||||
"cursorpyright.analysis.extraPaths": [
|
||||
"/PATH/TO/ComfyUI/",
|
||||
"/PATH/TO/ComfyUI/custom_nodes/"
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,29 +1,104 @@
|
||||
# LanPaint (Thinking mode Inpaint)
|
||||
<div align="center">
|
||||
|
||||
Unlock precise inpainting without additional training. LanPaint lets the model "think" through multiple iterations before denoising, aiming for seamless and accurate results.
|
||||

|
||||
# LanPaint: Universal Inpainting Sampler with "Think Mode"
|
||||
[](https://openreview.net/pdf?id=JPC8JyOUSW)
|
||||
[](https://github.com/scraed/LanPaintBench)
|
||||
[](https://github.com/comfyanonymous/ComfyUI)
|
||||
[](https://huggingface.co/charrywhite/LanPaint)
|
||||
[](https://scraed.github.io/scraedBlog/)
|
||||
[](https://github.com/scraed/LanPaint/stargazers)
|
||||
[](https://discord.gg/aCGZutBV)
|
||||
</div>
|
||||
|
||||
This is the official implementation of ["Lanpaint: Training-Free Diffusion Inpainting with Exact and Fast Conditional Inference"](https://arxiv.org/abs/2502.03491).
|
||||
|
||||
Universally applicable inpainting ability for every model. LanPaint sampler lets the model "think" through multiple iterations before denoising, enabling you to invest more computation time for superior inpainting quality.
|
||||
|
||||
This is the official implementation of ["LanPaint: Training-Free Diffusion Inpainting with Asymptotically Exact and Fast Conditional Sampling"](https://arxiv.org/abs/2502.03491), accepted by TMLR. The repository is for ComfyUI extension. Local Python benchmark code is published here: [LanPaintBench](https://github.com/scraed/LanPaintBench).
|
||||
|
||||
## Citation
|
||||
|
||||
```
|
||||
@article{
|
||||
zheng2025lanpaint,
|
||||
title={LanPaint: Training-Free Diffusion Inpainting with Asymptotically Exact and Fast Conditional Sampling},
|
||||
author={Candi Zheng and Yuan Lan and Yang Wang},
|
||||
journal={Transactions on Machine Learning Research},
|
||||
issn={2835-8856},
|
||||
year={2025},
|
||||
url={https://openreview.net/forum?id=JPC8JyOUSW},
|
||||
note={}
|
||||
}
|
||||
```
|
||||
**🎉 NEW 2026: Join our discord!**
|
||||
|
||||
[Join our Discord](https://discord.gg/aCGZutBV) to share experiences, discuss features, and explore future development.
|
||||
|
||||
**🎬 NEW: LanPaint now supports inpainting and outpainting based on Z-Image!**
|
||||
|
||||
| Original | Masked | Inpainted |
|
||||
|:--------:|:------:|:---------:|
|
||||
|  |  |  |
|
||||
|
||||
|
||||
**🎬 NEW: LanPaint now supports video inpainting and outpainting based on Wan 2.2!**
|
||||
|
||||
<div align="center">
|
||||
|
||||
| Original Video | Mask (edit T-shirt text) | Inpainted Result |
|
||||
|:--------------:|:----:|:----------------:|
|
||||
|  |  |  |
|
||||
|
||||
*Video Inpainting Example: 81 frames with temporal consistency*
|
||||
|
||||
</div>
|
||||
|
||||
Check our latest [Wan 2.2 Video Examples](#video-examples-beta), [Wan 2.2 Image Examples](#example-wan22-inpaintlanpaint-k-sampler-5-steps-of-thinking), and
|
||||
[Qwen Image Edit 2509](#example-qwen-edit-2509-inpaint) support.
|
||||
|
||||
|
||||
## Table of Contents
|
||||
- [Features](#features)
|
||||
- [Quickstart](#quickstart)
|
||||
- [How to Use Examples](#how-to-use-examples)
|
||||
- [Video Examples (Beta)](#video-examples-beta)
|
||||
- [Wan 2.2 Video Inpainting](#wan-22-video-inpainting)
|
||||
- [Wan 2.2 5B Video Inpainting](#wan-22-5b-video-inpainting)
|
||||
- [Wan 2.2 Video Outpainting](#wan-22-video-outpainting)
|
||||
- [Resource Consumption](#resource-consumption)
|
||||
- [Image Examples](#image-examples)
|
||||
- [Flux.2.Dev](#example-flux2dev-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Z-image](#example-z-image-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Hunyuan T2I](#example-hunyuan-t2i-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Wan 2.2 T2I](#example-wan22-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Wan 2.2 T2I with reference](#example-wan22-partial-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Qwen Image Edit 2511 2509](#example-qwen-edit-2509-inpaint)
|
||||
- [Qwen Image Edit 2508](#example-qwen-edit-2508-inpaint)
|
||||
- [Qwen Image](#example-qwen-image-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [HiDream](#example-hidream-inpaint-lanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [SD 3.5](#example-sd-35-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Flux](#example-flux-inpaintlanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [SDXL](#example-sdxl-0-character-consistency-side-view-generation-lanpaint-k-sampler-5-steps-of-thinking)
|
||||
- [Usage](#usage)
|
||||
- [Basic Sampler](#basic-sampler)
|
||||
- [Advanced Sampler](#lanpaint-ksampler-advanced)
|
||||
- [Tuning Guide](#lanpaint-ksampler-advanced-tuning-guide)
|
||||
- [Community Showcase](#community-showcase-)
|
||||
- [FAQ](#faq)
|
||||
- [Updates](#updates)
|
||||
- [ToDo](#todo)
|
||||
- [Citation](#citation)
|
||||
|
||||
## Features
|
||||
|
||||
- **Universal Compatibility** – Works instantly with almost any model (SD 1.5, XL, 3.5, Flux, HiDream, or custom LoRAs) and ControlNet.
|
||||
- **Universal Compatibility** – Works instantly with almost any model (**Z-image, Hunyuan, Wan 2.2, Qwen Image/Edit, HiDream, SD 3.5, Flux-series, SDXL, SD 1.5 or custom LoRAs**) and ControlNet.
|
||||

|
||||
- **No Training Needed** – Works out of the box with your existing model.
|
||||
- **Easy to Use** – Same workflow as standard ComfyUI KSampler.
|
||||
- **Flexible Masking** – Supports any mask shape, size, or position for inpainting/outpainting.
|
||||
- **No Workarounds** – Generates 100% new content (no blending or smoothing) without relying on partial denoising.
|
||||
- **Beyond Inpainting** – You can even use it as a simple way to generate consistent characters.
|
||||
|
||||
## How It Works
|
||||
LanPaint uses Langevin Dynamics as "thinking" steps, which digs deeper into the diffusion process and allows the model to generate more consistent results.
|
||||
|
||||
LanPaint introduces "BIG score" that creates a **two-way alignment** between masked and unmasked areas. It continuously evaluates:
|
||||
- *"Does the new content make sense with the existing elements?"*
|
||||
- *"Do the existing elements support the new creation?"*
|
||||
Based on this evaluation, LanPaint iteratively updates the noise in both the masked and unmasked regions.
|
||||
|
||||
LanPaint also implements an accurate, robust, and fast Langevin dynamics solver.
|
||||
|
||||
**Warning**: LanPaint has degraded performance on distillation models, such as Flux.dev, due to a similar [issue with LORA training](https://medium.com/@zhiwangshi28/why-flux-lora-so-hard-to-train-and-how-to-overcome-it-a0c70bc59eaf). Please use low flux guidance (1.0-2.0) to mitigate this [issue](https://github.com/scraed/LanPaint/issues/30).
|
||||
|
||||
## Quickstart
|
||||
|
||||
@@ -41,38 +116,232 @@ LanPaint also implements an accurate, robust, and fast Langevin dynamics solver.
|
||||
Once installed, you'll find the LanPaint nodes under the "sampling" category in ComfyUI. Use them just like the default KSampler for high-quality inpainting!
|
||||
|
||||
|
||||
## **How to Use Examples:**
|
||||
1. Navigate to the **example** folder (i.e example_1), download all pictures.
|
||||
2. Drag **InPainted_Drag_Me_to_ComfyUI.png** into ComfyUI to load the workflow.
|
||||
3. Download the required model (i.e clicking **Model Used in This Example**).
|
||||
4. Load the model in ComfyUI.
|
||||
5. Upload **Masked_Load_Me_in_Loader.png** to the **"Load image"** node in the **"Mask image for inpainting"** group (second from left), or the **Prepare Image** node.
|
||||
7. Queue the task, you will get inpainted results from LanPaint. Some example also gives you inpainted results from the following methods for comparison:
|
||||
- **[VAE Encode for Inpainting](https://comfyanonymous.github.io/ComfyUI_examples/inpaint/)**
|
||||
- **[Set Latent Noise Mask](https://comfyui-wiki.com/en/tutorial/basic/how-to-inpaint-an-image-in-comfyui)**
|
||||
|
||||
## Updates
|
||||
- 2025/06/04
|
||||
- Add more sampler support.
|
||||
- Add early stopping to advanced sampler.
|
||||
- 2025/05/28
|
||||
- Major update on the Langevin solver. It is now much faster and more stable.
|
||||
- Greatly simplified the parameters for advanced sampler.
|
||||
- Fix performance issue on Flux and SD 3.5
|
||||
- 2025/04/16
|
||||
- Added Primary HiDream support
|
||||
- 2025/03/22
|
||||
- Added Primary Flux support
|
||||
- Added Tease Mode
|
||||
- 2025/03/10
|
||||
- LanPaint has received a major update! All examples now use the LanPaint K Sampler, offering a simplified interface with enhanced performance and stability.
|
||||
## Video Examples (Beta)
|
||||
|
||||
## Examples
|
||||
All examples use a random seed 0 to generate batch of 4 images for fair comparison. (Warning: Generating 4 images may exceed your GPU memory; adjust batch size as needed.)
|
||||
LanPaint now supports video inpainting with Wan 2.2, enabling you to seamlessly inpaint masked regions across video frames while maintaining temporal consistency.
|
||||
|
||||
### Example HiDream: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
**Note:** LanPaint supports video inpainting for longer sequences (e.g., 81 frames), but processing time increases significantly (please check the [Resource Consumption](#resource-consumption) section for details) and performance may become unstable. For optimal results and stability, we recommend limiting video inpainting to **40 frames or fewer**.
|
||||
|
||||
### Wan 2.2 Video Inpainting
|
||||
|
||||
*Example: Wan2.2 t2v 14B, 480p video (11:6), 40 frames, LanPaint K Sampler, 2 steps of thinking*
|
||||
|
||||
| Original Video | Mask (Add a white hat) | Inpainted Result |
|
||||
|:--------------:|:----:|:----------------:|
|
||||
|  |  |  |
|
||||
|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_17)
|
||||
|
||||
You need to follow the ComfyUI version of [Wan2.2 T2V workflow](https://docs.comfy.org/tutorials/video/wan/wan2_2) to download and install the T2V model.
|
||||
|
||||
### Wan 2.2 5B Video Inpainting
|
||||
|
||||
Similar to Wan 2.2 14B with slightly different workflow. [View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_17)
|
||||
|
||||
### Wan 2.2 Video Outpainting
|
||||
|
||||
Extend your videos beyond their original boundaries with LanPaint's video outpainting capability based on Wan 2.2. This feature allows you to expand the canvas of your videos while maintaining coherent motion and context.
|
||||
|
||||
*Example: Wan2.2 t2v 14B, 480p video (1:1 outpaint to 11:6), 40 frames, LanPaint K Sampler, 2 steps of thinking*
|
||||
|
||||
| Original Video | Mask (Expand to 880x480) | Outpainted Result |
|
||||
|:--------------:|:----:|:-----------------:|
|
||||
|  |  |  |
|
||||
|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_19)
|
||||
|
||||
You need to follow the ComfyUI version of [Wan2.2 T2V workflow](https://docs.comfy.org/tutorials/video/wan/wan2_2) to download and install the T2V model.
|
||||
|
||||
### Resource Consumption
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Processing Mode</th>
|
||||
<th align="left">Resolution</th>
|
||||
<th align="left">Frames Processed</th>
|
||||
<th align="left">VRAM Required</th>
|
||||
<th align="left">Total Runtime (20 steps)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="background-color: #e8f4f8;">
|
||||
<td><strong>Inpainting</strong></td>
|
||||
<td>880×480 (11:6)</td>
|
||||
<td>40 frames</td>
|
||||
<td>39.8 GB</td>
|
||||
<td><strong>05:37 min</strong></td>
|
||||
</tr>
|
||||
<tr style="background-color: #e8f4f8;">
|
||||
<td><strong>Inpainting</strong></td>
|
||||
<td>480×480 (1:1)</td>
|
||||
<td>40 frames</td>
|
||||
<td>38.0 GB</td>
|
||||
<td><strong>05:35 min</strong></td>
|
||||
</tr>
|
||||
<tr style="background-color: #e8f4f8;">
|
||||
<td><strong>Outpainting</strong></td>
|
||||
<td>880×480 (11:6)</td>
|
||||
<td>40 frames</td>
|
||||
<td>40.2 GB</td>
|
||||
<td><strong>05:36 min</strong></td>
|
||||
</tr>
|
||||
<tr style="background-color: #fff4e6;">
|
||||
<td><strong>Inpainting</strong></td>
|
||||
<td>880×480 (11:6)</td>
|
||||
<td>81 frames</td>
|
||||
<td>43.3 GB</td>
|
||||
<td><strong>16:23 min</strong></td>
|
||||
</tr>
|
||||
<tr style="background-color: #fff4e6;">
|
||||
<td><strong>Inpainting</strong></td>
|
||||
<td>480×480 (1:1)</td>
|
||||
<td>81 frames</td>
|
||||
<td>39.8 GB</td>
|
||||
<td><strong>14:25 min</strong></td>
|
||||
</tr>
|
||||
<tr style="background-color: #fff4e6;">
|
||||
<td><strong>Outpainting</strong></td>
|
||||
<td>880×480 (11:6)</td>
|
||||
<td>81 frames</td>
|
||||
<td>42.6 GB</td>
|
||||
<td><strong>13:46 min</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<sub>**Test Platform**: All tests were conducted on an NVIDIA RTX Pro 6000.<br>
|
||||
**Model Used**: `wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors` and `wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors`.<br>
|
||||
**Processing Steps**: 20 sampling steps x 2 (LanPaint steps of thinking).</sub>
|
||||
|
||||
**Note:** Vram is required by the model, not LanPaint. To further reduce VRAM requirements, we recommend generating less frames and loading CLIP on CPU.
|
||||
|
||||
## Image Examples
|
||||
|
||||
### Example Hunyuan T2I: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
We are excited to announce that LanPaint now supports inpainting with Hunyuan text to image generation.
|
||||
|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_20)
|
||||
|
||||
|
||||
You need to follow the ComfyUI version of [Hunyuan workflow](https://docs.comfy.org/tutorials/video/hunyuan-video#hunyuan-text-to-video-workflow) to download and install the model.
|
||||
|
||||
### Example Wan2.2: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
We are excited to announce that LanPaint now supports Wan2.2 text to image generation with Wan2.2 T2V model.
|
||||
|
||||

|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_15)
|
||||
|
||||
|
||||
You need to follow the ComfyUI version of [Wan2.2 T2V workflow](https://docs.comfy.org/tutorials/video/wan/wan2_2) to download and install the T2V model.
|
||||
|
||||
### Example Z-image: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
LanPaint also supports inpainting with the Z-image text-to-image model.
|
||||
|
||||
<details open>
|
||||
<summary>View Original / Masked / Inpainted Comparison</summary>
|
||||
|
||||
| Original | Masked | Inpainted |
|
||||
|:--------:|:------:|:---------:|
|
||||
|  |  |  |
|
||||
|
||||
</details>
|
||||
|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_21)
|
||||
|
||||
<details open>
|
||||
<summary>View Z-image Outpainting (Original / Masked / Outpainted)</summary>
|
||||
|
||||
| Original | Masked | Outpainted |
|
||||
|:--------:|:------:|:----------:|
|
||||
|  |  |  |
|
||||
|
||||
</details>
|
||||
|
||||
[View Outpaint Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_22)
|
||||
|
||||
You can download the Z-image model for ComfyUI from [Z-image](https://docs.comfy.org/zh-CN/tutorials/image/z-image/z-image-turbo).
|
||||
|
||||
### Example Wan2.2: Partial InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
Sometimes we don't want to inpaint completely new content, but rather let the inpainted image reference the original image. One option to achieve this is to inpaint with an edit model like Qwen Image Edit. Another option is to perform a partial inpaint: allowing the diffusion process to start at some middle steps rather than from 0.
|
||||
|
||||

|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_16)
|
||||
|
||||
|
||||
You need to follow the ComfyUI version of [Wan2.2 T2V workflow](https://docs.comfy.org/tutorials/video/wan/wan2_2) to download and install the T2V model.
|
||||
|
||||
|
||||
### Example Qwen Edit 2509: InPaint
|
||||
Check our latest updated [Mased Qwen Edit Workflow](https://github.com/scraed/LanPaint/tree/master/examples/Example_14) for Qwen Image Edit 2509. Download the model at [Qwen Image Edit 2509 Comfy](https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/tree/main/split_files/diffusion_models). This workflow also supports Qwen Image Edit 2511.
|
||||
|
||||

|
||||
|
||||
### Example Qwen Edit 2508: InPaint
|
||||

|
||||
Check [Mased Qwen Edit Workflow](https://github.com/scraed/LanPaint/tree/master/examples/Example_14). You need to follow the ComfyUI version of [Qwen Image Edit workflow](https://docs.comfy.org/tutorials/image/qwen/qwen-image-edit) to download and install the model.
|
||||
|
||||
|
||||
|
||||
### Example Qwen Image: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
|
||||

|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_11)
|
||||
|
||||
|
||||
You need to follow the ComfyUI version of [Qwen Image workflow](https://docs.comfy.org/tutorials/image/qwen/qwen-image) to download and install the model.
|
||||
|
||||
The following examples utilize a random seed of 0 to generate a batch of 4 images for variance demonstration and fair comparison. (Note: Generating 4 images may exceed your GPU memory; please adjust the batch size as necessary.)
|
||||
|
||||

|
||||
Also check [Qwen Inpaint Workflow](https://github.com/scraed/LanPaint/tree/master/examples/Example_13) and [Qwen Outpaint Workflow](https://github.com/scraed/LanPaint/tree/master/examples/Example_12). You need to follow the ComfyUI version of [Qwen Image workflow](https://docs.comfy.org/tutorials/image/qwen/qwen-image) to download and install the model.
|
||||
|
||||
### Example HiDream: InPaint (LanPaint K Sampler, 5 steps of thinking)
|
||||

|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_8)
|
||||
|
||||
You need to follow the ComfyUI version of [HiDream workflow](https://docs.comfy.org/tutorials/image/hidream/hidream-i1) to download and install the model.
|
||||
|
||||
### Example HiDream: OutPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
.jpg)
|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_10)
|
||||
|
||||
You need to follow the ComfyUI version of [HiDream workflow](https://docs.comfy.org/tutorials/image/hidream/hidream-i1) to download and install the model. Thanks [Amazon90](https://github.com/Amazon90) for providing this example.
|
||||
|
||||
### Example SD 3.5: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||

|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_9)
|
||||
|
||||
You need to follow the ComfyUI version of [SD 3.5 workflow](https://comfyui-wiki.com/en/tutorial/advanced/stable-diffusion-3-5-comfyui-workflow) to download and install the model.
|
||||
|
||||
### Example Flux.2.Dev: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||
|
||||
<details open>
|
||||
<summary>View Original / Masked / Inpainted Comparison</summary>
|
||||
|
||||
| Original | Masked | Inpainted |
|
||||
|:--------:|:------:|:---------:|
|
||||
|  |  |  |
|
||||
|
||||
</details>
|
||||
|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_23)
|
||||
|
||||
[Model Used in This Example](https://huggingface.co/Comfy-Org/flux2-dev)
|
||||
|
||||
(Note: Prompt First mode is disabled on Flux.2.Dev. As it does not use CFG guidance.)
|
||||
|
||||
### Example Flux: InPaint(LanPaint K Sampler, 5 steps of thinking)
|
||||

|
||||
[View Workflow & Masks](https://github.com/scraed/LanPaint/tree/master/examples/Example_7)
|
||||
@@ -115,23 +384,6 @@ You need to follow the ComfyUI version of [SD 3.5 workflow](https://comfyui-wiki
|
||||
Check more for use cases like inpaint on [fine tuned models](https://github.com/scraed/LanPaint/issues/12#issuecomment-2938662021) and [face swapping](https://github.com/scraed/LanPaint/issues/12#issuecomment-2938723501), thanks to [Amazon90](https://github.com/Amazon90).
|
||||
|
||||
|
||||
## **How to Use These Examples:**
|
||||
1. Navigate to the **example** folder (i.e example_1) by clicking **View Workflow & Masks**, download all pictures.
|
||||
2. Drag **InPainted_Drag_Me_to_ComfyUI.png** into ComfyUI to load the workflow.
|
||||
3. Download the required model from Civitai by clicking **Model Used in This Example**.
|
||||
4. Load the model into the **"Load Checkpoint"** node.
|
||||
5. Upload **Original_No_Mask.png** to the **"Load image"** node in the **"Original Image"** group (far left).
|
||||
6. Upload **Masked_Load_Me_in_Loader.png** to the **"Load image"** node in the **"Mask image for inpainting"** group (second from left).
|
||||
7. Queue the task, you will get inpainted results from three methods:
|
||||
- **[VAE Encode for Inpainting](https://comfyanonymous.github.io/ComfyUI_examples/inpaint/)** (middle),
|
||||
- **[Set Latent Noise Mask](https://comfyui-wiki.com/en/tutorial/basic/how-to-inpaint-an-image-in-comfyui)** (second from right),
|
||||
- **LanPaint** (far right).
|
||||
|
||||
Compare and explore the results from each method!
|
||||
|
||||

|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
**Workflow Setup**
|
||||
@@ -166,20 +418,22 @@ Full parameter control:
|
||||
| `LanPaint_StepSize` | 0.1-1.0 | The StepSize of each thinking step. Recommend 0.1-0.5. |
|
||||
| `LanPaint_Beta` | 0.1-2.0 | The StepSize ratio between masked / unmasked region. Small value can compensate high lambda values. Recommend 1.0 |
|
||||
| `LanPaint_Friction` | 0.0-100.0 | The friction of Langevin dynamics. Higher means more slow but stable, lower means fast but unstable. Recommend 10.0 - 20.0|
|
||||
| `LanPaint_EarlyStop` | 0-10 | Stop LanPaint iteration before the final sampling step. Helps to remove artifacts in some cases. Recommend 1-5|
|
||||
| `LanPaint_PromptMode` | Image First / Prompt First | Image First mode focuses on the image context, maybe ignore prompt. Prompt First mode focuses more on the prompt. |
|
||||
|
||||
For detailed descriptions of each parameter, simply hover your mouse over the corresponding input field to view tooltips with additional information.
|
||||
|
||||
|
||||
### LanPaint Mask Blend
|
||||
This node blends the original image with the inpainted image based on the mask. It is useful if you want the unmasked region to match the original image pixel perfectly.
|
||||
|
||||
## LanPaint KSampler (Advanced) Tuning Guide
|
||||
For challenging inpainting tasks:
|
||||
|
||||
1️⃣ **Boost Quality**
|
||||
Increase total number of sampling steps, **LanPaint_NumSteps** (thinking iterations) or **LanPaint_Lambda** if the inpainted result does not meet your expectations.
|
||||
Increase **total number of sampling steps** (very important!), **LanPaint_NumSteps** (thinking iterations) or **LanPaint_Lambda** if the inpainted result does not meet your expectations.
|
||||
|
||||
2️⃣ **Boost Speed**
|
||||
If you want better results but still need fewer steps, consider:
|
||||
Decrease **LanPaint_NumSteps** to accelerate generation! If you want better results but still need fewer steps, consider:
|
||||
- **Increasing LanPaint_StepSize** to speed up the thinking process.
|
||||
- **Decreasing LanPaint_Friction** to make the Langevin dynamics converges more faster.
|
||||
|
||||
@@ -192,26 +446,62 @@ If you find the results have wired texture, try
|
||||
⚠️ **Notes**:
|
||||
- For effective tuning, **fix the seed** and adjust parameters incrementally while observing the results. This helps isolate the impact of each setting. Better to do it with a batche of images to avoid overfitting on a single image.
|
||||
|
||||
## Community Showcase [](#community-showcase-)
|
||||
|
||||
Discover how the community is using LanPaint! Here are some user-created tutorials:
|
||||
|
||||
- [Ai绘画进阶148-三大王炸!庆祝高允贞出道6周年!T8即将直播?当AI绘画学会深度思考?!万能修复神器LanPaint,万物皆可修!-T8 Comfyui教程](https://www.youtube.com/watch?v=Z4DSTv3UPJo)
|
||||
- [Ai绘画进阶151-真相了!T8竟是个AI?!LanPaint进阶(二),人物一致性,多视角实验性测试,新参数讲解,工作流分享-T8 Comfyui教程](https://www.youtube.com/watch?v=landiRhvF3k)
|
||||
- [重绘和三视图角色一致性解决新方案!LanPaint节点尝试](https://www.youtube.com/watch?v=X0WbXdm6FA0)
|
||||
- [ComfyUI: HiDream with Perturbation Upscale, LanPaint Inpainting (Workflow Tutorial)](https://www.youtube.com/watch?v=2-mGe4QVIIw&t=2785s)
|
||||
- [ComfyUI必备LanPaint插件超详细使用教程](https://plugin.aix.ink/archives/lanpaint)
|
||||
|
||||
Submit a PR to add your tutorial/video here, or open an [Issue](https://github.com/scraed/LanPaint/issues) with details!
|
||||
|
||||
## FAQ
|
||||
[Working togather with crop&stitch](https://github.com/scraed/LanPaint/issues/46)
|
||||
|
||||
## Updates
|
||||
- 2025/08/08
|
||||
- Add Qwen image support
|
||||
- 2025/06/21
|
||||
- Update the algorithm with enhanced stability and outpaint performance.
|
||||
- Add outpaint example
|
||||
- Supports Sampler Custom (Thanks to [MINENEMA](https://github.com/MINENEMA))
|
||||
- 2025/06/04
|
||||
- Add more sampler support.
|
||||
- Add early stopping to advanced sampler.
|
||||
- 2025/05/28
|
||||
- Major update on the Langevin solver. It is now much faster and more stable.
|
||||
- Greatly simplified the parameters for advanced sampler.
|
||||
- Fix performance issue on Flux and SD 3.5
|
||||
- 2025/04/16
|
||||
- Added Primary HiDream support
|
||||
- 2025/03/22
|
||||
- Added Primary Flux support
|
||||
- Added Tease Mode
|
||||
- 2025/03/10
|
||||
- LanPaint has received a major update! All examples now use the LanPaint K Sampler, offering a simplified interface with enhanced performance and stability.
|
||||
- 2025/03/06:
|
||||
- Bug Fix for str not callable error and unpack error. Big thanks to [jamesWalker55](https://github.com/jamesWalker55) and [EricBCoding](https://github.com/EricBCoding).
|
||||
|
||||
## ToDo
|
||||
- Try Implement Detailer
|
||||
- Provide inference code on without GUI.
|
||||
|
||||
## Contribute
|
||||
|
||||
- 2025/03/06: Bug Fix for str not callable error and unpack error. Big thanks to [jamesWalker55](https://github.com/jamesWalker55) and [EricBCoding](https://github.com/EricBCoding).
|
||||
- ~~Provide inference code on without GUI.~~ Check our local Python benchmark code [LanPaintBench](https://github.com/scraed/LanPaintBench).
|
||||
|
||||
|
||||
## Citation
|
||||
|
||||
```
|
||||
@misc{zheng2025lanpainttrainingfreediffusioninpainting,
|
||||
title={Lanpaint: Training-Free Diffusion Inpainting with Exact and Fast Conditional Inference},
|
||||
author={Candi Zheng and Yuan Lan and Yang Wang},
|
||||
year={2025},
|
||||
eprint={2502.03491},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={eess.IV},
|
||||
url={https://arxiv.org/abs/2502.03491},
|
||||
@article{
|
||||
zheng2025lanpaint,
|
||||
title={LanPaint: Training-Free Diffusion Inpainting with Asymptotically Exact and Fast Conditional Sampling},
|
||||
author={Candi Zheng and Yuan Lan and Yang Wang},
|
||||
journal={Transactions on Machine Learning Research},
|
||||
issn={2835-8856},
|
||||
year={2025},
|
||||
url={https://openreview.net/forum?id=JPC8JyOUSW},
|
||||
note={}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -219,4 +509,3 @@ If you find the results have wired texture, try
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,786 @@
|
||||
{
|
||||
"id": "978d3a45-3d13-43c6-8ef9-89dc3e74d6ba",
|
||||
"revision": 0,
|
||||
"last_node_id": 82,
|
||||
"last_link_id": 220,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 66,
|
||||
"type": "SetLatentNoiseMask",
|
||||
"pos": [
|
||||
514.1915893554688,
|
||||
781.9396362304688
|
||||
],
|
||||
"size": [
|
||||
264.5999755859375,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 216
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 189
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
186
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "SetLatentNoiseMask"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 78,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
314.8565368652344,
|
||||
255.63235473632812
|
||||
],
|
||||
"size": [
|
||||
422.84503173828125,
|
||||
164.31304931640625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"label": "clip",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 194
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"label": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
195
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Positive Prompt)",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.26",
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"cute anime girl with massive fluffy fennec ears and a big fluffy tail blonde messy long hair blue eyes wearing a maid outfit with a long black gold leaf pattern dress and a white apron mouth open placing a fancy black forest cake with candles on top of a dinner table of an old dark Victorian mansion lit by candlelight with a bright window to the foggy forest and very expensive stuff everywhere there are paintings on the walls"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 80,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
362.7684020996094,
|
||||
481.0662536621094
|
||||
],
|
||||
"size": [
|
||||
422.84503173828125,
|
||||
164.31304931640625
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"label": "clip",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 196
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"label": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
210
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Negative Prompt)",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.26",
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 79,
|
||||
"type": "FluxGuidance",
|
||||
"pos": [
|
||||
529.1380615234375,
|
||||
156.20236206054688
|
||||
],
|
||||
"size": [
|
||||
211.60000610351562,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"label": "conditioning",
|
||||
"name": "conditioning",
|
||||
"type": "CONDITIONING",
|
||||
"link": 195
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"label": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
207
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.26",
|
||||
"Node name for S&R": "FluxGuidance"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 77,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
-66.25785064697266,
|
||||
484.081787109375
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"label": "MODEL",
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
197
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "CLIP",
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"slot_index": 1,
|
||||
"links": [
|
||||
194,
|
||||
196
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "VAE",
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 2,
|
||||
"links": [
|
||||
200,
|
||||
203
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.26",
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"flux1-dev-fp8.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 73,
|
||||
"type": "LanPaint_KSampler",
|
||||
"pos": [
|
||||
1005.0399780273438,
|
||||
296.9553527832031
|
||||
],
|
||||
"size": [
|
||||
413.6495666503906,
|
||||
596
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 197
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 207
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 210
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 186
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
187
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "56bd6c04e89124cd06682b304245d6ddf8b20522",
|
||||
"Node name for S&R": "LanPaint_KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed",
|
||||
30,
|
||||
1,
|
||||
"euler",
|
||||
"simple",
|
||||
1,
|
||||
5,
|
||||
"Image First",
|
||||
"LanPaint KSampler. Recommend steps 50, LanPaint NumSteps 1-20 depending on the difficulty of task. LanPaint_EndSigma = 3.0 for anime style, 0.6 for realistic style. For more information, visit https://github.com/scraed/LanPaint",
|
||||
"🖼️ Image Inpainting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 65,
|
||||
"type": "VAEEncode",
|
||||
"pos": [
|
||||
200.1034698486328,
|
||||
776.3561401367188
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pixels",
|
||||
"type": "IMAGE",
|
||||
"link": 188
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 203
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
216
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEEncode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 48,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1075.49169921875,
|
||||
1167.2703857421875
|
||||
],
|
||||
"size": [
|
||||
311.2532653808594,
|
||||
484.7096252441406
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 103
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 81,
|
||||
"type": "LanPaint_MaskBlend",
|
||||
"pos": [
|
||||
1773.0189208984375,
|
||||
1222.9478759765625
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image1",
|
||||
"type": "IMAGE",
|
||||
"link": 219
|
||||
},
|
||||
{
|
||||
"name": "image2",
|
||||
"type": "IMAGE",
|
||||
"link": 218
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 220
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
217
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "4d3d5d17f0105b673df92da5b084cce567c9c712",
|
||||
"Node name for S&R": "LanPaint_MaskBlend"
|
||||
},
|
||||
"widgets_values": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 82,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
2106.45166015625,
|
||||
1090.682861328125
|
||||
],
|
||||
"size": [
|
||||
311.2532653808594,
|
||||
484.7096252441406
|
||||
],
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 217
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1211.46484375,
|
||||
1065.318359375
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 187
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 200
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
103,
|
||||
218
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
45.954593658447266,
|
||||
1150.45556640625
|
||||
],
|
||||
"size": [
|
||||
266.13720703125,
|
||||
487.1314697265625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
188,
|
||||
219
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
189,
|
||||
220
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.27",
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"clipspace/clipspace-mask-8865503.5.png [input]",
|
||||
"image"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
103,
|
||||
8,
|
||||
0,
|
||||
48,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
186,
|
||||
66,
|
||||
0,
|
||||
73,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
187,
|
||||
73,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
188,
|
||||
75,
|
||||
0,
|
||||
65,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
189,
|
||||
75,
|
||||
1,
|
||||
66,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
194,
|
||||
77,
|
||||
1,
|
||||
78,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
195,
|
||||
78,
|
||||
0,
|
||||
79,
|
||||
0,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
196,
|
||||
77,
|
||||
1,
|
||||
80,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
197,
|
||||
77,
|
||||
0,
|
||||
73,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
200,
|
||||
77,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
203,
|
||||
77,
|
||||
2,
|
||||
65,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
207,
|
||||
79,
|
||||
0,
|
||||
73,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
210,
|
||||
80,
|
||||
0,
|
||||
73,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
216,
|
||||
65,
|
||||
0,
|
||||
66,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
217,
|
||||
81,
|
||||
0,
|
||||
82,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
218,
|
||||
8,
|
||||
0,
|
||||
81,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
219,
|
||||
75,
|
||||
0,
|
||||
81,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
220,
|
||||
75,
|
||||
1,
|
||||
81,
|
||||
2,
|
||||
"MASK"
|
||||
]
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Mask image for inpainting.",
|
||||
"bounding": [
|
||||
36.04227828979492,
|
||||
989.7313232421875,
|
||||
278.89093017578125,
|
||||
669.3414916992188
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Convert Latents for LanPaint",
|
||||
"bounding": [
|
||||
286.0640563964844,
|
||||
714.343505859375,
|
||||
489.16796875,
|
||||
197.81044006347656
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Load Model and Set Prompts",
|
||||
"bounding": [
|
||||
-78.9311294555664,
|
||||
176.08712768554688,
|
||||
1006.1721801757812,
|
||||
514.258544921875
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Inpaint with the LanPaint KSampler",
|
||||
"bounding": [
|
||||
960.8922729492188,
|
||||
179.17588806152344,
|
||||
474.8909606933594,
|
||||
630.4742431640625
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "LanPaint OutPut",
|
||||
"bounding": [
|
||||
1085.6029052734375,
|
||||
994.0775756835938,
|
||||
345.4561767578125,
|
||||
669.4969482421875
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"title": "LanPaint",
|
||||
"bounding": [
|
||||
-262.59381103515625,
|
||||
140.46656799316406,
|
||||
1737.328857421875,
|
||||
797.4443359375
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
}
|
||||
],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.35049389948139237,
|
||||
"offset": [
|
||||
348.866804381099,
|
||||
308.65057628971834
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.27.10",
|
||||
"node_versions": {
|
||||
"comfy-core": "0.3.18",
|
||||
"LanPaint": "0f509469ed2cd60c6032f739e282aad5dfc06166"
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
After Width: | Height: | Size: 670 KiB |
|
After Width: | Height: | Size: 674 KiB |
|
After Width: | Height: | Size: 674 KiB |
|
After Width: | Height: | Size: 921 KiB |
@@ -0,0 +1,806 @@
|
||||
{
|
||||
"id": "11cce4ab-536b-4f42-a95c-0be437d04ace",
|
||||
"revision": 0,
|
||||
"last_node_id": 128,
|
||||
"last_link_id": 338,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 74,
|
||||
"type": "LanPaint_KSampler",
|
||||
"pos": [
|
||||
276.219970703125,
|
||||
179.55892944335938
|
||||
],
|
||||
"size": [
|
||||
388.97625732421875,
|
||||
572
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 325
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 323
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 324
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 332
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
334
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "56bd6c04e89124cd06682b304245d6ddf8b20522",
|
||||
"Node name for S&R": "LanPaint_KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed",
|
||||
20,
|
||||
4,
|
||||
"euler",
|
||||
"simple",
|
||||
1,
|
||||
5,
|
||||
"Image First",
|
||||
"LanPaint KSampler. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 113,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
807.1268310546875,
|
||||
868.395263671875
|
||||
],
|
||||
"size": [
|
||||
311.2532653808594,
|
||||
484.7096252441406
|
||||
],
|
||||
"flags": {},
|
||||
"order": 13,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 338
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 117,
|
||||
"type": "CLIPLoader",
|
||||
"pos": [
|
||||
-824.4296875,
|
||||
177.9814910888672
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
110
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
318,
|
||||
319
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "CLIPLoader",
|
||||
"models": [
|
||||
{
|
||||
"name": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||
"directory": "text_encoders"
|
||||
}
|
||||
],
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||
"qwen_image",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 118,
|
||||
"type": "VAELoader",
|
||||
"pos": [
|
||||
-824.4296875,
|
||||
327.9817199707031
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
60
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
329,
|
||||
335
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "VAELoader",
|
||||
"models": [
|
||||
{
|
||||
"name": "qwen_image_vae.safetensors",
|
||||
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors",
|
||||
"directory": "vae"
|
||||
}
|
||||
],
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"qwen_image_vae.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 121,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
-454.4298095703125,
|
||||
247.9816436767578
|
||||
],
|
||||
"size": [
|
||||
425.27801513671875,
|
||||
180.6060791015625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 319
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
324
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Negative Prompt)",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "CLIPTextEncode",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
" low quality, bad anatomy, extra digits, missing digits, extra limbs, missing limbs"
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 122,
|
||||
"type": "ModelSamplingAuraFlow",
|
||||
"pos": [
|
||||
-34.14249038696289,
|
||||
-43.64523696899414
|
||||
],
|
||||
"size": [
|
||||
300,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 320
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
325
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "ModelSamplingAuraFlow",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
3.5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 119,
|
||||
"type": "UNETLoader",
|
||||
"pos": [
|
||||
-824.4296875,
|
||||
37.98154830932617
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
90
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
320
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "UNETLoader",
|
||||
"models": [
|
||||
{
|
||||
"name": "qwen_image_fp8_e4m3fn.safetensors",
|
||||
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_fp8_e4m3fn.safetensors",
|
||||
"directory": "diffusion_models"
|
||||
}
|
||||
],
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"qwen_image_fp8_e4m3fn.safetensors",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 124,
|
||||
"type": "VAEEncode",
|
||||
"pos": [
|
||||
-530.8583984375,
|
||||
708.7066650390625
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pixels",
|
||||
"type": "IMAGE",
|
||||
"link": 326
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 329
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
327
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEEncode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 125,
|
||||
"type": "SetLatentNoiseMask",
|
||||
"pos": [
|
||||
-234.4196014404297,
|
||||
705.1629638671875
|
||||
],
|
||||
"size": [
|
||||
264.5999755859375,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 327
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 328
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
332
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "SetLatentNoiseMask"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 127,
|
||||
"type": "LanPaint_MaskBlend",
|
||||
"pos": [
|
||||
405.3840637207031,
|
||||
938.8120727539062
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image1",
|
||||
"type": "IMAGE",
|
||||
"link": 336
|
||||
},
|
||||
{
|
||||
"name": "image2",
|
||||
"type": "IMAGE",
|
||||
"link": 333
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 337
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
338
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "4d3d5d17f0105b673df92da5b084cce567c9c712",
|
||||
"Node name for S&R": "LanPaint_MaskBlend"
|
||||
},
|
||||
"widgets_values": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 126,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
115.07575225830078,
|
||||
878.4630737304688
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 334
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 335
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
333
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 123,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
-543.5358276367188,
|
||||
851.759765625
|
||||
],
|
||||
"size": [
|
||||
262.12347412109375,
|
||||
487.22296142578125
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
326,
|
||||
336
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"slot_index": 1,
|
||||
"links": [
|
||||
328,
|
||||
337
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"Masked_Load_Me_in_Loader (7).png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 120,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
-454.86480712890625,
|
||||
41.89194869995117
|
||||
],
|
||||
"size": [
|
||||
422.84503173828125,
|
||||
164.31304931640625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 318
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
323
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Positive Prompt)",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "CLIPTextEncode",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"Cyberpunk-style Einstein portrait: He wears a sleek black coat with glowing cyan circuit patterns, silver-rimmed cybernetic glasses (lenses display faint data streams), and his hair has subtle neon blue highlights. His expression is calm, with a faint smile. Behind him: a dark, rain-washed cybercity backdrop—towering skyscrapers with flickering holographic ads, wet pavement reflecting neon pink/magenta lights. In front of him: giant, glowing white 3D text of \"LanPaint\", with electric blue energy pulses swirling around the equation. Cinematic lighting, hyper-detailed textures, rain droplets visible in the air."
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 128,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [
|
||||
715.929931640625,
|
||||
371.1071472167969
|
||||
],
|
||||
"size": [
|
||||
300,
|
||||
190
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "KSampler settings",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Decrease **LanPaint_NumSteps** for faster generation. \n"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
318,
|
||||
117,
|
||||
0,
|
||||
120,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
319,
|
||||
117,
|
||||
0,
|
||||
121,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
320,
|
||||
119,
|
||||
0,
|
||||
122,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
323,
|
||||
120,
|
||||
0,
|
||||
74,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
324,
|
||||
121,
|
||||
0,
|
||||
74,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
325,
|
||||
122,
|
||||
0,
|
||||
74,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
326,
|
||||
123,
|
||||
0,
|
||||
124,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
327,
|
||||
124,
|
||||
0,
|
||||
125,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
328,
|
||||
123,
|
||||
1,
|
||||
125,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
329,
|
||||
118,
|
||||
0,
|
||||
124,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
332,
|
||||
125,
|
||||
0,
|
||||
74,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
333,
|
||||
126,
|
||||
0,
|
||||
127,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
334,
|
||||
74,
|
||||
0,
|
||||
126,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
335,
|
||||
118,
|
||||
0,
|
||||
126,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
336,
|
||||
123,
|
||||
0,
|
||||
127,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
337,
|
||||
123,
|
||||
1,
|
||||
127,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
338,
|
||||
127,
|
||||
0,
|
||||
113,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.7162766973052638,
|
||||
"offset": [
|
||||
1084.0595529886727,
|
||||
5.084234529384386
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.25.10",
|
||||
"node_versions": {
|
||||
"comfy-core": "0.3.18",
|
||||
"LanPaint": "0f509469ed2cd60c6032f739e282aad5dfc06166"
|
||||
},
|
||||
"groupNodes": {}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
After Width: | Height: | Size: 810 KiB |
@@ -0,0 +1,909 @@
|
||||
{
|
||||
"id": "11cce4ab-536b-4f42-a95c-0be437d04ace",
|
||||
"revision": 0,
|
||||
"last_node_id": 136,
|
||||
"last_link_id": 351,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 74,
|
||||
"type": "LanPaint_KSampler",
|
||||
"pos": [
|
||||
276.219970703125,
|
||||
179.55892944335938
|
||||
],
|
||||
"size": [
|
||||
388.97625732421875,
|
||||
572
|
||||
],
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 336
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 334
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 335
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 345
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
347
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "56bd6c04e89124cd06682b304245d6ddf8b20522",
|
||||
"Node name for S&R": "LanPaint_KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed",
|
||||
20,
|
||||
4,
|
||||
"euler",
|
||||
"simple",
|
||||
1,
|
||||
5,
|
||||
"Image First",
|
||||
"LanPaint KSampler. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 113,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
807.1268310546875,
|
||||
868.395263671875
|
||||
],
|
||||
"size": [
|
||||
311.2532653808594,
|
||||
484.7096252441406
|
||||
],
|
||||
"flags": {},
|
||||
"order": 15,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 351
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 123,
|
||||
"type": "CLIPLoader",
|
||||
"pos": [
|
||||
-730.1405029296875,
|
||||
183.70140075683594
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
110
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
329,
|
||||
330
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "CLIPLoader",
|
||||
"models": [
|
||||
{
|
||||
"name": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||
"directory": "text_encoders"
|
||||
}
|
||||
],
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||
"qwen_image",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 124,
|
||||
"type": "VAELoader",
|
||||
"pos": [
|
||||
-730.1405029296875,
|
||||
333.70147705078125
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
60
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
342,
|
||||
348
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "VAELoader",
|
||||
"models": [
|
||||
{
|
||||
"name": "qwen_image_vae.safetensors",
|
||||
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors",
|
||||
"directory": "vae"
|
||||
}
|
||||
],
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"qwen_image_vae.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 125,
|
||||
"type": "UNETLoader",
|
||||
"pos": [
|
||||
-730.1405029296875,
|
||||
43.7014274597168
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
90
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
331
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "UNETLoader",
|
||||
"models": [
|
||||
{
|
||||
"name": "qwen_image_fp8_e4m3fn.safetensors",
|
||||
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_fp8_e4m3fn.safetensors",
|
||||
"directory": "diffusion_models"
|
||||
}
|
||||
],
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"qwen_image_fp8_e4m3fn.safetensors",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 127,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
-360.1405029296875,
|
||||
253.70147705078125
|
||||
],
|
||||
"size": [
|
||||
425.27801513671875,
|
||||
180.6060791015625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 330
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
335
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Negative Prompt)",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "CLIPTextEncode",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
" low quality, bad anatomy, extra digits, missing digits, extra limbs, missing limbs"
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 128,
|
||||
"type": "ModelSamplingAuraFlow",
|
||||
"pos": [
|
||||
60.14683151245117,
|
||||
-37.92536544799805
|
||||
],
|
||||
"size": [
|
||||
300,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 331
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
336
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "ModelSamplingAuraFlow",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
3.5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 126,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
-360.57550048828125,
|
||||
47.6118278503418
|
||||
],
|
||||
"size": [
|
||||
422.84503173828125,
|
||||
164.31304931640625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 329
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
334
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Positive Prompt)",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.48",
|
||||
"Node name for S&R": "CLIPTextEncode",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"Cyberpunk-inspired portrait of a beautiful young woman with ethereal features: She has long, flowing silver hair with glowing purple neon streaks, wearing a form-fitting black leather jacket adorned with holographic circuit designs in electric blue, and augmented reality earrings that project faint digital fractals. Her eyes are piercing emerald green with subtle cybernetic enhancements showing data overlays, and her expression is mysterious yet alluring, with a subtle smirk. Behind her: a foggy, neon-lit futuristic alleyway—crumbling brick walls covered in vibrant graffiti and flickering LED signs, puddles on the ground reflecting turquoise and violet lights from overhead drones. Dramatic volumetric lighting, ultra-realistic details, mist particles in the air."
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 130,
|
||||
"type": "ImagePadForOutpaint",
|
||||
"pos": [
|
||||
-437.0110168457031,
|
||||
895.0103759765625
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
174
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 337
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
338,
|
||||
349
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
339
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.39",
|
||||
"Node name for S&R": "ImagePadForOutpaint",
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
200,
|
||||
200,
|
||||
200,
|
||||
200,
|
||||
20
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 131,
|
||||
"type": "VAEEncode",
|
||||
"pos": [
|
||||
-455.7289123535156,
|
||||
723.4658203125
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pixels",
|
||||
"type": "IMAGE",
|
||||
"link": 338
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 342
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
340
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEEncode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 132,
|
||||
"type": "ThresholdMask",
|
||||
"pos": [
|
||||
-67.46508026123047,
|
||||
903.83642578125
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 339
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
341,
|
||||
350
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.38",
|
||||
"Node name for S&R": "ThresholdMask"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.010000000000000002
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 133,
|
||||
"type": "SetLatentNoiseMask",
|
||||
"pos": [
|
||||
-152.71241760253906,
|
||||
712.6437377929688
|
||||
],
|
||||
"size": [
|
||||
264.5999755859375,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 340
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 341
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
345
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "SetLatentNoiseMask"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 129,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
-789.0392456054688,
|
||||
827.515380859375
|
||||
],
|
||||
"size": [
|
||||
295,
|
||||
399
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
337
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.27",
|
||||
"Node name for S&R": "LoadImage",
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI_07699_.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 134,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
256.8516540527344,
|
||||
900.2234497070312
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 13,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 347
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 348
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
346
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 135,
|
||||
"type": "LanPaint_MaskBlend",
|
||||
"pos": [
|
||||
547.1599731445312,
|
||||
960.5724487304688
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image1",
|
||||
"type": "IMAGE",
|
||||
"link": 349
|
||||
},
|
||||
{
|
||||
"name": "image2",
|
||||
"type": "IMAGE",
|
||||
"link": 346
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 350
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
351
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "4d3d5d17f0105b673df92da5b084cce567c9c712",
|
||||
"Node name for S&R": "LanPaint_MaskBlend"
|
||||
},
|
||||
"widgets_values": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 136,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [
|
||||
728.9194946289062,
|
||||
332.5254821777344
|
||||
],
|
||||
"size": [
|
||||
300,
|
||||
190
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "KSampler settings",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Decrease **LanPaint_NumSteps** for faster generation. \n"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
329,
|
||||
123,
|
||||
0,
|
||||
126,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
330,
|
||||
123,
|
||||
0,
|
||||
127,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
331,
|
||||
125,
|
||||
0,
|
||||
128,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
334,
|
||||
126,
|
||||
0,
|
||||
74,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
335,
|
||||
127,
|
||||
0,
|
||||
74,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
336,
|
||||
128,
|
||||
0,
|
||||
74,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
337,
|
||||
129,
|
||||
0,
|
||||
130,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
338,
|
||||
130,
|
||||
0,
|
||||
131,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
339,
|
||||
130,
|
||||
1,
|
||||
132,
|
||||
0,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
340,
|
||||
131,
|
||||
0,
|
||||
133,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
341,
|
||||
132,
|
||||
0,
|
||||
133,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
342,
|
||||
124,
|
||||
0,
|
||||
131,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
345,
|
||||
133,
|
||||
0,
|
||||
74,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
346,
|
||||
134,
|
||||
0,
|
||||
135,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
347,
|
||||
74,
|
||||
0,
|
||||
134,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
348,
|
||||
124,
|
||||
0,
|
||||
134,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
349,
|
||||
130,
|
||||
0,
|
||||
135,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
350,
|
||||
132,
|
||||
0,
|
||||
135,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
351,
|
||||
135,
|
||||
0,
|
||||
113,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.6087272163919795,
|
||||
"offset": [
|
||||
1617.0504979084035,
|
||||
167.0583828525509
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.25.10",
|
||||
"node_versions": {
|
||||
"comfy-core": "0.3.18",
|
||||
"LanPaint": "0f509469ed2cd60c6032f739e282aad5dfc06166"
|
||||
},
|
||||
"groupNodes": {}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,735 @@
|
||||
{
|
||||
"id": "26fb90cb-eb4a-422e-97d0-8b84dd6c3302",
|
||||
"revision": 0,
|
||||
"last_node_id": 75,
|
||||
"last_link_id": 192,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
333.06903076171875,
|
||||
249.68698120117188
|
||||
],
|
||||
"size": [
|
||||
422.84503173828125,
|
||||
164.31304931640625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 81
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
184
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"1girl, blue shirt, masterpiece, high score, great score, absurdres"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
335.06903076171875,
|
||||
462.68701171875
|
||||
],
|
||||
"size": [
|
||||
425.27801513671875,
|
||||
180.6060791015625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 82
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
185
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"lowres, bad anatomy, bad hands, text, error, missing finger, extra digits, fewer digits, cropped, worst quality, low quality, low score, bad score, average score, signature, watermark, username, blurry, nude, NSFW"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
-62.627220153808594,
|
||||
407.01416015625
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
183
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"slot_index": 1,
|
||||
"links": [
|
||||
81,
|
||||
82
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 2,
|
||||
"links": [
|
||||
84,
|
||||
157
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"animagineXL40_v4Opt.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 48,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1091.036376953125,
|
||||
1158.526611328125
|
||||
],
|
||||
"size": [
|
||||
311.2532653808594,
|
||||
484.7096252441406
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 103
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1211.46484375,
|
||||
1065.318359375
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 187
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 84
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
103,
|
||||
189
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
45.70227813720703,
|
||||
1147.2928466796875
|
||||
],
|
||||
"size": [
|
||||
262.12347412109375,
|
||||
487.22296142578125
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
156,
|
||||
190
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"slot_index": 1,
|
||||
"links": [
|
||||
155,
|
||||
191
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"clipspace/clipspace-mask-2620525.399999976.png [input]",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1845.7059326171875,
|
||||
1044.06201171875
|
||||
],
|
||||
"size": [
|
||||
311.2532653808594,
|
||||
484.7096252441406
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 188
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 73,
|
||||
"type": "LanPaint_KSampler",
|
||||
"pos": [
|
||||
996.4982299804688,
|
||||
299.599365234375
|
||||
],
|
||||
"size": [
|
||||
413.6495666503906,
|
||||
572
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 183
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 184
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 185
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 186
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
187
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "56bd6c04e89124cd06682b304245d6ddf8b20522",
|
||||
"Node name for S&R": "LanPaint_KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed",
|
||||
30,
|
||||
5,
|
||||
"euler",
|
||||
"karras",
|
||||
1,
|
||||
5,
|
||||
"Image First",
|
||||
"LanPaint KSampler. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 74,
|
||||
"type": "LanPaint_MaskBlend",
|
||||
"pos": [
|
||||
1512.2730712890625,
|
||||
1176.3270263671875
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image1",
|
||||
"type": "IMAGE",
|
||||
"link": 190
|
||||
},
|
||||
{
|
||||
"name": "image2",
|
||||
"type": "IMAGE",
|
||||
"link": 189
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 191
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
188
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "LanPaint",
|
||||
"ver": "4d3d5d17f0105b673df92da5b084cce567c9c712",
|
||||
"Node name for S&R": "LanPaint_MaskBlend"
|
||||
},
|
||||
"widgets_values": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 66,
|
||||
"type": "SetLatentNoiseMask",
|
||||
"pos": [
|
||||
480.30780029296875,
|
||||
821.3880004882812
|
||||
],
|
||||
"size": [
|
||||
264.5999755859375,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 192
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 155
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
186
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "SetLatentNoiseMask"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 65,
|
||||
"type": "VAEEncode",
|
||||
"pos": [
|
||||
206.43878173828125,
|
||||
818.9985961914062
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pixels",
|
||||
"type": "IMAGE",
|
||||
"link": 156
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 157
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
192
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.23",
|
||||
"Node name for S&R": "VAEEncode"
|
||||
},
|
||||
"widgets_values": []
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
81,
|
||||
29,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
82,
|
||||
29,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
84,
|
||||
29,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
103,
|
||||
8,
|
||||
0,
|
||||
48,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
155,
|
||||
20,
|
||||
1,
|
||||
66,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
156,
|
||||
20,
|
||||
0,
|
||||
65,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
157,
|
||||
29,
|
||||
2,
|
||||
65,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
183,
|
||||
29,
|
||||
0,
|
||||
73,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
184,
|
||||
6,
|
||||
0,
|
||||
73,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
185,
|
||||
7,
|
||||
0,
|
||||
73,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
186,
|
||||
66,
|
||||
0,
|
||||
73,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
187,
|
||||
73,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
188,
|
||||
74,
|
||||
0,
|
||||
75,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
189,
|
||||
8,
|
||||
0,
|
||||
74,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
190,
|
||||
20,
|
||||
0,
|
||||
74,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
191,
|
||||
20,
|
||||
1,
|
||||
74,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
192,
|
||||
65,
|
||||
0,
|
||||
66,
|
||||
0,
|
||||
"LATENT"
|
||||
]
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Mask image for inpainting.",
|
||||
"bounding": [
|
||||
36.04227828979492,
|
||||
989.7313232421875,
|
||||
278.89093017578125,
|
||||
669.3414916992188
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Convert Latents for LanPaint",
|
||||
"bounding": [
|
||||
286.0640563964844,
|
||||
714.343505859375,
|
||||
489.16796875,
|
||||
197.81044006347656
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Load Model and Set Prompts",
|
||||
"bounding": [
|
||||
-78.9311294555664,
|
||||
176.08712768554688,
|
||||
1006.1721801757812,
|
||||
514.258544921875
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Inpaint with the LanPaint KSampler",
|
||||
"bounding": [
|
||||
960.8922729492188,
|
||||
179.17588806152344,
|
||||
474.8909606933594,
|
||||
630.4742431640625
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "LanPaint OutPut",
|
||||
"bounding": [
|
||||
1085.6029052734375,
|
||||
994.0775756835938,
|
||||
345.4561767578125,
|
||||
669.4969482421875
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"title": "LanPaint",
|
||||
"bounding": [
|
||||
-262.59381103515625,
|
||||
140.46656799316406,
|
||||
1737.328857421875,
|
||||
797.4443359375
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"title": "Paste back the original to preserve it exactly, if you want",
|
||||
"bounding": [
|
||||
1491.586181640625,
|
||||
984.3547973632812,
|
||||
749.66455078125,
|
||||
637.360595703125
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
}
|
||||
],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.6209213230591556,
|
||||
"offset": [
|
||||
850.0803535605011,
|
||||
86.6432096141053
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.25.10",
|
||||
"node_versions": {
|
||||
"comfy-core": "0.3.18",
|
||||
"LanPaint": "0f509469ed2cd60c6032f739e282aad5dfc06166"
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 683 KiB |
|
After Width: | Height: | Size: 687 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 830 KiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1012 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 301 KiB |
|
After Width: | Height: | Size: 461 KiB |
|
After Width: | Height: | Size: 4.1 MiB |
|
After Width: | Height: | Size: 5.8 MiB |
|
After Width: | Height: | Size: 292 KiB |
|
After Width: | Height: | Size: 399 KiB |
|
After Width: | Height: | Size: 801 KiB |
|
After Width: | Height: | Size: 551 KiB |
|
After Width: | Height: | Size: 6.2 MiB |
|
After Width: | Height: | Size: 4.8 MiB |
|
After Width: | Height: | Size: 4.1 MiB |
|
After Width: | Height: | Size: 8.5 MiB |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "LanPaint"
|
||||
version = "1.0.2"
|
||||
version = "1.4.9"
|
||||
description = "Achieve seamless inpainting results without needing a specialized inpainting model."
|
||||
authors = [
|
||||
{name = "LanPaint", email = "czhengac@connect.ust.hk"}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import torch
|
||||
from .utils import *
|
||||
from functools import partial
|
||||
|
||||
class LanPaint():
|
||||
def __init__(self, Model, NSteps, Friction, Lambda, Beta, StepSize, IS_FLUX = False, IS_FLOW = False):
|
||||
self.n_steps = NSteps
|
||||
@@ -11,10 +12,22 @@ class LanPaint():
|
||||
self.inner_model = Model
|
||||
self.friction = Friction
|
||||
self.chara_beta = Beta
|
||||
|
||||
self.img_dim_size = None
|
||||
|
||||
def add_none_dims(self, array):
|
||||
# Create a tuple with ':' for the first dimension and 'None' repeated num_nones times
|
||||
index = (slice(None),) + (None,) * (self.img_dim_size-1)
|
||||
return array[index]
|
||||
def remove_none_dims(self, array):
|
||||
# Create a tuple with ':' for the first dimension and 'None' repeated num_nones times
|
||||
index = (slice(None),) + (0,) * (self.img_dim_size-1)
|
||||
return array[index]
|
||||
def __call__(self, x, latent_image, noise, sigma, latent_mask, current_times, model_options, seed, n_steps=None):
|
||||
self.img_dim_size = len(x.shape)
|
||||
self.latent_image = latent_image
|
||||
self.noise = noise
|
||||
if torch.mean(torch.abs(self.noise)) < 1e-8:
|
||||
self.noise = torch.randn_like(self.noise)
|
||||
if n_steps is None:
|
||||
n_steps = self.n_steps
|
||||
return self.LanPaint(x, sigma, latent_mask, current_times, n_steps, model_options, seed, self.IS_FLUX, self.IS_FLOW)
|
||||
@@ -23,26 +36,31 @@ class LanPaint():
|
||||
|
||||
|
||||
step_size = self.step_size * (1 - abt)
|
||||
step_size = step_size[:, None, None, None]
|
||||
step_size = self.add_none_dims(step_size)
|
||||
# self.inner_model.inner_model.scale_latent_inpaint returns variance exploding x_t values
|
||||
# This is the replace step
|
||||
x = x * (1 - latent_mask) + self.inner_model.inner_model.scale_latent_inpaint(x=x, sigma=sigma, noise=self.noise, latent_image=self.latent_image)* latent_mask
|
||||
def scale_latent_inpaint(x, sigma, noise, latent_image):
|
||||
return self.inner_model.inner_model.model_sampling.noise_scaling(sigma.reshape([sigma.shape[0]] + [1] * (len(noise.shape) - 1)), noise, latent_image)
|
||||
|
||||
x = x * (1 - latent_mask) + scale_latent_inpaint(x=x, sigma=sigma, noise=self.noise, latent_image=self.latent_image)* latent_mask
|
||||
|
||||
|
||||
|
||||
if IS_FLUX or IS_FLOW:
|
||||
x_t = x * ( abt[:, None,None,None]**0.5 + (1-abt[:, None,None,None])**0.5 )
|
||||
x_t = x * ( self.add_none_dims(abt)**0.5 + (1-self.add_none_dims(abt))**0.5 )
|
||||
else:
|
||||
x_t = x / ( 1+VE_Sigma[:, None,None,None]**2 )**0.5 # switch to variance perserving x_t values
|
||||
x_t = x / ( 1+self.add_none_dims(VE_Sigma)**2 )**0.5 # switch to variance perserving x_t values
|
||||
|
||||
############ LanPaint Iterations Start ###############
|
||||
# after noise_scaling, noise = latent_image + noise * sigma, which is x_t in the variance exploding diffusion model notation for the known region.
|
||||
args = None
|
||||
for i in range(n_steps):
|
||||
score_func = partial( self.score_model, y = self.latent_image, mask = latent_mask, abt = abt[:, None,None,None], sigma = VE_Sigma[:, None,None,None], tflow = Flow_t[:, None,None,None], model_options = model_options, seed = seed )
|
||||
x_t, args = self.langevin_dynamics(x_t, score_func , latent_mask, step_size , current_times, sigma_x = self.sigma_x(abt)[:, None,None,None], sigma_y = self.sigma_y(abt)[:, None,None,None], args = args)
|
||||
score_func = partial( self.score_model, y = self.latent_image, mask = latent_mask, abt = self.add_none_dims(abt), sigma = self.add_none_dims(VE_Sigma), tflow = self.add_none_dims(Flow_t), model_options = model_options, seed = seed )
|
||||
x_t, args = self.langevin_dynamics(x_t, score_func , latent_mask, step_size , current_times, sigma_x = self.add_none_dims(self.sigma_x(abt)), sigma_y = self.add_none_dims(self.sigma_y(abt)), args = args)
|
||||
if IS_FLUX or IS_FLOW:
|
||||
x = x_t / ( abt[:, None,None,None]**0.5 + (1-abt[:, None,None,None])**0.5 )
|
||||
x = x_t / ( self.add_none_dims(abt)**0.5 + (1-self.add_none_dims(abt))**0.5 )
|
||||
else:
|
||||
x = x_t * ( 1+VE_Sigma[:, None,None,None]**2 )**0.5 # switch to variance perserving x_t values
|
||||
x = x_t * ( 1+self.add_none_dims(VE_Sigma)**2 )**0.5 # switch to variance perserving x_t values
|
||||
############ LanPaint Iterations End ###############
|
||||
# out is x_0
|
||||
out, _ = self.inner_model(x, sigma, model_options=model_options, seed=seed)
|
||||
@@ -52,14 +70,13 @@ class LanPaint():
|
||||
def score_model(self, x_t, y, mask, abt, sigma, tflow, model_options, seed):
|
||||
|
||||
lamb = self.chara_lamb
|
||||
|
||||
if self.IS_FLUX or self.IS_FLOW:
|
||||
# compute t for flow model, with a small epsilon compensating for numerical error.
|
||||
x = x_t / ( abt**0.5 + (1-abt)**0.5 ) # switch to Gaussian flow matching
|
||||
x_0, x_0_BIG = self.inner_model(x, tflow[:, 0,0,0], model_options=model_options, seed=seed)
|
||||
x_0, x_0_BIG = self.inner_model(x, self.remove_none_dims(tflow), model_options=model_options, seed=seed)
|
||||
else:
|
||||
x = x_t * ( 1+sigma**2 )**0.5 # switch to variance exploding
|
||||
x_0, x_0_BIG = self.inner_model(x, sigma[:, 0,0,0], model_options=model_options, seed=seed)
|
||||
x_0, x_0_BIG = self.inner_model(x, self.remove_none_dims(sigma), model_options=model_options, seed=seed)
|
||||
|
||||
score_x = -(x_t - x_0)
|
||||
score_y = - (1 + lamb) * ( x_t - y ) + lamb * (x_t - x_0_BIG)
|
||||
@@ -82,33 +99,52 @@ class LanPaint():
|
||||
# -------------------------------------------------------------------------
|
||||
# Compute the Langevin dynamics update in variance perserving notation
|
||||
# -------------------------------------------------------------------------
|
||||
x0 = self.x0_evalutation(x_t, score, sigma, args)
|
||||
C = abt**0.5 * x0 / (1-abt)
|
||||
#x0 = self.x0_evalutation(x_t, score, sigma, args)
|
||||
#C = abt**0.5 * x0 / (1-abt)
|
||||
A = A_x * (1-mask) + A_y * mask
|
||||
D = D_x * (1-mask) + D_y * mask
|
||||
dt = dtx * (1-mask) + dty * mask
|
||||
Gamma = Gamma_x * (1-mask) + Gamma_y * mask
|
||||
|
||||
|
||||
|
||||
def Coef_C(x_t):
|
||||
x0 = self.x0_evalutation(x_t, score, sigma, args)
|
||||
C = (abt**0.5 * x0 - x_t )/ (1-abt) + A * x_t
|
||||
return C
|
||||
def advance_time(x_t, v, dt, Gamma, A, C, D):
|
||||
dtype = x_t.dtype
|
||||
with torch.autocast(device_type=x_t.device.type, dtype=torch.float32):
|
||||
osc = StochasticHarmonicOscillator(Gamma, A, C, D )
|
||||
x_t, v = osc.dynamics(x_t, v, dt )
|
||||
x_t = x_t.to(dtype)
|
||||
v = v.to(dtype)
|
||||
return x_t, v
|
||||
if args is None:
|
||||
#v = torch.zeros_like(x_t)
|
||||
v = None
|
||||
C = Coef_C(x_t)
|
||||
#print(torch.squeeze(dtx), torch.squeeze(dty))
|
||||
x_t, v = advance_time(x_t, v, dt, Gamma, A, C, D)
|
||||
else:
|
||||
v, = args
|
||||
v, C = args
|
||||
|
||||
with torch.autocast(device_type=x_t.device.type, dtype=torch.float32):
|
||||
osc = StochasticHarmonicOscillator(Gamma, A, C, D )
|
||||
x_t, v = osc.dynamics(x_t, v, dt )
|
||||
x_t, v = advance_time(x_t, v, dt/2, Gamma, A, C, D)
|
||||
|
||||
C_new = Coef_C(x_t)
|
||||
v = v + Gamma**0.5 * ( C_new - C) *dt
|
||||
|
||||
x_t, v = advance_time(x_t, v, dt/2, Gamma, A, C, D)
|
||||
|
||||
C = C_new
|
||||
|
||||
return x_t, (v,)
|
||||
return x_t, (v, C)
|
||||
|
||||
def prepare_step_size(self, current_times, step_size, sigma_x, sigma_y):
|
||||
# -------------------------------------------------------------------------
|
||||
# Unpack current times parameters (sigma and abt)
|
||||
sigma, abt, flow_t = current_times
|
||||
sigma = sigma[:, None,None,None]
|
||||
abt = abt[:, None,None,None]
|
||||
sigma = self.add_none_dims(sigma)
|
||||
abt = self.add_none_dims(abt)
|
||||
# Compute time step (dtx, dty) for x and y branches.
|
||||
dtx = 2 * step_size * sigma_x
|
||||
dty = 2 * step_size * sigma_y
|
||||
@@ -123,9 +159,9 @@ class LanPaint():
|
||||
# adjust dt to match denoise-addnoise steps sizes
|
||||
Gamma_hat_x /= 2.
|
||||
Gamma_hat_y /= 2.
|
||||
|
||||
A_t_x = (1) / ( 1 - abt ) * dtx / 2
|
||||
A_t_y = (1) / ( 1 - abt ) * dty / 2
|
||||
A_t_y = (1+self.chara_lamb) / ( 1 - abt ) * dty / 2
|
||||
|
||||
|
||||
A_x = A_t_x / (dtx/2)
|
||||
A_y = A_t_y / (dty/2)
|
||||
|
||||
@@ -11,21 +11,115 @@ from comfy.samplers import *
|
||||
from comfy.model_base import ModelType
|
||||
from .utils import *
|
||||
from .lanpaint import LanPaint
|
||||
# Monkey patch comfy.samplers module by importing with absolute package path
|
||||
#exec(inspect.getsource(comfy.samplers).replace("from .", "from comfy."))
|
||||
from comfy.model_base import WAN22
|
||||
import comfyui_version
|
||||
import comfy.nested_tensor
|
||||
|
||||
def reshape_mask(input_mask, output_shape):
|
||||
def reshape_mask(input_mask, output_shape,video_inpainting=False):
|
||||
|
||||
import comfy.nested_tensor
|
||||
|
||||
# 修改这里的判断条件,不能只用 hasattr("unbind")
|
||||
if isinstance(input_mask, comfy.nested_tensor.NestedTensor):
|
||||
masks = input_mask.unbind()
|
||||
|
||||
# 如果 output_shape 也是嵌套的(通常 noise.shape 在 NestedTensor 下返回 tuple of shapes)
|
||||
if isinstance(output_shape, (list, tuple)) and len(output_shape) > 0 and not isinstance(output_shape[0], int):
|
||||
reshaped_parts = []
|
||||
for i in range(len(masks)):
|
||||
# 递归处理每一个子部分,并传入对应的子 shape
|
||||
reshaped_parts.append(reshape_mask(masks[i], output_shape[i], video_inpainting))
|
||||
return comfy.nested_tensor.NestedTensor(tuple(reshaped_parts))
|
||||
else:
|
||||
# 如果 output_shape 是单一形状(降级处理)
|
||||
return comfy.nested_tensor.NestedTensor(tuple(reshape_mask(m, output_shape, video_inpainting) for m in masks))
|
||||
|
||||
dims = len(output_shape) - 2
|
||||
|
||||
|
||||
print('output shape',output_shape)
|
||||
scale_mode = "nearest-exact"
|
||||
mask = torch.nn.functional.interpolate(input_mask, size=output_shape[2:], mode=scale_mode)
|
||||
if mask.shape[1] < output_shape[1]:
|
||||
mask = mask.repeat((1, output_shape[1]) + (1,) * dims)[:,:output_shape[1]]
|
||||
mask = repeat_to_batch_size(mask, output_shape[0])
|
||||
print('input mask',input_mask.shape,type(input_mask),torch.max(input_mask),torch.min(input_mask))
|
||||
print('target output_shape',output_shape)
|
||||
print('input_mask.ndim:', input_mask.ndim, 'output_shape len:', len(output_shape))
|
||||
|
||||
# Handle video case with temporal dimension
|
||||
# if video_inpainting: # Video case: (batch, channels, frames, height, width)
|
||||
# target_frames = output_shape[2]
|
||||
# target_height, target_width = output_shape[-2:]
|
||||
|
||||
# print('Video case - input_mask initial shape:', input_mask.shape)
|
||||
|
||||
# # First reshape input_mask to have proper dimensions for video processing
|
||||
# # Assume input is (frames, channels, height, width) -> (1, channels, frames, height, width)
|
||||
# ## if comfy version < 0.6.0
|
||||
# if comfyui_version.__version__ < "0.6.0":
|
||||
# input_mask = input_mask.permute(1, 0, 2, 3).unsqueeze(0)
|
||||
# print('Video case - input_mask after reshaping:', input_mask.shape)
|
||||
# # Ensure we have the correct 5D shape: (batch, channels, frames, height, width)
|
||||
# batch_size, channels, frames, height, width = input_mask.shape
|
||||
# print('Video case - dimensions: batch_size={}, channels={}, frames={}, height={}, width={}'.format(batch_size, channels, frames, height, width))
|
||||
# print('Video case - target size:', (target_frames, target_height, target_width))
|
||||
|
||||
# # 3D nearest-exact interpolation: (batch, channels, frames, height, width) -> (batch, channels, target_frames, target_height, target_width)
|
||||
# temp_mask = torch.nn.functional.interpolate(
|
||||
# input_mask,
|
||||
# size=(target_frames, target_height, target_width),
|
||||
# mode=scale_mode,
|
||||
# )
|
||||
|
||||
# # temp_mask is already 5D: (batch, channels, target_frames, target_height, target_width)
|
||||
# mask = temp_mask
|
||||
# print('after mask',mask.shape)
|
||||
# # Handle channel dimension expansion if needed
|
||||
# if mask.shape[1] < output_shape[1]:
|
||||
# mask = mask.repeat(1, output_shape[1], 1, 1, 1)[:, :output_shape[1]]
|
||||
# # Handle batch dimension
|
||||
# mask = repeat_to_batch_size(mask, output_shape[0])
|
||||
if video_inpainting:
|
||||
# 如果是 3D Token 序列 (LTXV 压平后的情况)
|
||||
if input_mask.ndim == 3 and len(output_shape) == 3:
|
||||
mask = torch.nn.functional.interpolate(
|
||||
input_mask,
|
||||
size=output_shape[2],
|
||||
mode=scale_mode
|
||||
)
|
||||
return mask
|
||||
|
||||
# 只有在确认为 5D 视频张量时才执行原有逻辑
|
||||
if input_mask.ndim == 5:
|
||||
target_frames = output_shape[2]
|
||||
target_height, target_width = output_shape[-2:]
|
||||
|
||||
# (这里保留你原有的 permute 和 unsqueeze 逻辑,但要确保它是针对非 5D 输入的补救)
|
||||
if input_mask.ndim < 5:
|
||||
# 假设输入是 (F, C, H, W) -> (1, C, F, H, W)
|
||||
if hasattr(comfyui_version, "__version__") and comfyui_version.__version__ < "0.6.0":
|
||||
input_mask = input_mask.permute(1, 0, 2, 3).unsqueeze(0)
|
||||
|
||||
# 现在可以安全地解包 5D 形状了
|
||||
batch_size, channels, frames, height, width = input_mask.shape
|
||||
mask = torch.nn.functional.interpolate(
|
||||
input_mask,
|
||||
size=(target_frames, target_height, target_width),
|
||||
mode=scale_mode,
|
||||
)
|
||||
|
||||
if mask.shape[1] < output_shape[1]:
|
||||
mask = mask.repeat(1, output_shape[1], 1, 1, 1)[:, :output_shape[1]]
|
||||
mask = repeat_to_batch_size(mask, output_shape[0])
|
||||
return mask
|
||||
else: # Original 2D image case
|
||||
if comfyui_version.__version__ < "0.6.0":
|
||||
mask = torch.nn.functional.interpolate(input_mask, size=output_shape[-2:], mode=scale_mode)
|
||||
else:
|
||||
mask = torch.nn.functional.interpolate(input_mask, size=output_shape[2:], mode=scale_mode)
|
||||
if mask.shape[1] < output_shape[1]:
|
||||
mask = mask.repeat((1, output_shape[1]) + (1,) * dims)[:,:output_shape[1]]
|
||||
mask = repeat_to_batch_size(mask, output_shape[0])
|
||||
|
||||
|
||||
return mask
|
||||
def prepare_mask(noise_mask, shape, device):
|
||||
return reshape_mask(noise_mask, shape).to(device)
|
||||
def prepare_mask(noise_mask, shape, device,video_inpainting=False):
|
||||
return reshape_mask(noise_mask, shape,video_inpainting).to(device)
|
||||
def sampling_function_LanPaint(model, x, timestep, uncond, cond, cond_scale, cond_scale_BIG, model_options={}, seed=None):
|
||||
if math.isclose(cond_scale, 1.0) and model_options.get("disable_cfg1_optimization", False) == False:
|
||||
uncond_ = None
|
||||
@@ -44,13 +138,18 @@ def sampling_function_LanPaint(model, x, timestep, uncond, cond, cond_scale, con
|
||||
|
||||
|
||||
class CFGGuider_LanPaint:
|
||||
def outer_sample(self, noise, latent_image, sampler, sigmas, denoise_mask=None, callback=None, disable_pbar=False, seed=None):
|
||||
def outer_sample(self, noise, latent_image, sampler, sigmas, denoise_mask=None, callback=None, disable_pbar=False, seed=None, **kwargs):
|
||||
print("CFGGuider outer_sample")
|
||||
self.inner_model, self.conds, self.loaded_models = comfy.sampler_helpers.prepare_sampling(self.model_patcher, noise.shape, self.conds, self.model_options)
|
||||
device = self.model_patcher.load_device
|
||||
|
||||
if isinstance(self.inner_model, WAN22):
|
||||
print("WAN22 detected")
|
||||
self.inner_model.extra_conds = super(WAN22, self.inner_model).extra_conds
|
||||
if denoise_mask is not None:
|
||||
denoise_mask = prepare_mask(denoise_mask, noise.shape, device)
|
||||
video_inpainting = self.model_options.get("video_inpainting", False)
|
||||
print('denoise_mask',denoise_mask.shape,type(denoise_mask))
|
||||
denoise_mask = prepare_mask(denoise_mask, noise.shape, device, video_inpainting)
|
||||
|
||||
noise = noise.to(device)
|
||||
latent_image = latent_image.to(device)
|
||||
@@ -59,7 +158,7 @@ class CFGGuider_LanPaint:
|
||||
|
||||
try:
|
||||
self.model_patcher.pre_run()
|
||||
output = self.inner_sample(noise, latent_image, device, sampler, sigmas, denoise_mask, callback, disable_pbar, seed)
|
||||
output = self.inner_sample(noise, latent_image, device, sampler, sigmas, denoise_mask, callback, disable_pbar, seed, **kwargs)
|
||||
finally:
|
||||
self.model_patcher.cleanup()
|
||||
|
||||
@@ -77,8 +176,8 @@ class KSamplerX0Inpaint:
|
||||
def __init__(self, model, sigmas):
|
||||
self.inner_model = model
|
||||
self.sigmas = sigmas
|
||||
self.model_sigmas = torch.cat( (torch.tensor([0.], device = sigmas.device) , torch.tensor( self.inner_model.model_patcher.get_model_object("model_sampling").sigmas, device = sigmas.device) ) )
|
||||
self.model_sigmas = torch.tensor( self.model_sigmas, dtype = self.sigmas.dtype )
|
||||
#self.model_sigmas = torch.cat( (torch.tensor([0.], device = sigmas.device) , torch.tensor( self.inner_model.model_patcher.get_model_object("model_sampling").sigmas, device = sigmas.device) ) )
|
||||
#self.model_sigmas = torch.tensor( self.model_sigmas, dtype = self.sigmas.dtype )
|
||||
def __call__(self, x, sigma, denoise_mask, model_options={}, seed=None,**kwargs):
|
||||
### For 1.5 and XL model
|
||||
# x is x_t in the notation of variance exploding diffusion model, x_t = x_0 + sigma * noise
|
||||
@@ -88,15 +187,15 @@ class KSamplerX0Inpaint:
|
||||
|
||||
IS_FLUX = self.inner_model.inner_model.model_type == ModelType.FLUX
|
||||
IS_FLOW = self.inner_model.inner_model.model_type == ModelType.FLOW
|
||||
|
||||
#print("model class", type(self.inner_model.inner_model))
|
||||
#print("model type", self.inner_model.inner_model.model_type, "IS_FLUX", IS_FLUX, "IS_FLOW", IS_FLOW)
|
||||
#print("sigma", torch.mean(sigma).item(), torch.min(sigma).item(), torch.max(sigma).item())
|
||||
# unify the notations into variance exploding diffusion model
|
||||
if IS_FLUX or IS_FLOW:
|
||||
Flow_t = sigma
|
||||
abt = (1 - Flow_t)**2 / ((1 - Flow_t)**2 + Flow_t**2 )
|
||||
VE_Sigma = Flow_t / (1 - Flow_t)
|
||||
#print("t", torch.mean( sigma ).item(), "VE_Sigma", torch.mean( VE_Sigma ).item())
|
||||
|
||||
|
||||
else:
|
||||
VE_Sigma = sigma
|
||||
abt = 1/( 1+VE_Sigma**2 )
|
||||
@@ -106,6 +205,31 @@ class KSamplerX0Inpaint:
|
||||
if "denoise_mask_function" in model_options:
|
||||
denoise_mask = model_options["denoise_mask_function"](sigma, denoise_mask, extra_options={"model": self.inner_model, "sigmas": self.sigmas})
|
||||
|
||||
if isinstance(denoise_mask, comfy.nested_tensor.NestedTensor):
|
||||
masks = denoise_mask.unbind()
|
||||
xs = x.unbind()
|
||||
latent_imgs = self.latent_image.unbind()
|
||||
noises = self.noise.unbind()
|
||||
|
||||
outs = []
|
||||
# 针对 LTXV,通常 i=0 是视频,i=1 是音频
|
||||
for i in range(len(xs)):
|
||||
m = (masks[i] > 0.5).float()
|
||||
lm = 1 - m
|
||||
# 这里的 PaintMethod 通常只支持普通 Tensor,所以我们分块处理
|
||||
# 注意:如果音频部分不需要 Inpaint,可以增加判断
|
||||
current_times = (VE_Sigma, abt, Flow_t)
|
||||
|
||||
# 只有视频部分 (i=0) 应用 LanPaint 逻辑,音频部分通常直接 pass 或原样返回
|
||||
if i == 0:
|
||||
out_part = self.PaintMethod(xs[i], latent_imgs[i], noises[i], sigma, lm, current_times, model_options, seed)
|
||||
else:
|
||||
# 音频部分如果没有对应的 Inpaint 逻辑,通常直接调用 inner_model
|
||||
out_part, _ = self.inner_model(xs[i], sigma, model_options=model_options, seed=seed)
|
||||
outs.append(out_part)
|
||||
|
||||
return comfy.nested_tensor.NestedTensor(tuple(outs))
|
||||
|
||||
denoise_mask = (denoise_mask > 0.5).float()
|
||||
|
||||
latent_mask = 1 - denoise_mask
|
||||
@@ -114,7 +238,7 @@ class KSamplerX0Inpaint:
|
||||
current_step = torch.argmin( torch.abs( self.sigmas - torch.mean(sigma) ) )
|
||||
total_steps = len(self.sigmas)-1
|
||||
|
||||
if total_steps - current_step < self.LanPaint_early_stop:
|
||||
if total_steps - current_step <= self.LanPaint_early_stop:
|
||||
out = self.PaintMethod(x, self.latent_image, self.noise, sigma, latent_mask, current_times, model_options, seed, n_steps=0)
|
||||
else:
|
||||
out = self.PaintMethod(x, self.latent_image, self.noise, sigma, latent_mask, current_times, model_options, seed)
|
||||
@@ -140,6 +264,7 @@ class KSAMPLER(comfy.samplers.KSAMPLER):
|
||||
#noise here is a randn noise from comfy.sample.prepare_noise
|
||||
#latent_image is the latent image as input of the KSampler node. For inpainting, it is the masked latent image. Otherwise it is zero tensor.
|
||||
extra_args["denoise_mask"] = denoise_mask
|
||||
print("LanPaint KSampler start sampler_function",denoise_mask.shape if denoise_mask is not None else None)
|
||||
model_k = KSamplerX0Inpaint(model_wrap, sigmas)
|
||||
model_k.latent_image = latent_image
|
||||
if self.inpaint_options.get("random", False): #TODO: Should this be the default?
|
||||
@@ -247,6 +372,7 @@ class LanPaint_KSampler():
|
||||
"LanPaint_NumSteps": ("INT", {"default": 5, "min": 0, "max": 100, "tooltip": "The number of steps for the Langevin dynamics, representing the turns of thinking per step."}),
|
||||
"LanPaint_PromptMode": (["Image First", "Prompt First"], {"tooltip": "Image First: emphasis image quality, Prompt First: emphasis prompt following"}),
|
||||
"LanPaint_Info": ("STRING", {"default": "LanPaint KSampler. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!", "multiline": True}),
|
||||
"Inpainting_mode": (["🖼️ Image Inpainting", "🎬 Video Inpainting"], {"default": "🖼️ Image Inpainting", "tooltip": "Choose Image mode for photos or Video mode for video frames with temporal consistency"}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,11 +383,11 @@ class LanPaint_KSampler():
|
||||
CATEGORY = "sampling"
|
||||
DESCRIPTION = "Uses the provided model, positive and negative conditioning to denoise the latent image."
|
||||
|
||||
def sample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0, LanPaint_NumSteps=5, LanPaint_PromptMode = "Image First", LanPaint_Info=""):
|
||||
def sample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0, LanPaint_NumSteps=5, LanPaint_PromptMode="Image First", LanPaint_Info="",Inpainting_mode="🖼️ Image Inpainting"):
|
||||
|
||||
model.LanPaint_StepSize = 0.15
|
||||
model.LanPaint_Lambda = 8.0
|
||||
model.LanPaint_Beta = 1.0
|
||||
model.LanPaint_StepSize = 0.2
|
||||
model.LanPaint_Lambda = 16.0
|
||||
model.LanPaint_Beta = 1.
|
||||
model.LanPaint_NumSteps = LanPaint_NumSteps
|
||||
model.LanPaint_Friction = 15.
|
||||
model.LanPaint_EarlyStop = 1
|
||||
@@ -269,6 +395,13 @@ class LanPaint_KSampler():
|
||||
model.LanPaint_cfg_BIG = cfg
|
||||
else:
|
||||
model.LanPaint_cfg_BIG = 0*cfg - 0.5
|
||||
|
||||
# Convert inpainting_mode to boolean for video_inpainting
|
||||
video_inpainting = (Inpainting_mode == "🎬 Video Inpainting")
|
||||
if not hasattr(model, 'model_options') or model.model_options is None:
|
||||
model.model_options = {}
|
||||
model.model_options["video_inpainting"] = video_inpainting
|
||||
|
||||
with override_sample_function():
|
||||
return nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise)
|
||||
class LanPaint_KSamplerAdvanced:
|
||||
@@ -289,13 +422,14 @@ class LanPaint_KSamplerAdvanced:
|
||||
"end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}),
|
||||
"return_with_leftover_noise": (["disable", "enable"], ),
|
||||
"LanPaint_NumSteps": ("INT", {"default": 5, "min": 0, "max": 100, "tooltip": "The number of steps for the Langevin dynamics, representing the turns of thinking per step."}),
|
||||
"LanPaint_Lambda": ("FLOAT", {"default": 8., "min": 0.1, "max": 50.0, "step": 0.1, "round": 0.1, "tooltip": "The bidirectional guidance scale. Higher values align with known regions more closely, but may result in instability."}),
|
||||
"LanPaint_StepSize": ("FLOAT", {"default": 0.15, "min": 0.0001, "max": 1., "step": 0.01, "round": 0.001, "tooltip": "The step size for the Langevin dynamics. Higher values result in faster convergence but may be unstable."}),
|
||||
"LanPaint_Lambda": ("FLOAT", {"default": 16., "min": 0.1, "max": 50.0, "step": 0.1, "round": 0.1, "tooltip": "The bidirectional guidance scale. Higher values align with known regions more closely, but may result in instability."}),
|
||||
"LanPaint_StepSize": ("FLOAT", {"default": 0.2, "min": 0.0001, "max": 1., "step": 0.01, "round": 0.001, "tooltip": "The step size for the Langevin dynamics. Higher values result in faster convergence but may be unstable."}),
|
||||
"LanPaint_Beta": ("FLOAT", {"default": 1., "min": 0.0001, "max": 5, "step": 0.1, "round": 0.1, "tooltip": "The step size ratio between masked / unmasked regions. Lower value can compensate high values of LanPaint_Lambda."}),
|
||||
"LanPaint_Friction": ("FLOAT", {"default": 15, "min": 0., "max": 50.0, "step": 0.1, "round": 0.1, "tooltip": "The friction parameter for fast langevin, lower values result in faster convergence but may be unstable."}),
|
||||
"LanPaint_PromptMode": (["Image First", "Prompt First"], {"tooltip": "Image First: emphasis image quality, Prompt First: emphasis prompt following"}),
|
||||
"LanPaint_EarlyStop": ("INT", {"default": 1, "min": 0, "max": 10000, "tooltip": "The number of steps to stop the LanPaint early, useful for preventing the image from irregular patterns."}),
|
||||
"LanPaint_Info": ("STRING", {"default": "LanPaint KSampler Adv. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!", "multiline": True}),
|
||||
"Inpainting_mode": (["🖼️ Image Inpainting", "🎬 Video Inpainting"], {"default": "🖼️ Image Inpainting", "tooltip": "Choose Image mode for photos or Video mode for video frames with temporal consistency"}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -304,7 +438,7 @@ class LanPaint_KSamplerAdvanced:
|
||||
|
||||
CATEGORY = "sampling"
|
||||
|
||||
def sample(self, model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise, denoise=1.0, LanPaint_StepSize=0.05, LanPaint_Lambda=5, LanPaint_Beta=1, LanPaint_NumSteps=5, LanPaint_Friction=5, LanPaint_PromptMode = "Image First", LanPaint_EarlyStop = 1, LanPaint_Info=""):
|
||||
def sample(self, model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise, LanPaint_NumSteps=5, LanPaint_Lambda=16.0, LanPaint_StepSize=0.2, LanPaint_Beta=1.0, LanPaint_Friction=15.0, LanPaint_PromptMode="Image First", LanPaint_EarlyStop=1, LanPaint_Info="", Inpainting_mode="🖼️ Image Inpainting"):
|
||||
force_full_denoise = True
|
||||
if return_with_leftover_noise == "enable":
|
||||
force_full_denoise = False
|
||||
@@ -321,9 +455,309 @@ class LanPaint_KSamplerAdvanced:
|
||||
model.LanPaint_cfg_BIG = cfg
|
||||
else:
|
||||
model.LanPaint_cfg_BIG = 0*cfg - 0.5
|
||||
|
||||
# Convert inpainting_mode to boolean for video_inpainting
|
||||
video_inpainting = (Inpainting_mode == "🎬 Video Inpainting")
|
||||
if not hasattr(model, 'model_options') or model.model_options is None:
|
||||
model.model_options = {}
|
||||
model.model_options["video_inpainting"] = video_inpainting
|
||||
|
||||
with override_sample_function():
|
||||
return nodes.common_ksampler(model, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise, disable_noise=disable_noise, start_step=start_at_step, last_step=end_at_step, force_full_denoise=force_full_denoise)
|
||||
return nodes.common_ksampler(model, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0, disable_noise=disable_noise, start_step=start_at_step, last_step=end_at_step, force_full_denoise=force_full_denoise)
|
||||
|
||||
|
||||
class MaskBlend:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"image1": ("IMAGE", {"tooltip": "Image before inpaint"}),
|
||||
"image2": ("IMAGE", {"tooltip": "Image after inpaint"}),
|
||||
"mask": ("MASK",),
|
||||
"blend_overlap": ("INT", {"default": 1, "min": 1, "max": 51, "step": 2, "tooltip": "The number of pixels to blend between the two images."})
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "blend_images"
|
||||
|
||||
CATEGORY = "image/postprocessing"
|
||||
|
||||
def blend_images(self, image1: torch.Tensor, image2: torch.Tensor, mask: torch.Tensor, blend_overlap: int):
|
||||
# smooth the binary 01 mask, keep 1 still 1, but smooth the transition from 1 to 0
|
||||
# for each mask pixel, find out the nearest 1 pixel, and set the mask value to the distance between the two pixels
|
||||
# check the size of mask and image1, image2, if not the same, assert error
|
||||
if image1.shape[1] != image2.shape[1] or image1.shape[2] != image2.shape[2]:
|
||||
raise ValueError(
|
||||
"Image size mismatch: Image1 and Image2 must have the same dimensions.\n"
|
||||
"Additionally, ensure both images have width and height that are multiples of 8.\n"
|
||||
"This is required because VAE decode always generates images with dimensions that are multiples of 8.\n"
|
||||
"If your input images are not multiples of 8, a size mismatch will occur during the decoding process.\n"
|
||||
"Please resize your images using an image resize node to ensure compatibility.\n"
|
||||
"Current sizes - Image1: {}x{}, Image2: {}x{}".format(
|
||||
image1.shape[2], image1.shape[1], image2.shape[2], image2.shape[1]
|
||||
)
|
||||
)
|
||||
mask = mask.float()
|
||||
mask = torch.nn.functional.max_pool2d(mask, kernel_size=blend_overlap, stride=1, padding=blend_overlap//2)
|
||||
# apply Gaussian blur with kernel size blend_overlap
|
||||
kernel = self.gaussian_kernel(blend_overlap)
|
||||
kernel = kernel.to(image1.device)
|
||||
kernel = kernel[None, None, ...]
|
||||
|
||||
mask = torch.nn.functional.conv2d(mask[:,None,:,:], kernel, padding=blend_overlap//2)[:,0,:,:]
|
||||
|
||||
|
||||
blended_image = image1 * (1 - mask[...,None]) + image2 * mask[...,None]
|
||||
return (blended_image,)
|
||||
def gaussian_kernel(self,kernel_size):
|
||||
"""
|
||||
Creates a 2D Gaussian kernel with the given size and standard deviation (sigma).
|
||||
"""
|
||||
sigma = (kernel_size - 1)/4
|
||||
# Create a grid of (x, y) coordinates
|
||||
x = torch.arange(kernel_size).float() - kernel_size // 2
|
||||
y = torch.arange(kernel_size).float() - kernel_size // 2
|
||||
x_grid, y_grid = torch.meshgrid(x, y, indexing='ij')
|
||||
|
||||
# Compute the Gaussian function
|
||||
kernel = torch.exp(-(x_grid ** 2 + y_grid ** 2) / (2 * sigma ** 2))
|
||||
kernel = kernel / kernel.sum() # Normalize the kernel
|
||||
|
||||
return kernel
|
||||
|
||||
class MaskBlendAlpha:
|
||||
"""
|
||||
Create an RGBA image by writing the mask into the PNG alpha channel.
|
||||
|
||||
Requirement:
|
||||
- inpaint region: alpha = 0 (transparent)
|
||||
- other region: alpha = 1 (opaque)
|
||||
|
||||
This node writes the mask into the PNG alpha channel.
|
||||
Current default behavior matches the previous `invert_mask=True` behavior:
|
||||
alpha = mask.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE", {"tooltip": "VAE-decoded image (RGB)."}),
|
||||
"mask": ("MASK", {"tooltip": "Mask used as alpha channel (alpha = mask)."}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "to_rgba"
|
||||
CATEGORY = "image/postprocessing"
|
||||
|
||||
def to_rgba(self, image: torch.Tensor, mask: torch.Tensor):
|
||||
"""
|
||||
image: [B,H,W,3] float in [0,1]
|
||||
mask: [B,H,W] (or [H,W]) float in [0,1] used as alpha
|
||||
returns RGBA image: [B,H,W,4] float in [0,1]
|
||||
"""
|
||||
if image.ndim != 4 or image.shape[-1] != 3:
|
||||
raise ValueError(f"Expected IMAGE tensor [B,H,W,3], got {tuple(image.shape)}")
|
||||
|
||||
# Normalize mask shape to [B,H,W]
|
||||
if mask.ndim == 2:
|
||||
mask = mask.unsqueeze(0)
|
||||
elif mask.ndim == 3:
|
||||
pass
|
||||
else:
|
||||
# Some pipelines may carry mask as [B,1,H,W]
|
||||
if mask.ndim == 4 and mask.shape[1] == 1:
|
||||
mask = mask[:, 0, :, :]
|
||||
else:
|
||||
raise ValueError(f"Expected MASK tensor [B,H,W] or [H,W], got {tuple(mask.shape)}")
|
||||
|
||||
b, h, w, _ = image.shape
|
||||
|
||||
# Batch align
|
||||
if mask.shape[0] != b:
|
||||
if mask.shape[0] == 1:
|
||||
mask = mask.repeat(b, 1, 1)
|
||||
else:
|
||||
raise ValueError(f"Batch mismatch: image batch={b}, mask batch={mask.shape[0]}")
|
||||
|
||||
# Spatial align (resize mask to image resolution if needed)
|
||||
if mask.shape[1] != h or mask.shape[2] != w:
|
||||
mask_4d = mask.unsqueeze(1) # [B,1,H,W]
|
||||
mask_4d = torch.nn.functional.interpolate(mask_4d, size=(h, w), mode="nearest")
|
||||
mask = mask_4d[:, 0, :, :]
|
||||
|
||||
mask = mask.float().clamp(0.0, 1.0)
|
||||
|
||||
# Default behavior (matches previous invert_mask=True path):
|
||||
# alpha = mask
|
||||
rgba = torch.cat([image, mask.unsqueeze(-1)], dim=-1)
|
||||
return (rgba,)
|
||||
|
||||
class Noise_EmptyNoise:
|
||||
def generate_noise(self, latent):
|
||||
return torch.zeros_like(latent["samples"])
|
||||
|
||||
class Noise_RandomNoise:
|
||||
def __init__(self, seed):
|
||||
self.seed = seed
|
||||
def generate_noise(self, latent):
|
||||
torch.manual_seed(self.seed)
|
||||
return torch.randn_like(latent["samples"])
|
||||
|
||||
# Custom sampler implementation mimmicking base comfy nodes_custom_sampler.py
|
||||
class LanPaint_SamplerCustom:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required":
|
||||
{"model": ("MODEL",),
|
||||
"add_noise": ("BOOLEAN", {"default": True}),
|
||||
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "control_after_generate": True}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
||||
"positive": ("CONDITIONING",),
|
||||
"negative": ("CONDITIONING",),
|
||||
"sampler": ("SAMPLER",),
|
||||
"sigmas": ("SIGMAS",),
|
||||
"latent_image": ("LATENT",),
|
||||
"LanPaint_NumSteps": ("INT", {"default": 5, "min": 0, "max": 100, "tooltip": "Number of steps for Langevin dynamics, representing turns of thinking per step."}),
|
||||
"LanPaint_PromptMode": (["Image First", "Prompt First"], {"tooltip": "Image First: prioritizes image quality; Prompt First: prioritizes prompt adherence."}),
|
||||
"LanPaint_Info": ("STRING", {"default": "LanPaint Custom Sampler. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!", "multiline": True}),
|
||||
"Inpainting_mode": (["🖼️ Image Inpainting", "🎬 Video Inpainting"], {"default": "🖼️ Image Inpainting", "tooltip": "Choose Image mode for photos or Video mode for video frames with temporal consistency"}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LATENT", "LATENT")
|
||||
RETURN_NAMES = ("output", "denoised_output")
|
||||
FUNCTION = "sample"
|
||||
CATEGORY = "sampling/custom_sampling"
|
||||
|
||||
def sample(self, model, sampler, sigmas, add_noise, noise_seed, cfg, positive, negative, latent_image, LanPaint_NumSteps, LanPaint_PromptMode, LanPaint_Info="",Inpainting_mode="🖼️ Image Inpainting"):
|
||||
model.LanPaint_StepSize = 0.2
|
||||
model.LanPaint_Lambda = 16.0
|
||||
model.LanPaint_Beta = 1.
|
||||
model.LanPaint_NumSteps = LanPaint_NumSteps
|
||||
model.LanPaint_Friction = 15.
|
||||
model.LanPaint_EarlyStop = 1
|
||||
if LanPaint_PromptMode == "Image First":
|
||||
model.LanPaint_cfg_BIG = cfg
|
||||
else:
|
||||
model.LanPaint_cfg_BIG = 0 * cfg - 0.5
|
||||
video_inpainting = (Inpainting_mode == "🎬 Video Inpainting")
|
||||
if not hasattr(model, 'model_options') or model.model_options is None:
|
||||
model.model_options = {}
|
||||
model.model_options["video_inpainting"] = video_inpainting
|
||||
with override_sample_function():
|
||||
latent = latent_image.copy()
|
||||
latent_image = latent["samples"]
|
||||
latent_image = comfy.sample.fix_empty_latent_channels(model, latent_image)
|
||||
latent["samples"] = latent_image
|
||||
|
||||
if not add_noise:
|
||||
noise = Noise_EmptyNoise().generate_noise(latent)
|
||||
else:
|
||||
noise = Noise_RandomNoise(noise_seed).generate_noise(latent)
|
||||
|
||||
noise_mask = None
|
||||
if "noise_mask" in latent:
|
||||
noise_mask = latent["noise_mask"]
|
||||
|
||||
x0_output = {}
|
||||
callback = latent_preview.prepare_callback(model, sigmas.shape[-1] - 1, x0_output)
|
||||
disable_pbar = not comfy.utils.PROGRESS_BAR_ENABLED
|
||||
|
||||
samples = comfy.sample.sample_custom(model, noise, cfg, sampler, sigmas, positive, negative, latent_image,noise_mask=noise_mask, callback=callback, disable_pbar=disable_pbar, seed=noise_seed)
|
||||
|
||||
out = latent.copy()
|
||||
out["samples"] = samples
|
||||
if "x0" in x0_output:
|
||||
out_denoised = latent.copy()
|
||||
out_denoised["samples"] = model.model.process_latent_out(x0_output["x0"].cpu())
|
||||
else:
|
||||
out_denoised = out
|
||||
return (out, out_denoised)
|
||||
|
||||
class LanPaint_SamplerCustomAdvanced:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required":
|
||||
{"noise": ("NOISE",),
|
||||
"guider": ("GUIDER", ),
|
||||
"sampler": ("SAMPLER", ),
|
||||
"sigmas": ("SIGMAS", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"LanPaint_NumSteps": ("INT", {"default": 5, "min": 0, "max": 100, "tooltip": "Number of steps for Langevin dynamics, representing turns of thinking per step."}),
|
||||
"LanPaint_Lambda": ("FLOAT", {"default": 16.0, "min": 0.1, "max": 50.0, "step": 0.1, "tooltip": "Bidirectional guidance scale. Higher values align with known regions but may cause instability."}),
|
||||
"LanPaint_StepSize": ("FLOAT", {"default": 0.2, "min": 0.0001, "max": 1.0, "step": 0.01, "tooltip": "Step size for Langevin dynamics. Higher values speed convergence but may be unstable."}),
|
||||
"LanPaint_Beta": ("FLOAT", {"default": 1.0, "min": 0.0001, "max": 5.0, "step": 0.1, "tooltip": "Step size ratio between masked/unmasked regions. Lower values balance high Lambda."}),
|
||||
"LanPaint_Friction": ("FLOAT", {"default": 15.0, "min": 0.0, "max": 50.0, "step": 0.1, "tooltip": "Friction parameter for fast Langevin. Lower values speed convergence but may be unstable."}),
|
||||
"LanPaint_PromptMode": (["Image First", "Prompt First"], {"tooltip": "Image First: prioritizes image quality; Prompt First: prioritizes prompt adherence."}),
|
||||
"LanPaint_EarlyStop": ("INT", {"default": 1, "min": 0, "max": 10000, "tooltip": "Steps to stop LanPaint early, preventing irregular patterns."}),
|
||||
"LanPaint_Info": ("STRING", {"default": "LanPaint Custom Sampler Adv. For more info, visit https://github.com/scraed/LanPaint. If you find it useful, please give a star ⭐️!", "multiline": True}),
|
||||
"Inpainting_mode": (["🖼️ Image Inpainting", "🎬 Video Inpainting"], {"default": "🖼️ Image Inpainting", "tooltip": "Choose Image mode for photos or Video mode for video frames with temporal consistency"}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LATENT","LATENT")
|
||||
RETURN_NAMES = ("output", "denoised_output")
|
||||
|
||||
FUNCTION = "sample"
|
||||
|
||||
CATEGORY = "sampling/custom_sampling"
|
||||
|
||||
def sample(self, noise, guider, sampler, sigmas, latent_image, LanPaint_NumSteps, LanPaint_Lambda, LanPaint_StepSize, LanPaint_Beta, LanPaint_Friction, LanPaint_PromptMode, LanPaint_EarlyStop, LanPaint_Info="",Inpainting_mode="🖼️ Image Inpainting"):
|
||||
model = guider.model_patcher
|
||||
model.LanPaint_StepSize = LanPaint_StepSize
|
||||
model.LanPaint_Lambda = LanPaint_Lambda
|
||||
model.LanPaint_Beta = LanPaint_Beta
|
||||
model.LanPaint_NumSteps = LanPaint_NumSteps
|
||||
model.LanPaint_Friction = LanPaint_Friction
|
||||
model.LanPaint_EarlyStop = LanPaint_EarlyStop
|
||||
if LanPaint_PromptMode == "Image First":
|
||||
model.LanPaint_cfg_BIG = guider.cfg
|
||||
else:
|
||||
model.LanPaint_cfg_BIG = 0 * guider.cfg - 0.5
|
||||
|
||||
video_inpainting = (Inpainting_mode == "🎬 Video Inpainting")
|
||||
if not hasattr(model, 'model_options') or model.model_options is None:
|
||||
model.model_options = {}
|
||||
model.model_options["video_inpainting"] = video_inpainting
|
||||
with override_sample_function():
|
||||
latent = latent_image
|
||||
latent_image = latent["samples"]
|
||||
print('before fix_empty_latent_channels latent_image shape',latent_image.shape)
|
||||
latent = latent.copy()
|
||||
latent_image = comfy.sample.fix_empty_latent_channels(guider.model_patcher, latent_image)
|
||||
latent["samples"] = latent_image
|
||||
print('latent_image shape',latent_image.shape)
|
||||
print('outside noise_mask',latent["noise_mask"].shape if "noise_mask" in latent else 'no noise_mask')
|
||||
print('latent keys',latent.keys())
|
||||
noise_mask = None
|
||||
if "noise_mask" in latent:
|
||||
noise_mask = latent["noise_mask"]
|
||||
print('inside noise_mask shape',noise_mask.shape)
|
||||
|
||||
x0_output = {}
|
||||
callback = latent_preview.prepare_callback(guider.model_patcher, sigmas.shape[-1] - 1, x0_output)
|
||||
|
||||
disable_pbar = not comfy.utils.PROGRESS_BAR_ENABLED
|
||||
samples = guider.sample(noise.generate_noise(latent), latent_image, sampler, sigmas, denoise_mask=noise_mask, callback=callback, disable_pbar=disable_pbar, seed=noise.seed)
|
||||
samples = samples.to(comfy.model_management.intermediate_device())
|
||||
|
||||
out = latent.copy()
|
||||
out["samples"] = samples
|
||||
if "x0" in x0_output:
|
||||
out_denoised = latent.copy()
|
||||
out_denoised["samples"] = guider.model_patcher.model.process_latent_out(x0_output["x0"].cpu())
|
||||
else:
|
||||
out_denoised = out
|
||||
# print('output',out.keys(),out["samples"].shape,out['noise_mask'].shape)
|
||||
return (out, out_denoised)
|
||||
|
||||
|
||||
# A dictionary that contains all nodes you want to export with their names
|
||||
@@ -331,6 +765,10 @@ class LanPaint_KSamplerAdvanced:
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"LanPaint_KSampler": LanPaint_KSampler,
|
||||
"LanPaint_KSamplerAdvanced": LanPaint_KSamplerAdvanced,
|
||||
"LanPaint_SamplerCustom" : LanPaint_SamplerCustom,
|
||||
"LanPaint_SamplerCustomAdvanced" : LanPaint_SamplerCustomAdvanced,
|
||||
"LanPaint_MaskBlend": MaskBlend,
|
||||
"LanPaint_MaskBlendAlpha": MaskBlendAlpha,
|
||||
# "LanPaint_UpSale_LatentNoiseMask": LanPaint_UpSale_LatentNoiseMask,
|
||||
}
|
||||
|
||||
@@ -338,5 +776,9 @@ NODE_CLASS_MAPPINGS = {
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"LanPaint_KSampler": "LanPaint KSampler",
|
||||
"LanPaint_KSamplerAdvanced": "LanPaint KSampler (Advanced)",
|
||||
"LanPaint_SamplerCustom" : "LanPaint Sampler Custom",
|
||||
"LanPaint_SamplerCustomAdvanced" : "LanPaint Sampler Custom (Advanced)",
|
||||
"LanPaint_MaskBlend": "LanPaint Mask Blend",
|
||||
"LanPaint_MaskBlendAlpha": "MaskBlend (alpha)",
|
||||
# "LanPaint_UpSale_LatentNoiseMask": "LanPaint UpSale Latent Noise Mask"
|
||||
}
|
||||
|
||||
@@ -240,7 +240,6 @@ class StochasticHarmonicOscillator:
|
||||
tuple: (y(t), v(t))
|
||||
"""
|
||||
|
||||
|
||||
dummyzero = y0.new_zeros(1) # convert scalar to tensor with same device and dtype as y0
|
||||
Delta = self.Delta + dummyzero
|
||||
Gamma_hat = self.Gamma * t + dummyzero
|
||||
@@ -253,8 +252,8 @@ class StochasticHarmonicOscillator:
|
||||
EE = 1 - Gamma_hat * zeta_2
|
||||
|
||||
if v0 is None:
|
||||
#v0 = torch.randn_like(y0) * D / 2 ** 0.5
|
||||
v0 = (C - A * y0)/Gamma**0.5
|
||||
v0 = torch.randn_like(y0) * D / 2 ** 0.5
|
||||
#v0 = (C - A * y0)/Gamma**0.5
|
||||
|
||||
# Calculate mean position and velocity
|
||||
term1 = (1 - zeta_1) * (C * t - A * t * y0) + zeta_2 * (Gamma ** 0.5) * v0 * t
|
||||
@@ -273,16 +272,30 @@ class StochasticHarmonicOscillator:
|
||||
cov_matrix[..., 0, 1] = cov_yv
|
||||
cov_matrix[..., 1, 0] = cov_yv # symmetric
|
||||
cov_matrix[..., 1, 1] = cov_vv
|
||||
|
||||
|
||||
|
||||
# Compute the Cholesky decomposition to get scale_tril
|
||||
#scale_tril = torch.linalg.cholesky(cov_matrix)
|
||||
scale_tril = torch.zeros(*batch_shape, 2, 2, device=y0.device, dtype=y0.dtype)
|
||||
tol = 1e-8
|
||||
cov_yy = torch.clamp( cov_yy, min = tol )
|
||||
sd_yy = torch.sqrt( cov_yy )
|
||||
inv_sd_yy = 1/(sd_yy)
|
||||
|
||||
scale_tril[..., 0, 0] = sd_yy
|
||||
scale_tril[..., 0, 1] = 0.
|
||||
scale_tril[..., 1, 0] = cov_yv * inv_sd_yy
|
||||
scale_tril[..., 1, 1] = torch.clamp( cov_vv - cov_yv**2 / cov_yy, min = tol ) ** 0.5
|
||||
# check if it matches torch.linalg.
|
||||
#assert torch.allclose(torch.linalg.cholesky(cov_matrix), scale_tril, atol = 1e-4, rtol = 1e-4 )
|
||||
# Sample correlated noise from multivariate normal
|
||||
mean = torch.zeros(*batch_shape, 2, device=y0.device, dtype=y0.dtype)
|
||||
mean[..., 0] = y_mean
|
||||
mean[..., 1] = v_mean
|
||||
new_yv = torch.distributions.MultivariateNormal(
|
||||
loc=mean,
|
||||
covariance_matrix=cov_matrix
|
||||
scale_tril=scale_tril
|
||||
).sample()
|
||||
|
||||
return new_yv[...,0], new_yv[...,1]
|
||||
|
||||
|
||||
return new_yv[...,0], new_yv[...,1]
|
||||