mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
control outpaint
This commit is contained in:
+27
-20
@@ -16,10 +16,10 @@ ModernUI is still in early development and not all features are available yet, p
|
||||
Thanks to @BinaryQuantumSoul for his hard work on this project!
|
||||
|
||||
*Note*: [SD.Next](https://github.com/vladmandic/automatic) is no longer marked as a fork of [A1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) and github project has been fully detached
|
||||
Given huge number of changes with *+3443/-3342 commits diff over the past year, a completely different backend/engine and a change of focus,
|
||||
Given huge number of changes with *+3443/-3342* commits diff (at the time of fork detach) over the past year, a completely different backend/engine and a change of focus,
|
||||
it is time to give credit to original [author](https://github.com/auTOMATIC1111), and move on!
|
||||
|
||||
## Update for 2024-05-06
|
||||
## Update for 2024-05-07
|
||||
|
||||
- **Features**:
|
||||
- **ModernUI** preview of the new [ModernUI](https://github.com/BinaryQuantumSoul/sdnext-modernui)
|
||||
@@ -53,24 +53,13 @@ it is time to give credit to original [author](https://github.com/auTOMATIC1111)
|
||||
Newer alternative method to [ToMe](https://github.com/dbolya/tomesd) that can provide speed-up with minimal quality loss
|
||||
Enable in *settings -> inference settings -> token merging*
|
||||
Also available in XYZ grid
|
||||
- **UI**:
|
||||
- Faster **UI** load times
|
||||
- Theme types:
|
||||
**Standard* (built-in themes), **Modern** (experimental nextgen ui), **None** (used for Gradio and Huggingface 3rd party themes)
|
||||
Specifying a theme type updates list of available themes
|
||||
For example, *Gradio* themes will not appear as available if theme type is set to *Standard*
|
||||
- Redesign of base txt2img interface
|
||||
- Minor tweaks to styles: refresh/apply/save
|
||||
- See details in [WiKi](https://github.com/vladmandic/automatic/wiki/Themes)
|
||||
- **API**:
|
||||
- Add API endpoint `/sdapi/v1/control` and CLI util `cli/simple-control.py`
|
||||
(in addition to previously added `/sdapi/v1/preprocessors` and `/sdapi/v1/masking`)
|
||||
example:
|
||||
> simple-control.py --prompt 'woman in the city' --sampler UniPC --steps 20
|
||||
> --input ~/generative/Samples/cutie-512.png --output /tmp/test.png --processed /tmp/proc.png
|
||||
> --control 'Canny:Canny FP16:0.7, OpenPose:OpenPose FP16:0.8' --type controlnet
|
||||
> --ipadapter 'Plus:~/generative/Samples/cutie-512.png:0.5'
|
||||
- Add API endpoint `/sdapi/v1/vqa` and CLI util `cli/simple-vqa.py`
|
||||
- **Outpaint**:
|
||||
New method of outpainting that uses a combination of auto-masking and edge generation to create seamless transitions between original and generated image
|
||||
Use on control tab:
|
||||
- *input -> denoising strength: 0.5 or higher*
|
||||
- *select image -> outpaint -> expand edges or zoom out to desired size*
|
||||
- *size -> mode: outpaint, method: nearest*
|
||||
- *mask -> inpaint masked only (if you want to keep original image)*
|
||||
- **Models**:
|
||||
- **Load UNET**: ability to override/load external UNET to a selected model
|
||||
Works similar to how VAE is selected and loaded: Set UNet folder and UNet model in settings
|
||||
@@ -89,6 +78,24 @@ it is time to give credit to original [author](https://github.com/auTOMATIC1111)
|
||||
- [Hyper-SD](https://huggingface.co/ByteDance/Hyper-SD)
|
||||
sd15 and sdxl 1-step, 2-step, 4-step and 8-step optimized models using lora
|
||||
set parameters: *sampler: TCD or LCM, steps: 1/2/4/8, cfg_scale: 0.0*
|
||||
- **UI**:
|
||||
- Faster **UI** load times
|
||||
- Theme types:
|
||||
**Standard** (built-in themes), **Modern** (experimental nextgen ui), **None** (used for Gradio and Huggingface 3rd party themes)
|
||||
Specifying a theme type updates list of available themes
|
||||
For example, *Gradio* themes will not appear as available if theme type is set to *Standard*
|
||||
- Redesign of base txt2img interface
|
||||
- Minor tweaks to styles: refresh/apply/save
|
||||
- See details in [WiKi](https://github.com/vladmandic/automatic/wiki/Themes)
|
||||
- **API**:
|
||||
- Add API endpoint `/sdapi/v1/control` and CLI util `cli/simple-control.py`
|
||||
(in addition to previously added `/sdapi/v1/preprocessors` and `/sdapi/v1/masking`)
|
||||
example:
|
||||
> simple-control.py --prompt 'woman in the city' --sampler UniPC --steps 20
|
||||
> --input ~/generative/Samples/cutie-512.png --output /tmp/test.png --processed /tmp/proc.png
|
||||
> --control 'Canny:Canny FP16:0.7, OpenPose:OpenPose FP16:0.8' --type controlnet
|
||||
> --ipadapter 'Plus:~/generative/Samples/cutie-512.png:0.5'
|
||||
- Add API endpoint `/sdapi/v1/vqa` and CLI util `cli/simple-vqa.py`
|
||||
- **Changes**:
|
||||
- Removed built-in extensions: *ControlNet* and *Image-Browser*
|
||||
as both *image-browser* and *controlnet* have native built-in equivalents
|
||||
|
||||
@@ -351,6 +351,7 @@ def outpaint(input_image: Image.Image, outpaint_type: str = 'Edge'):
|
||||
mask = cv2.cvtColor(np.array(mask), cv2.COLOR_BGR2GRAY)
|
||||
mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)[1]
|
||||
sigmaX, sigmaY = int((h0-h1)/3), int((w0-w1)/3)
|
||||
sigmaX, sigmaY = max(1, sigmaX), max(1, sigmaY)
|
||||
kernel = np.ones((5, 5), np.uint8)
|
||||
mask = cv2.erode(mask, kernel, iterations=max(sigmaX, sigmaY) // 3) # increase overlap area
|
||||
mask = cv2.GaussianBlur(mask, (0, 0), sigmaX=sigmaX, sigmaY=sigmaY) # blur mask
|
||||
@@ -366,6 +367,8 @@ def outpaint(input_image: Image.Image, outpaint_type: str = 'Edge'):
|
||||
# noised[y1:y1 + h, x1:x1 + w] = cropped # overlay original over initialized
|
||||
# image = noised
|
||||
|
||||
# mask = Image.new('L', (w0, h0), 0)
|
||||
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||
image = Image.fromarray(image)
|
||||
return image, mask
|
||||
|
||||
@@ -179,7 +179,7 @@ def create_ui(_blocks: gr.Blocks=None):
|
||||
with gr.Column(scale=9, elem_id='control-preview-column', visible=True) as column_preview:
|
||||
gr.HTML('<span id="control-preview-button">Preview</p>')
|
||||
with gr.Tabs(elem_classes=['control-tabs'], elem_id='control-tab-preview'):
|
||||
with gr.Tab('Preview', id='preview-image') as tab_image:
|
||||
with gr.Tab('Preview', id='preview-image') as _tab_preview:
|
||||
preview_process = gr.Image(label="Preview", show_label=False, type="pil", source="upload", interactive=False, height=gr_height, visible=True, elem_id='control_preview', elem_classes=['control-image'])
|
||||
|
||||
with gr.Accordion('Control elements', open=False, elem_id="control_elements"):
|
||||
@@ -474,7 +474,7 @@ def create_ui(_blocks: gr.Blocks=None):
|
||||
btn_interrogate_booru.click(fn=helpers.interrogate_booru, inputs=[], outputs=[prompt])
|
||||
|
||||
select_fields = [input_mode, input_image, init_image, input_type, input_resize, input_inpaint, input_video, input_batch, input_folder]
|
||||
select_output = [output_tabs, result_txt]
|
||||
select_output = [output_tabs, preview_process, result_txt]
|
||||
select_dict = dict(
|
||||
fn=helpers.select_input,
|
||||
_js="controlInputMode",
|
||||
|
||||
@@ -126,12 +126,12 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
|
||||
input_source = None
|
||||
busy = False
|
||||
# debug('Control input: none')
|
||||
return [gr.Tabs.update(), '']
|
||||
return [gr.Tabs.update(), None, '']
|
||||
debug(f'Control select input: source={selected_input} init={init_image} type={init_type} mode={input_mode}')
|
||||
input_type = type(selected_input)
|
||||
input_mask = None
|
||||
status = 'Control input | Unknown'
|
||||
res = [gr.Tabs.update(selected='out-gallery'), status]
|
||||
res = [gr.Tabs.update(selected='out-gallery'), input_mask, status]
|
||||
# control inputs
|
||||
if isinstance(selected_input, Image.Image): # image via upload -> image
|
||||
if input_mode == 'Outpaint':
|
||||
@@ -140,23 +140,23 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
|
||||
input_source = [selected_input]
|
||||
input_type = 'PIL.Image'
|
||||
status = f'Control input | Image | Size {selected_input.width}x{selected_input.height} | Mode {selected_input.mode}'
|
||||
res = [gr.Tabs.update(selected='out-gallery'), status]
|
||||
res = [gr.Tabs.update(selected='out-gallery'), input_mask, status]
|
||||
elif isinstance(selected_input, dict): # inpaint -> dict image+mask
|
||||
input_mask = selected_input['mask']
|
||||
selected_input = selected_input['image']
|
||||
input_source = [selected_input]
|
||||
input_type = 'PIL.Image'
|
||||
status = f'Control input | Image | Size {selected_input.width}x{selected_input.height} | Mode {selected_input.mode}'
|
||||
res = [gr.Tabs.update(selected='out-gallery'), status]
|
||||
res = [gr.Tabs.update(selected='out-gallery'), input_mask, status]
|
||||
elif isinstance(selected_input, gr.components.image.Image): # not likely
|
||||
input_source = [selected_input.value]
|
||||
input_type = 'gr.Image'
|
||||
res = [gr.Tabs.update(selected='out-gallery'), status]
|
||||
res = [gr.Tabs.update(selected='out-gallery'), input_mask, status]
|
||||
elif isinstance(selected_input, str): # video via upload > tmp filepath to video
|
||||
input_source = selected_input
|
||||
input_type = 'gr.Video'
|
||||
status = get_video(input_source)
|
||||
res = [gr.Tabs.update(selected='out-video'), status]
|
||||
res = [gr.Tabs.update(selected='out-video'), input_mask, status]
|
||||
elif isinstance(selected_input, list): # batch or folder via upload -> list of tmp filepaths
|
||||
if hasattr(selected_input[0], 'name'):
|
||||
input_type = 'tempfiles'
|
||||
@@ -165,7 +165,7 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
|
||||
input_type = 'files'
|
||||
input_source = selected_input
|
||||
status = f'Control input | Images | Files {len(input_source)}'
|
||||
res = [gr.Tabs.update(selected='out-gallery'), status]
|
||||
res = [gr.Tabs.update(selected='out-gallery'), input_mask, status]
|
||||
else: # unknown
|
||||
input_source = None
|
||||
shared.log.debug(f'Control input: type={input_type} input={input_source}')
|
||||
@@ -176,7 +176,7 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
|
||||
input_init = None
|
||||
elif init_type == 2: # Separate init image
|
||||
input_init = [init_image]
|
||||
debug(f'Control select input: source={input_source} init={input_init} mode={input_mode}')
|
||||
debug(f'Control select input: source={input_source} init={input_init} mask={input_mask} mode={input_mode}')
|
||||
busy = False
|
||||
return res
|
||||
|
||||
|
||||
Reference in New Issue
Block a user