diff --git a/CHANGELOG.md b/CHANGELOG.md index f56b8fe9f..d5bd3c84f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,16 @@ # Change Log for SD.Next -## Update for 2026-07-28 +## Update for 2026-07-30 - **Features** - startup: optimized server startup - process: preserve audio when processing video - video: support for scripts/extensions - prompt enhance: support for video generation + - remove background: add [lucida](https://huggingface.co/egeorcun/lucida) model - **Fixes** - seedvr quality + - skip-all do not skip env init ## Update for 2026-07-23 diff --git a/launch.py b/launch.py index c80031380..e3b0b995e 100755 --- a/launch.py +++ b/launch.py @@ -254,7 +254,7 @@ def main(): installer.check_version() installer.check_venv() log.info(f'Args: {sys.argv[1:]}') - if not args.skip_env and not args.skip_all: + if not args.skip_env: installer.set_environment() if args.uv and shutil.which('uv') is None: installer.install('uv', 'uv') diff --git a/modules/rembg/lucida.py b/modules/rembg/lucida.py new file mode 100644 index 000000000..9976cbc3a --- /dev/null +++ b/modules/rembg/lucida.py @@ -0,0 +1,39 @@ +model = None +repo_id = "egeorcun/lucida" + + +def remove(image): + import torch + from PIL import Image + from torchvision import transforms + from transformers import AutoModelForImageSegmentation + from modules import devices + + global model # pylint: disable=global-statement + + if model is None: + model = AutoModelForImageSegmentation.from_pretrained(repo_id, + trust_remote_code=True, + dtype=torch.float32, + ) + model.eval() + + t = transforms.Compose([ + transforms.Resize((1024, 1024)), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ]) + model = model.to(device=devices.device) + with devices.inference_context(): + input_tensor = t(image).unsqueeze(0).to(devices.device) + preds = model(input_tensor)[-1].sigmoid() + alpha = transforms.functional.resize(preds[0], image.size[::-1]).squeeze(0) + alpha = alpha.detach().cpu().numpy() + model = model.to(device=devices.cpu) + + rgba = image.copy() + rgba.putalpha(Image.fromarray((255.0 * alpha).astype("uint8"))) + + if rgba is None: + return image + return rgba diff --git a/modules/rembg/rembg_api.py b/modules/rembg/rembg_api.py index e4ab757bd..0bb30f4dd 100644 --- a/modules/rembg/rembg_api.py +++ b/modules/rembg/rembg_api.py @@ -28,6 +28,9 @@ async def post_rembg( if model == "ben2": from modules.rembg import ben2 image = ben2.remove(input_image, refine=refine) + elif model == "lucida": + from modules.rembg import lucida + image = lucida.remove(input_image) else: dependencies() import rembg diff --git a/scripts/postprocessing_rembg.py b/scripts/postprocessing_rembg.py index ca350b968..4068f958b 100644 --- a/scripts/postprocessing_rembg.py +++ b/scripts/postprocessing_rembg.py @@ -1,11 +1,11 @@ import os import gradio as gr from PIL import Image -from modules import scripts_postprocessing - +from modules import errors, scripts_postprocessing models = [ "none", + "lucida", "ben2", "silueta", "u2net", @@ -84,6 +84,15 @@ class ScriptPostprocessingRembg(scripts_postprocessing.ScriptPostprocessing): image = ben2.remove(image, refine=refine) except Exception as e: log.error(f'RemoveBackground: model={model} {e}') + errors.display(e, 'Rembg model=ben2') + return pp + elif model == 'lucida': + try: + from modules.rembg import lucida + image = lucida.remove(image) + except Exception as e: + log.error(f'RemoveBackground: model={model} {e}') + errors.display(e, 'Rembg model=lucida') return pp else: try: @@ -101,6 +110,7 @@ class ScriptPostprocessingRembg(scripts_postprocessing.ScriptPostprocessing): session=rembg.new_session(model)) except Exception as e: log.error(f'RemoveBackground: model={model} {e}') + errors.display(e, f'Rembg model={model}') return pp if mask_only and image.mode == "RGBA": diff --git a/wiki b/wiki index ea41a43b4..ee4e24dbb 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit ea41a43b4458319e2716c01a8c4eee08dc5d89c1 +Subproject commit ee4e24dbb80ac1c9b110271f49f44b0f23e1271c