Change from custom script to extension.
Extend to support turning tiling on and off mid-generation.main
parent
76c8bfcf64
commit
b4470ddc38
|
|
@ -1,11 +1,13 @@
|
|||
# Asymmetric Tiling for stable-diffusion-webui
|
||||
|
||||
A custom script for [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) to configure seamless image tiling independently for the X and Y axes.
|
||||
An always visible script extension for [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) to configure seamless image tiling independently for the X and Y axes.
|
||||
|
||||
To use, add [asymmetric_tiling.py](asymmetric_tiling.py) to your `scripts` directory in stable-diffusion-webui, restart your server, select `Asymmetric tiling` in the script dropdown, and check `Tile X` or `Tile Y` as desired. While this script is active, the `Tiling` checkbox in the main UI will be ignored.
|
||||
To use, install this repository from the "Extensions" tab in stable-diffusion-webui, restart your server, open the `Asymmetric tiling` foldout on txt2img or img2img, and make it active, and check `Tile X` or `Tile Y` as desired. While this script is active, the `Tiling` checkbox in the main UI will be ignored.
|
||||
|
||||
Like existing tiling options this won't guarantee seamless tiling 100% of the time, but it should manage it for most prompts. You can check that images tile seamlessly using online tools like [Seamless Texture Check](https://www.pycheung.com/checker/).
|
||||
|
||||
For the old, non-extension version of this script, use the "classic_script" branch.
|
||||
|
||||
## X axis tiling examples
|
||||

|
||||

|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import modules.scripts
|
||||
import modules.sd_hijack
|
||||
import modules.shared
|
||||
import gradio
|
||||
|
||||
from modules.processing import process_images
|
||||
|
|
@ -19,39 +20,52 @@ class Script(modules.scripts.Script):
|
|||
return "Asymmetric tiling"
|
||||
|
||||
# Override from modules.scripts.Script
|
||||
def ui(self, is_img2img):
|
||||
tileX = gradio.Checkbox(True, label="Tile X")
|
||||
tileY = gradio.Checkbox(False, label="Tile Y")
|
||||
|
||||
return [tileX, tileY]
|
||||
def show(self, is_img2img):
|
||||
return modules.scripts.AlwaysVisible
|
||||
|
||||
# Override from modules.scripts.Script
|
||||
def run(self, p, tileX, tileY):
|
||||
def ui(self, is_img2img):
|
||||
with gradio.Accordion("Asymmetric tiling", open=False):
|
||||
active = gradio.Checkbox(False, label="Active")
|
||||
tileX = gradio.Checkbox(True, label="Tile X")
|
||||
tileY = gradio.Checkbox(False, label="Tile Y")
|
||||
startStep = gradio.Number(0, label="Start tiling from step N", precision=0)
|
||||
stopStep = gradio.Number(-1, label="Stop tiling after step N (-1: Don't stop)", precision=0)
|
||||
|
||||
return [active, tileX, tileY, startStep, stopStep]
|
||||
|
||||
# Override from modules.scripts.Script
|
||||
def process(self, p, active, tileX, tileY, startStep, stopStep):
|
||||
if (active):
|
||||
# Record tiling options chosen for each axis.
|
||||
p.extra_generation_params = {
|
||||
"Tile X": tileX,
|
||||
"Tile Y": tileY,
|
||||
"Start Tiling From Step": startStep,
|
||||
"Stop Tiling After Step": stopStep,
|
||||
}
|
||||
|
||||
try:
|
||||
# Modify the model's Conv2D layers to perform our chosen tiling.
|
||||
self.__hijackConv2DMethods(tileX, tileY)
|
||||
self.__hijackConv2DMethods(tileX, tileY, startStep, stopStep)
|
||||
else:
|
||||
# Restore model behaviour to normal.
|
||||
self.__restoreConv2DMethods()
|
||||
|
||||
# Process images as normal.
|
||||
return process_images(p)
|
||||
finally:
|
||||
# Restore model behaviour to normal, even if something went wrong during processing.
|
||||
def postprocess(self, *args):
|
||||
# Restore model behaviour to normal.
|
||||
self.__restoreConv2DMethods()
|
||||
|
||||
# [Private]
|
||||
# Go through all the "Conv2D" layers in the model and patch them to use the requested asymmetric tiling mode.
|
||||
def __hijackConv2DMethods(self, tileX: bool, tileY: bool):
|
||||
def __hijackConv2DMethods(self, tileX: bool, tileY: bool, startStep: int, stopStep: int):
|
||||
for layer in modules.sd_hijack.model_hijack.layers:
|
||||
if type(layer) == Conv2d:
|
||||
layer.padding_modeX = 'circular' if tileX else 'constant'
|
||||
layer.padding_modeY = 'circular' if tileY else 'constant'
|
||||
layer.paddingX = (layer._reversed_padding_repeated_twice[0], layer._reversed_padding_repeated_twice[1], 0, 0)
|
||||
layer.paddingY = (0, 0, layer._reversed_padding_repeated_twice[2], layer._reversed_padding_repeated_twice[3])
|
||||
layer.paddingStartStep = startStep
|
||||
layer.paddingStopStep = stopStep
|
||||
layer._conv_forward = Script.__replacementConv2DConvForward.__get__(layer, Conv2d)
|
||||
|
||||
# [Private]
|
||||
|
|
@ -69,6 +83,11 @@ class Script(modules.scripts.Script):
|
|||
# paddingX (tuple, cached copy of _reversed_padding_repeated_twice with the last two values zeroed)
|
||||
# paddingY (tuple, cached copy of _reversed_padding_repeated_twice with the first two values zeroed)
|
||||
def __replacementConv2DConvForward(self, input: Tensor, weight: Tensor, bias: Optional[Tensor]):
|
||||
step = modules.shared.state.sampling_step
|
||||
if ((self.paddingStartStep < 0 or step >= self.paddingStartStep) and (self.paddingStopStep < 0 or step <= self.paddingStopStep)):
|
||||
working = F.pad(input, self.paddingX, mode=self.padding_modeX)
|
||||
working = F.pad(working, self.paddingY, mode=self.padding_modeY)
|
||||
else:
|
||||
working = F.pad(input, self.paddingX, mode='constant')
|
||||
working = F.pad(working, self.paddingY, mode='constant')
|
||||
return F.conv2d(working, weight, bias, self.stride, _pair(0), self.dilation, self.groups)
|
||||
Loading…
Reference in New Issue