Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inpaint with only masked downscale the original image #12

Closed
2blackbar opened this issue Aug 1, 2023 · 3 comments · Fixed by #19
Closed

Inpaint with only masked downscale the original image #12

2blackbar opened this issue Aug 1, 2023 · 3 comments · Fixed by #19

Comments

@2blackbar
Copy link

When i go to inpaint and choose only masked instead of whole picture, it should preserve resolution of original imave even if its 4k image, and it does when this extension is not in use, but when i enable this extension, it will downscale all images to pixelater versions , its pretty weird and its a serious pipeline bug that degrades all images i run through it .
You can test it with images with text, choose onlyu masked and face swap with this extension, resulting image will have pixelated text which is clearly much lower resolution.
So default behaviour should be - when i dont mask anything and i use hires picture, faceswaplab should be able to isolate the face from that image , then inpaint just the face, then paste face back into the image without degrading resolution, it does work like this when we mask only the face but it would be much better if faceswaplab did it on its own since it can recognize the face .

@glucauze
Copy link
Owner

glucauze commented Aug 1, 2023

Could put a link to a photo that poses a problem? I'll have to check for myself.

The function that adds the mask to the last part is as follows (in imgutils):

def apply_mask(
    img: PILImage, p: processing.StableDiffusionProcessing, batch_index: int
) -> PILImage:
    """
    Apply mask overlay and color correction to an image if enabled

    Args:
        img: PIL Image objects.
        p : The processing object
        batch_index : the batch index

    Returns:
        PIL Image object
    """
    if isinstance(p, processing.StableDiffusionProcessingImg2Img):
        if p.inpaint_full_res:
            overlays = p.overlay_images
            if overlays is None or batch_index >= len(overlays):
                return img
            overlay: PILImage = overlays[batch_index]

# This is probably the thing that's causing the problem but this is necessary to merge the two images :
            overlay = overlay.resize((img.size), resample=Image.Resampling.LANCZOS)
            img = img.copy()
            img.paste(overlay, (0, 0), overlay)
            return img

        img = processing.apply_overlay(img, p.paste_to, batch_index, p.overlay_images)
        if p.color_corrections is not None and batch_index < len(p.color_corrections):
            img = processing.apply_color_correction(
                p.color_corrections[batch_index], img
            )
    return img

I changed the title of the issue to be a little less dramatic ;) Even if I recognize that the problem is painful. My hunch is that the resize part is not suitable. But we need to find a solution to do this better.

@glucauze glucauze changed the title MAjor issue with scaling in inpaint Inpaint with only masked downscale the original image Aug 1, 2023
@glucauze
Copy link
Owner

glucauze commented Aug 1, 2023

It seems that resizing is not always necessary. You could try that :

def apply_mask(
    img: PILImage, p: processing.StableDiffusionProcessing, batch_index: int
) -> PILImage:
    """
    Apply mask overlay and color correction to an image if enabled

    Args:
        img: PIL Image objects.
        p : The processing object
        batch_index : the batch index

    Returns:
        PIL Image object
    """
    if isinstance(p, processing.StableDiffusionProcessingImg2Img):
        if p.inpaint_full_res:
            overlays = p.overlay_images
            if overlays is None or batch_index >= len(overlays):
                return img
            overlay: PILImage = overlays[batch_index]
            logger.debug("Overlay size %s, Image size %s", overlay.size, img.size)
            if overlay.size != img.size :
                overlay = overlay.resize((img.size), resample=Image.Resampling.LANCZOS)
            img = img.copy()
            img.paste(overlay, (0, 0), overlay)
            return img

        img = processing.apply_overlay(img, p.paste_to, batch_index, p.overlay_images)
        if p.color_corrections is not None and batch_index < len(p.color_corrections):
            img = processing.apply_color_correction(
                p.color_corrections[batch_index], img
            )
    return img

I wonder if resizing is necessary only when the image dimensions are not exactly multiples of 16. I'd had bugs when I didn't resize. That's why I did it without thinking too much about it. I don't use a lot of hd images.

@glucauze
Copy link
Owner

glucauze commented Aug 3, 2023

Based on my tests, version 1.2.0 should solve this problem.

@glucauze glucauze linked a pull request Aug 3, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants