diff --git a/README.md b/README.md index 05dc4c8..28babf1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# NSFW-Roop 0.1.0 for StableDiffusion +# Roop-GE 0.2.0 for StableDiffusion ### NSFW (uncensored) version (use it on your own responsibility) of [original sd-webui-roop](https://github.com/s0md3v/sd-webui-roop) with a lot of improvements +> GE (Gourieff Edition), aka "NSFW-Roop" + This is an extension for StableDiffusion's [AUTOMATIC1111 web-ui](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) that allows face-replacement in images. It is based on [Roop-GE](https://github.com/Gourieff/Roop-GE). example @@ -26,9 +28,15 @@ To install the extension, follow these steps: ## Usage -1. Under "NSFW-Roop" drop-down menu, import an image containing a face. -2. Turn on the "Enable" checkbox -3. That's it, now the generated result will have the face you selected +1. Under "Roop-GE" drop-down menu, import an image containing a face; +2. Turn on the "Enable" checkbox; +3. That's it, now the generated result will have the face you selected. + +**You can use Roop-GE with Webui API:** +1. Check the [SD Web API Wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/API) for how to use API; +2. Call `requests.get(url=f'{address}/sdapi/v1/script-info')` to find the args that Roop-GE needs; +3. Define Roop-GE script args and add like this `"alwayson_scripts": {"roop-ge":{"args":args}}` in the payload; +4. Call the API, there's an [full usage example](./example/api_example.py) in example folder. ### The result face is blurry Use the "Restore Face" option. You can also try the "Upscaler" option or for more finer control, use an upscaler from the "Extras" tab. diff --git a/scripts/faceswap.py b/scripts/faceswap.py index 9ee7ce3..5880a46 100644 --- a/scripts/faceswap.py +++ b/scripts/faceswap.py @@ -26,13 +26,13 @@ def get_models(): class FaceSwapScript(scripts.Script): def title(self): - return f"NSFW-Roop" + return f"Roop-GE" def show(self, is_img2img): return scripts.AlwaysVisible def ui(self, is_img2img): - with gr.Accordion(f"NSFW-Roop {version_flag}", open=False): + with gr.Accordion(f"Roop-GE {version_flag}", open=False): with gr.Column(): img = gr.inputs.Image(type="pil") enable = gr.Checkbox(False, placeholder="enable", label="Enable") @@ -179,7 +179,7 @@ class FaceSwapScript(scripts.Script): if self.enable: if self.source is not None: if isinstance(p, StableDiffusionProcessingImg2Img) and swap_in_source: - logger.info(f"NSFW-Roop is enabled, face index %s", self.faces_index) + logger.info(f"Roop-GE is enabled, face index %s", self.faces_index) for i in range(len(p.init_images)): logger.info(f"Swap in source %s", i) diff --git a/scripts/roop_logging.py b/scripts/roop_logging.py index 718329e..cd547f7 100644 --- a/scripts/roop_logging.py +++ b/scripts/roop_logging.py @@ -24,7 +24,7 @@ class ColoredFormatter(logging.Formatter): # Create a new logger -logger = logging.getLogger("NSFW-Roop") +logger = logging.getLogger("Roop-GE") logger.propagate = False # Add handler if we don't have one. diff --git a/scripts/roop_version.py b/scripts/roop_version.py index bfba7c4..d369de9 100644 --- a/scripts/roop_version.py +++ b/scripts/roop_version.py @@ -1,5 +1,5 @@ -version_flag = "v0.1.0" +version_flag = "v0.2.0" from scripts.roop_logging import logger -logger.info(f"NSFW-Roop {version_flag}") +logger.info(f"Roop-GE {version_flag}") diff --git a/scripts/swapper.py b/scripts/swapper.py index a996caf..a3d5e3e 100644 --- a/scripts/swapper.py +++ b/scripts/swapper.py @@ -66,7 +66,7 @@ def upscale_image(image: Image, upscale_options: UpscaleOptions): if upscale_options.do_restore_first: if upscale_options.face_restorer is not None: original_image = result_image.copy() - logger.info("1. Restore face with %s", upscale_options.face_restorer.name()) + logger.info("Restore face with %s", upscale_options.face_restorer.name()) numpy_image = np.array(result_image) numpy_image = upscale_options.face_restorer.restore(numpy_image) restored_image = Image.fromarray(numpy_image) @@ -76,7 +76,7 @@ def upscale_image(image: Image, upscale_options: UpscaleOptions): if upscale_options.upscaler is not None and upscale_options.upscaler.name != "None": original_image = result_image.copy() logger.info( - "2. Upscale with %s scale = %s", + "Upscale with %s scale = %s", upscale_options.upscaler.name, upscale_options.scale, ) @@ -91,7 +91,7 @@ def upscale_image(image: Image, upscale_options: UpscaleOptions): if upscale_options.upscaler is not None and upscale_options.upscaler.name != "None": original_image = result_image.copy() logger.info( - "1. Upscale with %s scale = %s", + "Upscale with %s scale = %s", upscale_options.upscaler.name, upscale_options.scale, ) @@ -104,7 +104,7 @@ def upscale_image(image: Image, upscale_options: UpscaleOptions): ) if upscale_options.face_restorer is not None: original_image = result_image.copy() - logger.info("2. Restore face with %s", upscale_options.face_restorer.name()) + logger.info("Restore face with %s", upscale_options.face_restorer.name()) numpy_image = np.array(result_image) numpy_image = upscale_options.face_restorer.restore(numpy_image) restored_image = Image.fromarray(numpy_image) @@ -152,6 +152,20 @@ def swap_face( result_image = target_img fn = tempfile.NamedTemporaryFile(delete=False, suffix=".png") if model is not None: + + if isinstance(source_img, str): # source_img is a base64 string + import base64, io + if 'base64,' in source_img: # check if the base64 string has a data URL scheme + # split the base64 string to get the actual base64 encoded image data + base64_data = source_img.split('base64,')[-1] + # decode base64 string to bytes + img_bytes = base64.b64decode(base64_data) + else: + # if no data URL scheme, just decode + img_bytes = base64.b64decode(source_img) + + source_img = Image.open(io.BytesIO(img_bytes)) + source_img = cv2.cvtColor(np.array(source_img), cv2.COLOR_RGB2BGR) target_img = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR) source_face = get_face_single(source_img, face_index=source_faces_index[0])