Merge pull request #15583 from AUTOMATIC1111/get_crop_region_v2
get_crop_region_v2
This commit is contained in:
commit
e6a8d0b4e6
|
@ -1,17 +1,39 @@
|
||||||
from PIL import Image, ImageFilter, ImageOps
|
from PIL import Image, ImageFilter, ImageOps
|
||||||
|
|
||||||
|
|
||||||
def get_crop_region(mask, pad=0):
|
def get_crop_region_v2(mask, pad=0):
|
||||||
"""finds a rectangular region that contains all masked ares in an image. Returns (x1, y1, x2, y2) coordinates of the rectangle.
|
"""
|
||||||
For example, if a user has painted the top-right part of a 512x512 image, the result may be (256, 0, 512, 256)"""
|
Finds a rectangular region that contains all masked ares in a mask.
|
||||||
mask_img = mask if isinstance(mask, Image.Image) else Image.fromarray(mask)
|
Returns None if mask is completely black mask (all 0)
|
||||||
box = mask_img.getbbox()
|
|
||||||
if box:
|
Parameters:
|
||||||
|
mask: PIL.Image.Image L mode or numpy 1d array
|
||||||
|
pad: int number of pixels that the region will be extended on all sides
|
||||||
|
Returns: (x1, y1, x2, y2) | None
|
||||||
|
|
||||||
|
Introduced post 1.9.0
|
||||||
|
"""
|
||||||
|
mask = mask if isinstance(mask, Image.Image) else Image.fromarray(mask)
|
||||||
|
if box := mask.getbbox():
|
||||||
x1, y1, x2, y2 = box
|
x1, y1, x2, y2 = box
|
||||||
else: # when no box is found
|
return max(x1 - pad, 0), max(y1 - pad, 0), min(x2 + pad, mask.size[0]), min(y2 + pad, mask.size[1]) if pad else box
|
||||||
x1, y1 = mask_img.size
|
|
||||||
|
|
||||||
|
def get_crop_region(mask, pad=0):
|
||||||
|
"""
|
||||||
|
Same function as get_crop_region_v2 but handles completely black mask (all 0) differently
|
||||||
|
when mask all black still return coordinates but the coordinates may be invalid ie x2>x1 or y2>y1
|
||||||
|
Notes: it is possible for the coordinates to be "valid" again if pad size is sufficiently large
|
||||||
|
(mask_size.x-pad, mask_size.y-pad, pad, pad)
|
||||||
|
|
||||||
|
Extension developer should use get_crop_region_v2 instead unless for compatibility considerations.
|
||||||
|
"""
|
||||||
|
mask = mask if isinstance(mask, Image.Image) else Image.fromarray(mask)
|
||||||
|
if box := get_crop_region_v2(mask, pad):
|
||||||
|
return box
|
||||||
|
x1, y1 = mask.size
|
||||||
x2 = y2 = 0
|
x2 = y2 = 0
|
||||||
return max(x1 - pad, 0), max(y1 - pad, 0), min(x2 + pad, mask_img.size[0]), min(y2 + pad, mask_img.size[1])
|
return max(x1 - pad, 0), max(y1 - pad, 0), min(x2 + pad, mask.size[0]), min(y2 + pad, mask.size[1])
|
||||||
|
|
||||||
|
|
||||||
def expand_crop_region(crop_region, processing_width, processing_height, image_width, image_height):
|
def expand_crop_region(crop_region, processing_width, processing_height, image_width, image_height):
|
||||||
|
|
|
@ -1611,19 +1611,23 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||||
if self.inpaint_full_res:
|
if self.inpaint_full_res:
|
||||||
self.mask_for_overlay = image_mask
|
self.mask_for_overlay = image_mask
|
||||||
mask = image_mask.convert('L')
|
mask = image_mask.convert('L')
|
||||||
crop_region = masking.get_crop_region(mask, self.inpaint_full_res_padding)
|
crop_region = masking.get_crop_region_v2(mask, self.inpaint_full_res_padding)
|
||||||
if crop_region[0] >= crop_region[2] and crop_region[1] >= crop_region[3]:
|
if crop_region:
|
||||||
crop_region = None
|
|
||||||
image_mask = None
|
|
||||||
self.mask_for_overlay = None
|
|
||||||
else:
|
|
||||||
crop_region = masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height)
|
crop_region = masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height)
|
||||||
x1, y1, x2, y2 = crop_region
|
x1, y1, x2, y2 = crop_region
|
||||||
mask = mask.crop(crop_region)
|
mask = mask.crop(crop_region)
|
||||||
image_mask = images.resize_image(2, mask, self.width, self.height)
|
image_mask = images.resize_image(2, mask, self.width, self.height)
|
||||||
|
self.inpaint_full_res = False
|
||||||
self.paste_to = (x1, y1, x2-x1, y2-y1)
|
self.paste_to = (x1, y1, x2-x1, y2-y1)
|
||||||
self.extra_generation_params["Inpaint area"] = "Only masked"
|
self.extra_generation_params["Inpaint area"] = "Only masked"
|
||||||
self.extra_generation_params["Masked area padding"] = self.inpaint_full_res_padding
|
self.extra_generation_params["Masked area padding"] = self.inpaint_full_res_padding
|
||||||
|
else:
|
||||||
|
crop_region = None
|
||||||
|
image_mask = None
|
||||||
|
self.mask_for_overlay = None
|
||||||
|
massage = 'Unable to perform "Inpaint Only mask" because mask is blank, switch to img2img mode.'
|
||||||
|
model_hijack.comments.append(massage)
|
||||||
|
logging.info(massage)
|
||||||
else:
|
else:
|
||||||
image_mask = images.resize_image(self.resize_mode, image_mask, self.width, self.height)
|
image_mask = images.resize_image(self.resize_mode, image_mask, self.width, self.height)
|
||||||
np_mask = np.array(image_mask)
|
np_mask = np.array(image_mask)
|
||||||
|
|
Loading…
Reference in New Issue