Skip to content

Commit d999054

Browse files
authored
🔨 Extract pixel perfect calculation (AUTOMATIC1111#1522)
1 parent d4db708 commit d999054

File tree

4 files changed

+81
-40
lines changed

4 files changed

+81
-40
lines changed

scripts/controlnet.py

+6-20
Original file line numberDiff line numberDiff line change
@@ -716,26 +716,12 @@ def process(self, p, *args):
716716

717717
preprocessor_resolution = unit.processor_res
718718
if unit.pixel_perfect:
719-
raw_H, raw_W, _ = input_image.shape
720-
target_H, target_W = h, w
721-
722-
k0 = float(target_H) / float(raw_H)
723-
k1 = float(target_W) / float(raw_W)
724-
725-
if resize_mode == external_code.ResizeMode.OUTER_FIT:
726-
estimation = min(k0, k1) * float(min(raw_H, raw_W))
727-
else:
728-
estimation = max(k0, k1) * float(min(raw_H, raw_W))
729-
730-
preprocessor_resolution = int(np.round(estimation))
731-
732-
print(f'Pixel Perfect Mode Enabled.')
733-
print(f'resize_mode = {str(resize_mode)}')
734-
print(f'raw_H = {raw_H}')
735-
print(f'raw_W = {raw_W}')
736-
print(f'target_H = {target_H}')
737-
print(f'target_W = {target_W}')
738-
print(f'estimation = {estimation}')
719+
preprocessor_resolution = external_code.pixel_perfect_resolution(
720+
input_image,
721+
target_H=h,
722+
target_W=w,
723+
resize_mode=resize_mode
724+
)
739725

740726
print(f'preprocessor resolution = {preprocessor_resolution}')
741727
detected_map, is_image = preprocessor(input_image, res=preprocessor_resolution, thr_a=unit.threshold_a, thr_b=unit.threshold_b)

scripts/controlnet_ui/controlnet_ui_group.py

+6-20
Original file line numberDiff line numberDiff line change
@@ -608,26 +608,12 @@ def run_annotator(image, module, pres, pthr_a, pthr_b, t2i_w, t2i_h, pp, rm):
608608
preprocessor = self.preprocessors[module]
609609

610610
if pp:
611-
raw_H, raw_W, _ = img.shape
612-
target_H, target_W = t2i_h, t2i_w
613-
rm = str(rm)
614-
615-
k0 = float(target_H) / float(raw_H)
616-
k1 = float(target_W) / float(raw_W)
617-
618-
if rm == external_code.ResizeMode.OUTER_FIT.value:
619-
estimation = min(k0, k1) * float(min(raw_H, raw_W))
620-
else:
621-
estimation = max(k0, k1) * float(min(raw_H, raw_W))
622-
623-
pres = int(np.round(estimation))
624-
print(f"Pixel Perfect Mode Enabled In Preview.")
625-
print(f"resize_mode = {rm}")
626-
print(f"raw_H = {raw_H}")
627-
print(f"raw_W = {raw_W}")
628-
print(f"target_H = {target_H}")
629-
print(f"target_W = {target_W}")
630-
print(f"estimation = {estimation}")
611+
pres = external_code.pixel_perfect_resolution(
612+
img,
613+
target_H=t2i_h,
614+
target_W=t2i_w,
615+
resize_mode=external_code.resize_mode_from_value(rm),
616+
)
631617

632618
class JsonAcceptor:
633619
def __init__(self) -> None:

scripts/external_code.py

+51
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,57 @@ def control_mode_from_value(value: Union[str, int, ControlMode]) -> ControlMode:
6565
return [e for e in ControlMode][value]
6666
else:
6767
return value
68+
69+
70+
def pixel_perfect_resolution(
71+
image: np.ndarray,
72+
target_H: int,
73+
target_W: int,
74+
resize_mode: ResizeMode,
75+
) -> int:
76+
"""
77+
Calculate the estimated resolution for resizing an image while preserving aspect ratio.
78+
79+
The function first calculates scaling factors for height and width of the image based on the target
80+
height and width. Then, based on the chosen resize mode, it either takes the smaller or the larger
81+
scaling factor to estimate the new resolution.
82+
83+
If the resize mode is OUTER_FIT, the function uses the smaller scaling factor, ensuring the whole image
84+
fits within the target dimensions, potentially leaving some empty space.
85+
86+
If the resize mode is not OUTER_FIT, the function uses the larger scaling factor, ensuring the target
87+
dimensions are fully filled, potentially cropping the image.
88+
89+
After calculating the estimated resolution, the function prints some debugging information.
90+
91+
Args:
92+
image (np.ndarray): A 3D numpy array representing an image. The dimensions represent [height, width, channels].
93+
target_H (int): The target height for the image.
94+
target_W (int): The target width for the image.
95+
resize_mode (ResizeMode): The mode for resizing.
96+
97+
Returns:
98+
int: The estimated resolution after resizing.
99+
"""
100+
raw_H, raw_W, _ = image.shape
101+
102+
k0 = float(target_H) / float(raw_H)
103+
k1 = float(target_W) / float(raw_W)
104+
105+
if resize_mode == ResizeMode.OUTER_FIT:
106+
estimation = min(k0, k1) * float(min(raw_H, raw_W))
107+
else:
108+
estimation = max(k0, k1) * float(min(raw_H, raw_W))
109+
110+
print(f"Pixel Perfect Mode Enabled In Preview.")
111+
print(f"resize_mode = {resize_mode}")
112+
print(f"raw_H = {raw_H}")
113+
print(f"raw_W = {raw_W}")
114+
print(f"target_H = {target_H}")
115+
print(f"target_W = {target_W}")
116+
print(f"estimation = {estimation}")
117+
118+
return int(np.round(estimation))
68119

69120

70121
InputImage = Union[np.ndarray, str]

tests/external_code_api/external_code_test.py

+18
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,23 @@ def test_masked_image_dict(self):
116116
self.assert_dict_is_valid()
117117

118118

119+
class TestPixelPerfectResolution(unittest.TestCase):
120+
def test_outer_fit(self):
121+
image = np.zeros((100, 100, 3))
122+
target_H, target_W = 50, 100
123+
resize_mode = external_code.ResizeMode.OUTER_FIT
124+
result = external_code.pixel_perfect_resolution(image, target_H, target_W, resize_mode)
125+
expected = 50 # manually computed expected result
126+
self.assertEqual(result, expected)
127+
128+
def test_inner_fit(self):
129+
image = np.zeros((100, 100, 3))
130+
target_H, target_W = 50, 100
131+
resize_mode = external_code.ResizeMode.INNER_FIT
132+
result = external_code.pixel_perfect_resolution(image, target_H, target_W, resize_mode)
133+
expected = 100 # manually computed expected result
134+
self.assertEqual(result, expected)
135+
136+
119137
if __name__ == '__main__':
120138
unittest.main()

0 commit comments

Comments
 (0)