mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 17:24:32 +02:00
refactor: integrate sharpfin for high-quality image resize
Vendor sharpfin library (Apache 2.0) and add centralized wrapper module (images_sharpfin.py) replacing torchvision tensor/PIL conversion and resize operations throughout the codebase. - Add modules/sharpfin/ vendored library with MKS2021, Lanczos3, Mitchell, Catmull-Rom kernels and optional Triton sparse acceleration - Add modules/images_sharpfin.py wrapper with to_tensor(), to_pil(), pil_to_tensor(), normalize(), resize(), resize_tensor() - Add resize_quality and resize_linearize_srgb settings - Add MKS2021 and Lanczos3 upscaler entries - Replace torchvision.transforms.functional imports across 18 files - to_pil() auto-detects HWC/BHWC layout, adds .round() before uint8 - Sparse Triton path falls back to dense GPU on compilation failure - Mixed-axis resize splits into two single-axis scale() calls - Masks and non-sRGB data always use linearize=False
This commit is contained in:
committed by
vladmandic
parent
2c4d0751d9
commit
76aa949a26
@@ -1,6 +1,6 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
import torchvision.transforms.functional as vF
|
||||
from modules import images_sharpfin
|
||||
import PIL
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def preprocess(image, processor, **kwargs):
|
||||
elif isinstance(image, np.ndarray):
|
||||
image = PIL.Image.fromarray(image)
|
||||
elif isinstance(image, torch.Tensor):
|
||||
image = vF.to_pil_image(image)
|
||||
image = images_sharpfin.to_pil(image)
|
||||
else:
|
||||
raise TypeError(f"Image must be of type PIL.Image, np.ndarray, or torch.Tensor, got {type(image)} instead.")
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ from packaging import version
|
||||
import PIL.Image
|
||||
import numpy as np
|
||||
import torch
|
||||
import torchvision
|
||||
from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTextModelWithProjection, CLIPTokenizer
|
||||
from diffusers.image_processor import VaeImageProcessor
|
||||
from diffusers.loaders import FromSingleFileMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
||||
@@ -859,7 +858,8 @@ class StableDiffusionXLDiffImg2ImgPipeline(DiffusionPipeline, FromSingleFileMixi
|
||||
|
||||
# 4. Preprocess image
|
||||
#image = self.image_processor.preprocess(image) #ideally we would have preprocess the image with diffusers, but for this POC we won't --- it throws a deprecated warning
|
||||
map = torchvision.transforms.Resize(tuple(s // self.vae_scale_factor for s in original_image.shape[2:]),antialias=None)(map)
|
||||
from modules import images_sharpfin
|
||||
map = images_sharpfin.resize_tensor(map, tuple(s // self.vae_scale_factor for s in original_image.shape[2:]), linearize=False)
|
||||
# 5. Prepare timesteps
|
||||
def denoising_value_valid(dnv):
|
||||
return type(denoising_end) == float and 0 < dnv < 1
|
||||
@@ -1758,7 +1758,8 @@ class StableDiffusionDiffImg2ImgPipeline(DiffusionPipeline):
|
||||
|
||||
# 7. Prepare extra step kwargs.
|
||||
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
|
||||
map = torchvision.transforms.Resize(tuple(s // self.vae_scale_factor for s in image.shape[2:]),antialias=None)(map)
|
||||
from modules import images_sharpfin
|
||||
map = images_sharpfin.resize_tensor(map, tuple(s // self.vae_scale_factor for s in image.shape[2:]), linearize=False)
|
||||
|
||||
# 8. Denoising loop
|
||||
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
||||
@@ -1833,8 +1834,7 @@ class StableDiffusionDiffImg2ImgPipeline(DiffusionPipeline):
|
||||
import gradio as gr
|
||||
import diffusers
|
||||
from PIL import Image, ImageEnhance, ImageOps # pylint: disable=reimported
|
||||
from torchvision import transforms
|
||||
from modules import errors, shared, devices, scripts_manager, processing, sd_models, images
|
||||
from modules import errors, shared, devices, scripts_manager, processing, sd_models, images, images_sharpfin
|
||||
|
||||
|
||||
detector = None
|
||||
@@ -1888,9 +1888,9 @@ class Script(scripts_manager.Script):
|
||||
else:
|
||||
return None, None, None
|
||||
image_mask = image_map.copy()
|
||||
image_map = transforms.ToTensor()(image_map)
|
||||
image_map = images_sharpfin.to_tensor(image_map)
|
||||
image_map = image_map.to(devices.device)
|
||||
image_init = 2 * transforms.ToTensor()(image_init) - 1
|
||||
image_init = 2 * images_sharpfin.to_tensor(image_init) - 1
|
||||
image_init = image_init.unsqueeze(0)
|
||||
image_init = image_init.to(devices.device)
|
||||
return image_init, image_map, image_mask
|
||||
|
||||
+3
-3
@@ -84,7 +84,7 @@ class Script(scripts_manager.Script):
|
||||
from installer import install
|
||||
install('lpips')
|
||||
|
||||
from torchvision.transforms import ToPILImage, ToTensor
|
||||
from modules import images_sharpfin
|
||||
from scripts.lbm import get_model, extract_object, resize_and_center_crop # pylint: disable=no-name-in-module
|
||||
|
||||
ori_h_bg, ori_w_bg = fg_image.size
|
||||
@@ -110,7 +110,7 @@ class Script(scripts_manager.Script):
|
||||
if lbm_method == 'Simple':
|
||||
output_image = img_pasted
|
||||
else:
|
||||
img_pasted_tensor = ToTensor()(img_pasted).to(device=devices.device, dtype=devices.dtype).unsqueeze(0) * 2 - 1
|
||||
img_pasted_tensor = images_sharpfin.to_tensor(img_pasted).to(device=devices.device, dtype=devices.dtype).unsqueeze(0) * 2 - 1
|
||||
batch = { "source_image": img_pasted_tensor }
|
||||
z_source = model.vae.encode(batch[model.source_key])
|
||||
output_image = model.sample(
|
||||
@@ -120,7 +120,7 @@ class Script(scripts_manager.Script):
|
||||
max_samples=1,
|
||||
)
|
||||
output_image = (output_image[0].clamp(-1, 1).float().cpu() + 1) / 2
|
||||
output_image = ToPILImage()(output_image)
|
||||
output_image = images_sharpfin.to_pil(output_image)
|
||||
if lbm_composite:
|
||||
output_image = Image.composite(output_image, bg_image, fg_mask)
|
||||
|
||||
|
||||
@@ -26,17 +26,13 @@ class Script(scripts_manager.Script):
|
||||
def encode(self, p: processing.StableDiffusionProcessing, image: Image.Image):
|
||||
if image is None:
|
||||
return None
|
||||
import numpy as np
|
||||
import torch
|
||||
from modules import images_sharpfin
|
||||
if p.width is None or p.width == 0:
|
||||
p.width = int(8 * (image.width * p.scale_by // 8))
|
||||
if p.height is None or p.height == 0:
|
||||
p.height = int(8 * (image.height * p.scale_by // 8))
|
||||
image = images.resize_image(p.resize_mode, image, p.width, p.height, upscaler_name=p.resize_name, context=p.resize_context)
|
||||
tensor = np.array(image).astype(np.float16) / 255.0
|
||||
tensor = tensor[None].transpose(0, 3, 1, 2)
|
||||
# image = image.transpose(0, 3, 1, 2)
|
||||
tensor = torch.from_numpy(tensor).to(device=devices.device, dtype=devices.dtype)
|
||||
tensor = images_sharpfin.to_tensor(image).unsqueeze(0).to(device=devices.device, dtype=devices.dtype)
|
||||
tensor = 2.0 * tensor - 1.0
|
||||
with devices.inference_context():
|
||||
latent = shared.sd_model.vae.tiled_encode(tensor)
|
||||
|
||||
+6
-6
@@ -18,7 +18,6 @@ import cv2
|
||||
import numpy as np
|
||||
from PIL import Image, ImageFilter
|
||||
import torch
|
||||
import torchvision
|
||||
from torchvision import transforms
|
||||
from transformers import (
|
||||
CLIPImageProcessor,
|
||||
@@ -1323,7 +1322,8 @@ class StableDiffusionXLSoftFillPipeline(
|
||||
image.save("noised_image.png")
|
||||
|
||||
image = transforms.CenterCrop((image.size[1] // 64 * 64, image.size[0] // 64 * 64))(image)
|
||||
image = transforms.ToTensor()(image)
|
||||
from modules import images_sharpfin
|
||||
image = images_sharpfin.to_tensor(image)
|
||||
image = image * 2 - 1 # Normalize to [-1, 1]
|
||||
return image.unsqueeze(0)
|
||||
|
||||
@@ -1334,7 +1334,8 @@ class StableDiffusionXLSoftFillPipeline(
|
||||
"""
|
||||
map = map.convert("L")
|
||||
map = transforms.CenterCrop((map.size[1] // 64 * 64, map.size[0] // 64 * 64))(map)
|
||||
map = transforms.ToTensor()(map)
|
||||
from modules import images_sharpfin
|
||||
map = images_sharpfin.to_tensor(map)
|
||||
map = (map - 0.05) / (0.95 - 0.05)
|
||||
map = torch.clamp(map, 0.0, 1.0)
|
||||
return 1.0 - map
|
||||
@@ -1349,9 +1350,8 @@ class StableDiffusionXLSoftFillPipeline(
|
||||
|
||||
# Prepare mask as rescaled tensor map
|
||||
map = preprocess_map(mask).to(device)
|
||||
map = torchvision.transforms.Resize(
|
||||
tuple(s // self.vae_scale_factor for s in original_image_tensor.shape[2:]), antialias=None
|
||||
)(map)
|
||||
from modules import images_sharpfin
|
||||
map = images_sharpfin.resize_tensor(map, tuple(s // self.vae_scale_factor for s in original_image_tensor.shape[2:]), linearize=False)
|
||||
|
||||
# Generate latent tensor with noise
|
||||
original_with_noise = self.prepare_latents(
|
||||
|
||||
Reference in New Issue
Block a user