Spaces:
Paused
Paused
Fix pad
Browse files
app.py
CHANGED
@@ -80,45 +80,105 @@ def make_example(image_path: Path, mask_path: Path) -> EditorValue:
|
|
80 |
}
|
81 |
|
82 |
|
83 |
-
def
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
|
92 |
def adjust_bbox_to_divisible_16(
|
93 |
-
x_min
|
94 |
-
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
x_min = max(x_min - padding, 0)
|
97 |
y_min = max(y_min - padding, 0)
|
98 |
x_max = min(x_max + padding, width)
|
99 |
y_max = min(y_max + padding, height)
|
100 |
|
101 |
-
# Calculate current bbox width and height
|
102 |
-
bbox_width = x_max - x_min
|
103 |
-
bbox_height = y_max - y_min
|
104 |
-
|
105 |
# Ensure bbox dimensions are divisible by 16
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
|
|
117 |
x_min = max(x_min, 0)
|
118 |
y_min = max(y_min, 0)
|
119 |
x_max = min(x_max, width)
|
120 |
y_max = min(y_max, height)
|
121 |
|
|
|
|
|
|
|
|
|
122 |
return x_min, y_min, x_max, y_max
|
123 |
|
124 |
|
@@ -176,18 +236,9 @@ def infer(
|
|
176 |
mask_bbox_x_max,
|
177 |
mask_bbox_y_max,
|
178 |
))
|
179 |
-
room_image_cropped =
|
180 |
-
room_image_cropped,
|
181 |
-
(bbox_longest_side, bbox_longest_side),
|
182 |
-
# White padding
|
183 |
-
color=(255, 255, 255),
|
184 |
-
centering=(0.5, 0.5),
|
185 |
-
)
|
186 |
-
room_image_cropped = ImageOps.fit(
|
187 |
room_image_cropped,
|
188 |
(max_dimension, max_dimension),
|
189 |
-
method=Image.Resampling.BICUBIC,
|
190 |
-
centering=(0.5, 0.5),
|
191 |
)
|
192 |
|
193 |
room_mask_cropped = room_mask.crop((
|
@@ -196,30 +247,17 @@ def infer(
|
|
196 |
mask_bbox_x_max,
|
197 |
mask_bbox_y_max,
|
198 |
))
|
199 |
-
room_mask_cropped
|
200 |
-
room_mask_cropped = ImageOps.pad(
|
201 |
room_mask_cropped,
|
202 |
(max_dimension, max_dimension),
|
203 |
-
# White padding
|
204 |
-
color=(255, 255, 255),
|
205 |
-
centering=(0.5, 0.5),
|
206 |
-
)
|
207 |
-
room_mask_cropped = ImageOps.fit(
|
208 |
-
room_mask_cropped,
|
209 |
-
(max_dimension, max_dimension),
|
210 |
-
method=Image.Resampling.BICUBIC,
|
211 |
-
centering=(0.5, 0.5),
|
212 |
)
|
213 |
|
214 |
room_image_cropped.save("room_image_cropped.png")
|
215 |
room_mask_cropped.save("room_mask_cropped.png")
|
216 |
|
217 |
-
furniture_image =
|
218 |
furniture_image_input,
|
219 |
(max_dimension, max_dimension),
|
220 |
-
# White padding
|
221 |
-
color=(255, 255, 255),
|
222 |
-
centering=(0.5, 0.5),
|
223 |
)
|
224 |
|
225 |
furniture_mask = Image.new("RGB", (max_dimension, max_dimension), (255, 255, 255))
|
@@ -271,19 +309,9 @@ def infer(
|
|
271 |
for image in results_images:
|
272 |
final_image = room_image.copy()
|
273 |
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
0,
|
278 |
-
max_dimension * 2,
|
279 |
-
max_dimension,
|
280 |
-
))
|
281 |
-
image_generated = image_generated.resize(
|
282 |
-
(bbox_longest_side, bbox_longest_side), Image.Resampling.BICUBIC
|
283 |
-
)
|
284 |
-
# Crop back to the bbox (remove the padding)
|
285 |
-
image_generated = remove_padding(
|
286 |
-
image_generated,
|
287 |
(
|
288 |
mask_bbox_x_max - mask_bbox_x_min,
|
289 |
mask_bbox_y_max - mask_bbox_y_min,
|
|
|
80 |
}
|
81 |
|
82 |
|
83 |
+
def pad(
|
84 |
+
image: Image.Image,
|
85 |
+
size: tuple[int, int],
|
86 |
+
method: int = Image.Resampling.BICUBIC,
|
87 |
+
color: str | int | tuple[int, ...] | None = None,
|
88 |
+
centering: tuple[float, float] = (1, 1),
|
89 |
+
) -> tuple[Image.Image, tuple[int, int]]:
|
90 |
+
resized = ImageOps.contain(image, size, method)
|
91 |
+
resized_size = resized.size
|
92 |
+
if resized_size == size:
|
93 |
+
out = resized
|
94 |
+
else:
|
95 |
+
out = Image.new(image.mode, size, color)
|
96 |
+
if resized.palette:
|
97 |
+
palette = resized.getpalette()
|
98 |
+
if palette is not None:
|
99 |
+
out.putpalette(palette)
|
100 |
+
if resized.width != size[0]:
|
101 |
+
x = round((size[0] - resized.width) * max(0, max(centering[0], 1)))
|
102 |
+
out.paste(resized, (x, 0))
|
103 |
+
else:
|
104 |
+
y = round((size[1] - resized.height) * max(0, max(centering[1], 1)))
|
105 |
+
out.paste(resized, (0, y))
|
106 |
+
return out, resized_size
|
107 |
+
|
108 |
+
|
109 |
+
def unpad(
|
110 |
+
padded_image: Image.Image,
|
111 |
+
padded_size: tuple[int, int],
|
112 |
+
original_size: tuple[int, int],
|
113 |
+
centering: tuple[float, float] = (1, 1),
|
114 |
+
method: int = Image.Resampling.BICUBIC,
|
115 |
+
) -> Image.Image:
|
116 |
+
"""
|
117 |
+
Remove the padding added by the `pad` function to recover the original resized image.
|
118 |
+
|
119 |
+
Args:
|
120 |
+
padded_image (Image.Image): The padded image.
|
121 |
+
padded_size (tuple[int, int]): The original size of the resized image before padding.
|
122 |
+
centering (tuple[float, float]): The centering used during padding (x, y), defaults to (1, 1).
|
123 |
+
|
124 |
+
Returns:
|
125 |
+
Image.Image: The cropped image matching the original resized dimensions.
|
126 |
+
|
127 |
+
"""
|
128 |
+
width, height = padded_image.size
|
129 |
+
padded_width, padded_height = padded_size
|
130 |
+
|
131 |
+
# Calculate the cropping box based on centering
|
132 |
+
left = round((width - padded_width) * centering[0])
|
133 |
+
top = round((height - padded_height) * centering[1])
|
134 |
+
right = left + padded_width
|
135 |
+
bottom = top + padded_height
|
136 |
+
|
137 |
+
# Crop the image to remove the padding
|
138 |
+
cropped_image = padded_image.crop((left, top, right, bottom))
|
139 |
+
|
140 |
+
# Resize the cropped image to match the original size
|
141 |
+
resized_image = cropped_image.resize(original_size, method)
|
142 |
+
return resized_image
|
143 |
|
144 |
|
145 |
def adjust_bbox_to_divisible_16(
|
146 |
+
x_min: int,
|
147 |
+
y_min: int,
|
148 |
+
x_max: int,
|
149 |
+
y_max: int,
|
150 |
+
width: int,
|
151 |
+
height: int,
|
152 |
+
padding: int = MASK_CONTEXT_PADDING,
|
153 |
+
) -> tuple[int, int, int, int]:
|
154 |
+
# Add context padding
|
155 |
x_min = max(x_min - padding, 0)
|
156 |
y_min = max(y_min - padding, 0)
|
157 |
x_max = min(x_max + padding, width)
|
158 |
y_max = min(y_max + padding, height)
|
159 |
|
|
|
|
|
|
|
|
|
160 |
# Ensure bbox dimensions are divisible by 16
|
161 |
+
def make_divisible_16(val_min, val_max, max_limit):
|
162 |
+
size = val_max - val_min
|
163 |
+
if size % 16 != 0:
|
164 |
+
adjustment = 16 - (size % 16)
|
165 |
+
val_min = max(val_min - adjustment // 2, 0)
|
166 |
+
val_max = min(val_max + adjustment // 2, max_limit)
|
167 |
+
return val_min, val_max
|
168 |
+
|
169 |
+
x_min, x_max = make_divisible_16(x_min, x_max, width)
|
170 |
+
y_min, y_max = make_divisible_16(y_min, y_max, height)
|
171 |
+
|
172 |
+
# Re-check divisibility after bounds adjustment
|
173 |
x_min = max(x_min, 0)
|
174 |
y_min = max(y_min, 0)
|
175 |
x_max = min(x_max, width)
|
176 |
y_max = min(y_max, height)
|
177 |
|
178 |
+
# Final divisibility check (in case constraints pushed it off again)
|
179 |
+
x_min, x_max = make_divisible_16(x_min, x_max, width)
|
180 |
+
y_min, y_max = make_divisible_16(y_min, y_max, height)
|
181 |
+
|
182 |
return x_min, y_min, x_max, y_max
|
183 |
|
184 |
|
|
|
236 |
mask_bbox_x_max,
|
237 |
mask_bbox_y_max,
|
238 |
))
|
239 |
+
room_image_cropped, room_image_cropped_size = pad(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
room_image_cropped,
|
241 |
(max_dimension, max_dimension),
|
|
|
|
|
242 |
)
|
243 |
|
244 |
room_mask_cropped = room_mask.crop((
|
|
|
247 |
mask_bbox_x_max,
|
248 |
mask_bbox_y_max,
|
249 |
))
|
250 |
+
room_mask_cropped, _ = pad(
|
|
|
251 |
room_mask_cropped,
|
252 |
(max_dimension, max_dimension),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
)
|
254 |
|
255 |
room_image_cropped.save("room_image_cropped.png")
|
256 |
room_mask_cropped.save("room_mask_cropped.png")
|
257 |
|
258 |
+
furniture_image, _ = pad(
|
259 |
furniture_image_input,
|
260 |
(max_dimension, max_dimension),
|
|
|
|
|
|
|
261 |
)
|
262 |
|
263 |
furniture_mask = Image.new("RGB", (max_dimension, max_dimension), (255, 255, 255))
|
|
|
309 |
for image in results_images:
|
310 |
final_image = room_image.copy()
|
311 |
|
312 |
+
image_generated = unpad(
|
313 |
+
image,
|
314 |
+
room_image_cropped_size,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
315 |
(
|
316 |
mask_bbox_x_max - mask_bbox_x_min,
|
317 |
mask_bbox_y_max - mask_bbox_y_min,
|