diff --git a/modules/masking.py b/modules/masking.py index 2fc83031953..3423f00713e 100644 --- a/modules/masking.py +++ b/modules/masking.py @@ -77,6 +77,33 @@ def expand_crop_region(crop_region, processing_width, processing_height, image_w return x1, y1, x2, y2 +def expand_too_small_crop_region(crop_region, processing_width, processing_height, image_width, image_height): + """expands a crop_region to not have dimensions smaller than processing_dimensions""" + + def _expand_segment(c1, c2, desirable_length, maximal_coordinate): + """expands the segment given by c1 c2 to the desired_dimension but not exceeding the boundaries of the maximal_coordinate""" + if (diff := desirable_length + c1 - c2) > 0: + # if the region is smaller than desirable_length, extend both sides equally + diff_l = diff // 2 + c1 -= diff_l + c2 += diff - diff_l + if c1 < 0: # shift the region to the right by c1 + c2 = min(c2 - c1, maximal_coordinate) # ensure c2 is within maximal_coordinate + c1 = 0 + elif c2 >= maximal_coordinate: # shift the region to the left by (c2 - maximal_coordinate) + c1 = max(c1 - c2 + maximal_coordinate, 0) # ensure c1 is not below 0 + c2 = maximal_coordinate + return c1, c2 + + x1, y1, x2, y2 = crop_region + x1, x2 = _expand_segment(x1, x2, processing_width, image_width) + y1, y2 = _expand_segment(y1, y2, processing_height, image_height) + new_crop_region = x1, y1, x2, y2 + if new_crop_region != crop_region: + print("Crop region was smaller then resolution and has been corrected") + return new_crop_region + + def fill(image, mask): """fills masked regions with colors from image using blur. Not extremely effective.""" diff --git a/modules/processing.py b/modules/processing.py index 7535b56e18c..163375c3e33 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -1639,6 +1639,8 @@ def init(self, all_prompts, all_seeds, all_subseeds): crop_region = masking.get_crop_region_v2(mask, self.inpaint_full_res_padding) if crop_region: crop_region = masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height) + if shared.opts.forbid_too_small_crop_region: + crop_region = masking.expand_too_small_crop_region(crop_region, self.width, self.height, mask.width, mask.height) x1, y1, x2, y2 = crop_region mask = mask.crop(crop_region) image_mask = images.resize_image(2, mask, self.width, self.height) diff --git a/modules/shared_options.py b/modules/shared_options.py index 9f4520274b1..b6275d12418 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -227,6 +227,7 @@ "return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results for web"), "img2img_batch_show_results_limit": OptionInfo(32, "Show the first N batch img2img results in UI", gr.Slider, {"minimum": -1, "maximum": 1000, "step": 1}).info('0: disable, -1: show all images. Too many images can cause lag'), "overlay_inpaint": OptionInfo(True, "Overlay original for inpaint").info("when inpainting, overlay the original image over the areas that weren't inpainted."), + "forbid_too_small_crop_region": OptionInfo(False, "Forbid too small crop region").info("Correct inpaint padding for only masked to avoid crop region sides less then processing resolution"), })) options_templates.update(options_section(('optimizations', "Optimizations", "sd"), {